tmail 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. data/LICENSE +21 -0
  2. data/README +157 -0
  3. data/bat/changelog +19 -0
  4. data/bat/clobber/package +10 -0
  5. data/bat/compile +42 -0
  6. data/bat/config.yaml +8 -0
  7. data/bat/prepare +8 -0
  8. data/bat/publish +51 -0
  9. data/bat/rdoc +42 -0
  10. data/bat/release +12 -0
  11. data/bat/setup +1616 -0
  12. data/bat/stats +138 -0
  13. data/bat/tag +25 -0
  14. data/bat/test +25 -0
  15. data/ext/tmail/Makefile +25 -0
  16. data/ext/tmail/base64/MANIFEST +4 -0
  17. data/ext/tmail/base64/base64.c +264 -0
  18. data/ext/tmail/base64/depend +1 -0
  19. data/ext/tmail/base64/extconf.rb +38 -0
  20. data/ext/tmail/scanner_c/MANIFEST +4 -0
  21. data/ext/tmail/scanner_c/depend +1 -0
  22. data/ext/tmail/scanner_c/extconf.rb +38 -0
  23. data/ext/tmail/scanner_c/scanner_c.c +582 -0
  24. data/lib/tmail.rb +4 -0
  25. data/lib/tmail/Makefile +19 -0
  26. data/lib/tmail/address.rb +245 -0
  27. data/lib/tmail/attachments.rb +47 -0
  28. data/lib/tmail/base64.rb +75 -0
  29. data/lib/tmail/compat.rb +39 -0
  30. data/lib/tmail/config.rb +71 -0
  31. data/lib/tmail/core_extensions.rb +67 -0
  32. data/lib/tmail/encode.rb +524 -0
  33. data/lib/tmail/header.rb +931 -0
  34. data/lib/tmail/index.rb +8 -0
  35. data/lib/tmail/interface.rb +540 -0
  36. data/lib/tmail/loader.rb +1 -0
  37. data/lib/tmail/mail.rb +507 -0
  38. data/lib/tmail/mailbox.rb +435 -0
  39. data/lib/tmail/mbox.rb +1 -0
  40. data/lib/tmail/net.rb +282 -0
  41. data/lib/tmail/obsolete.rb +137 -0
  42. data/lib/tmail/parser.rb +1475 -0
  43. data/lib/tmail/parser.y +381 -0
  44. data/lib/tmail/port.rb +379 -0
  45. data/lib/tmail/quoting.rb +142 -0
  46. data/lib/tmail/require_arch.rb +56 -0
  47. data/lib/tmail/scanner.rb +44 -0
  48. data/lib/tmail/scanner_r.rb +263 -0
  49. data/lib/tmail/stringio.rb +279 -0
  50. data/lib/tmail/tmail.rb +1 -0
  51. data/lib/tmail/utils.rb +281 -0
  52. data/lib/tmail/version.rb +38 -0
  53. data/meta/icli.yaml +16 -0
  54. data/meta/tmail-1.1.1.roll +24 -0
  55. data/sample/data/multipart +23 -0
  56. data/sample/data/normal +29 -0
  57. data/sample/data/sendtest +5 -0
  58. data/sample/data/simple +14 -0
  59. data/sample/data/test +27 -0
  60. data/sample/extract-attachements.rb +33 -0
  61. data/sample/from-check.rb +26 -0
  62. data/sample/multipart.rb +26 -0
  63. data/sample/parse-bench.rb +68 -0
  64. data/sample/parse-test.rb +19 -0
  65. data/sample/sendmail.rb +94 -0
  66. data/test/extctrl.rb +6 -0
  67. data/test/fixtures/raw_base64_decoded_string +0 -0
  68. data/test/fixtures/raw_base64_email +83 -0
  69. data/test/fixtures/raw_base64_encoded_string +1 -0
  70. data/test/fixtures/raw_email +14 -0
  71. data/test/fixtures/raw_email10 +20 -0
  72. data/test/fixtures/raw_email11 +34 -0
  73. data/test/fixtures/raw_email12 +32 -0
  74. data/test/fixtures/raw_email13 +29 -0
  75. data/test/fixtures/raw_email2 +114 -0
  76. data/test/fixtures/raw_email3 +70 -0
  77. data/test/fixtures/raw_email4 +59 -0
  78. data/test/fixtures/raw_email5 +19 -0
  79. data/test/fixtures/raw_email6 +20 -0
  80. data/test/fixtures/raw_email7 +66 -0
  81. data/test/fixtures/raw_email8 +47 -0
  82. data/test/fixtures/raw_email9 +28 -0
  83. data/test/fixtures/raw_email_quoted_with_0d0a +14 -0
  84. data/test/fixtures/raw_email_simple +11 -0
  85. data/test/fixtures/raw_email_with_illegal_boundary +58 -0
  86. data/test/fixtures/raw_email_with_multipart_mixed_quoted_boundary +50 -0
  87. data/test/fixtures/raw_email_with_nested_attachment +100 -0
  88. data/test/fixtures/raw_email_with_partially_quoted_subject +14 -0
  89. data/test/fixtures/raw_email_with_quoted_illegal_boundary +58 -0
  90. data/test/kcode.rb +14 -0
  91. data/test/test_address.rb +1128 -0
  92. data/test/test_attachments.rb +35 -0
  93. data/test/test_base64.rb +63 -0
  94. data/test/test_encode.rb +77 -0
  95. data/test/test_header.rb +885 -0
  96. data/test/test_helper.rb +2 -0
  97. data/test/test_mail.rb +623 -0
  98. data/test/test_mbox.rb +126 -0
  99. data/test/test_port.rb +430 -0
  100. data/test/test_scanner.rb +209 -0
  101. data/test/test_utils.rb +37 -0
  102. metadata +205 -0
@@ -0,0 +1 @@
1
+ tmbase64.o: tmbase64.c $(hdrdir)/ruby.h $(topdir)/config.h $(hdrdir)/defines.h Makefile
@@ -0,0 +1,38 @@
1
+ require 'mkmf'
2
+ require 'rbconfig'
3
+
4
+ extension_name = 'base64'
5
+
6
+ arch = Config::CONFIG['arch']
7
+
8
+ windows = (/mswin/ =~ arch) #RUBY_PLATFORM)
9
+
10
+ if (ENV['NORUBYEXT'] == 'true') || windows # TEMPORARILY ADD WINDOWS HERE
11
+ #ENV['make'] = 'echo' # THIS DOESN"T GET TO THE PARENT PROCESS!!!
12
+ # LETS TRY FAKING IT OUT.
13
+ if windows
14
+ File.open('make.bat', 'w') do |f|
15
+ f << 'echo Native extension will be omitted.'
16
+ end
17
+ File.open('nmake.bat', 'w') do |f|
18
+ f << 'echo Native extension will be omitted.'
19
+ end
20
+ #File.chmod(0755, "make.bat", "nmake.bat") # need?
21
+ end
22
+ File.open('Makefile', 'w') do |f|
23
+ f << "all:\n"
24
+ f << "install:\n"
25
+ end
26
+ else
27
+ if windows && ENV['make'].nil?
28
+ $LIBS += " msvcprt.lib"
29
+ #dir_config(extension_name)
30
+ #create_makefile(extension_name, "tmail")
31
+ create_makefile(extension_name, "tmail/#{arch}")
32
+ else
33
+ $CFLAGS += " -D_FILE_OFFSET_BITS=64" #???
34
+ #dir_config(extension_name)
35
+ #create_makefile(extension_name, "tmail")
36
+ create_makefile(extension_name, "tmail/#{arch}")
37
+ end
38
+ end
@@ -0,0 +1,4 @@
1
+ MANIFEST
2
+ mails.c
3
+ extconf.rb
4
+ depend
@@ -0,0 +1 @@
1
+ mails.o: mails.c $(hdrdir)/ruby.h $(topdir)/config.h $(hdrdir)/defines.h Makefile
@@ -0,0 +1,38 @@
1
+ require 'mkmf'
2
+ require 'rbconfig'
3
+
4
+ extension_name = 'scanner_c'
5
+
6
+ arch = Config::CONFIG['arch']
7
+
8
+ windows = (/mswin/ =~ arch) #RUBY_PLATFORM)
9
+
10
+ if (ENV['NORUBYEXT'] == 'true') || windows # TEMPORARILY ADD WINDOWS HERE
11
+ #ENV['make'] = 'echo' # THIS DOESN"T GET TO THE PARENT PROCESS!!!
12
+ # LETS TRY FAKING IT OUT.
13
+ if windows
14
+ File.open('make.bat', 'w') do |f|
15
+ f << 'echo Native extension will be omitted.'
16
+ end
17
+ File.open('nmake.bat', 'w') do |f|
18
+ f << 'echo Native extension will be omitted.'
19
+ end
20
+ #File.chmod(0755, "make.bat", "nmake.bat") # need?
21
+ end
22
+ File.open('Makefile', 'w') do |f|
23
+ f << "all:\n"
24
+ f << "install:\n"
25
+ end
26
+ else
27
+ if windows && ENV['make'].nil?
28
+ $LIBS += " msvcprt.lib"
29
+ #dir_config(extension_name)
30
+ #create_makefile(extension_name, "tmail")
31
+ create_makefile(extension_name, "tmail/#{arch}")
32
+ else
33
+ $CFLAGS += " -D_FILE_OFFSET_BITS=64" #???
34
+ #dir_config(extension_name)
35
+ #create_makefile(extension_name, "tmail")
36
+ create_makefile(extension_name, "tmail/#{arch}")
37
+ end
38
+ end
@@ -0,0 +1,582 @@
1
+ /*
2
+
3
+ scanner_c.c
4
+
5
+ Copyright (c) 1998-2007 Minero Aoki
6
+
7
+ This program is free software.
8
+ You can distribute/modify this program under the terms of
9
+ the GNU Lesser General Public License version 2.1.
10
+
11
+ */
12
+
13
+ #include <stdio.h>
14
+ #ifdef __STDC__
15
+ # include <stdlib.h>
16
+ #endif
17
+
18
+ #include "ruby.h"
19
+ #include "re.h"
20
+
21
+
22
+ #define TMAIL_VERSION "0.10.8"
23
+
24
+ static VALUE MailScanner;
25
+ static VALUE ScanError;
26
+
27
+ struct scanner
28
+ {
29
+ char *pbeg;
30
+ char *p;
31
+ char *pend;
32
+ unsigned int flags;
33
+ VALUE comments;
34
+ };
35
+
36
+ #define MODE_MIME (1 << 0)
37
+ #define MODE_RECV (1 << 1)
38
+ #define MODE_ISO2022 (1 << 2)
39
+ #define MODE_DEBUG (1 << 4)
40
+
41
+ #define MIME_MODE_P(s) ((s)->flags & MODE_MIME)
42
+ #define RECV_MODE_P(s) ((s)->flags & MODE_RECV)
43
+ #define ISO2022_MODE_P(s) ((s)->flags & MODE_ISO2022)
44
+
45
+ #define GET_SCANNER(val, s) Data_Get_Struct(val, struct scanner, s)
46
+
47
+
48
+ static void
49
+ mails_free(sc)
50
+ struct scanner *sc;
51
+ {
52
+ free(sc);
53
+ }
54
+
55
+ #ifndef StringValue
56
+ # define StringValue(s) Check_Type(str, T_STRING);
57
+ #endif
58
+
59
+ /*
60
+ * Document-method: mails_s_new
61
+ *
62
+ * Creates a new mail
63
+ *
64
+ */
65
+ static VALUE
66
+ mails_s_new(klass, str, ident, cmt)
67
+ VALUE klass, str, ident, cmt;
68
+ {
69
+ struct scanner *sc;
70
+ const char *tmp;
71
+
72
+ sc = ALLOC_N(struct scanner, 1);
73
+
74
+ StringValue(str);
75
+ sc->pbeg = RSTRING(str)->ptr;
76
+ sc->p = sc->pbeg;
77
+ sc->pend = sc->p + RSTRING(str)->len;
78
+
79
+ sc->flags = 0;
80
+ Check_Type(ident, T_SYMBOL);
81
+ tmp = rb_id2name(SYM2ID(ident));
82
+ if (strcmp(tmp, "RECEIVED") == 0) sc->flags |= MODE_RECV;
83
+ else if (strcmp(tmp, "CTYPE") == 0) sc->flags |= MODE_MIME;
84
+ else if (strcmp(tmp, "CENCODING") == 0) sc->flags |= MODE_MIME;
85
+ else if (strcmp(tmp, "CDISPOSITION") == 0) sc->flags |= MODE_MIME;
86
+
87
+ tmp = rb_get_kcode();
88
+ if (strcmp(tmp, "EUC") == 0 || strcmp(tmp, "SJIS") == 0) {
89
+ sc->flags |= MODE_ISO2022;
90
+ }
91
+
92
+ sc->comments = Qnil;
93
+ if (! NIL_P(cmt)) {
94
+ Check_Type(cmt, T_ARRAY);
95
+ sc->comments = cmt;
96
+ }
97
+
98
+ return Data_Wrap_Struct(MailScanner, 0, mails_free, sc);
99
+ }
100
+
101
+ /*
102
+ * Document-method: mails_debug_get
103
+ *
104
+ * TODO: Documentation needed
105
+ *
106
+ */
107
+ static VALUE
108
+ mails_debug_get(self)
109
+ VALUE self;
110
+ {
111
+ struct scanner *sc;
112
+
113
+ GET_SCANNER(self, sc);
114
+ if (sc->flags & MODE_DEBUG)
115
+ return Qtrue;
116
+ else
117
+ return Qfalse;
118
+ }
119
+
120
+ /*
121
+ * Document-method: mails_debug_set
122
+ *
123
+ * TODO: Documentation needed
124
+ *
125
+ */
126
+ static VALUE
127
+ mails_debug_set(self, flag)
128
+ VALUE self, flag;
129
+ {
130
+ struct scanner *sc;
131
+
132
+ GET_SCANNER(self, sc);
133
+ if (RTEST(flag))
134
+ sc->flags |= MODE_DEBUG;
135
+ else
136
+ sc->flags &= ~MODE_DEBUG;
137
+ return Qnil;
138
+ }
139
+
140
+
141
+ /*
142
+ ----------------------------------------------------------------------
143
+ scanning routines
144
+ ----------------------------------------------------------------------
145
+ */
146
+
147
+ #define ESC '\033'
148
+ #define ATOM_SYMBOLS "_#!$%&'`*+-{|}~^/=?"
149
+ #define TOKEN_SYMBOLS "_#!$%&'`*+-{|}~^."
150
+ #define ATOM_SPECIAL "()<>[]@,;:\"\\."
151
+ #define TOKEN_SPECIAL "()<>[]@,;:\"\\/?="
152
+ #define LWSP " \t\r\n"
153
+
154
+ #define IS_ALPHA(ch) (('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z'))
155
+ #define IS_UPPER(ch) ('A' <= ch && ch <= 'Z')
156
+ #define TO_LOWER(ch) (IS_UPPER(ch) ? ch + 32 : ch)
157
+ #define IS_LWSP(ch) (strchr(LWSP, ch))
158
+ #define IS_DIGIT(ch) ('0' <= ch && ch <= '9')
159
+ #define IS_WORDCHAR(ch, symlist) \
160
+ (IS_ALPHA(ch) || IS_DIGIT(ch) || strchr(symlist, ch))
161
+ #define IS_ATOMCHAR(ch) IS_WORDCHAR(ch, ATOM_SYMBOLS)
162
+ #define IS_TOKENCHAR(ch) IS_WORDCHAR(ch, TOKEN_SYMBOLS)
163
+ #define IS_JCHAR(ch) ismbchar(ch)
164
+
165
+
166
+ /* I know this implement is ugly, but usually useful. */
167
+
168
+ /* skip until "\e(B" (us-ascii) */
169
+ static void
170
+ skip_iso2022jp_string(sc)
171
+ struct scanner *sc;
172
+ {
173
+ for (; sc->p < sc->pend; sc->p++) {
174
+ if (*sc->p == ESC) {
175
+ if (strncmp(sc->p, "\033(B", 3) == 0) {
176
+ sc->p += 3;
177
+ return;
178
+ }
179
+ }
180
+ }
181
+ }
182
+
183
+ static void
184
+ skip_japanese_string(sc)
185
+ struct scanner *sc;
186
+ {
187
+ while (sc->p < sc->pend) {
188
+ if (! ismbchar(*sc->p)) return;
189
+ sc->p += mbclen(*sc->p);
190
+ }
191
+ }
192
+
193
+
194
+ #define scan_atom(sc) scan_word(sc, ATOM_SYMBOLS)
195
+ #define scan_token(sc) scan_word(sc, TOKEN_SYMBOLS)
196
+
197
+ static VALUE
198
+ scan_word(sc, syms)
199
+ struct scanner *sc;
200
+ char *syms;
201
+ {
202
+ char *beg = sc->p;
203
+
204
+ while (sc->p < sc->pend) {
205
+ if (ISO2022_MODE_P(sc) && *sc->p == ESC) {
206
+ skip_iso2022jp_string(sc);
207
+ }
208
+ else if (IS_JCHAR(*sc->p)) {
209
+ skip_japanese_string(sc);
210
+ }
211
+ else if (IS_WORDCHAR(*sc->p, syms)) {
212
+ sc->p++;
213
+ }
214
+ else {
215
+ break;
216
+ }
217
+ }
218
+
219
+ return rb_str_new(beg, sc->p - beg);
220
+ }
221
+
222
+
223
+ #define BUFSIZE 256
224
+
225
+ static VALUE
226
+ scan_quoted_word(sc)
227
+ struct scanner *sc;
228
+ {
229
+ char buf[BUFSIZE];
230
+ char *p;
231
+ char *save;
232
+ VALUE result = rb_str_new("", 0);
233
+
234
+ sc->p++; /* discard first dquote */
235
+ p = buf;
236
+ while (sc->p < sc->pend) {
237
+ if (*sc->p == '"') {
238
+ sc->p++; /* discard terminal dquote */
239
+ rb_str_cat(result, buf, p - buf);
240
+ return result;
241
+ }
242
+ if (ISO2022_MODE_P(sc) && *sc->p == ESC) {
243
+ save = sc->p;
244
+ skip_iso2022jp_string(sc);
245
+ while (save < sc->p) {
246
+ *p++ = *save++;
247
+ if (p >= buf + BUFSIZE) {
248
+ /* flush buffer */
249
+ rb_str_cat(result, buf, BUFSIZE);
250
+ p = buf;
251
+ }
252
+ }
253
+ continue;
254
+ }
255
+
256
+ if (*sc->p == '\\')
257
+ sc->p++; /* discard quoting backslash */
258
+ *p++ = *sc->p++;
259
+ if (p >= buf + BUFSIZE) {
260
+ /* flush buffer */
261
+ rb_str_cat(result, buf, BUFSIZE);
262
+ p = buf;
263
+ }
264
+ }
265
+
266
+ rb_raise(ScanError, "unterminated quoted-word");
267
+ return Qnil;
268
+ }
269
+
270
+ static VALUE
271
+ scan_domain_literal(sc)
272
+ struct scanner *sc;
273
+ {
274
+ char buf[BUFSIZE];
275
+ char *p;
276
+ VALUE result = rb_str_new("", 0);
277
+
278
+ p = buf;
279
+ while (sc->p < sc->pend) {
280
+ if (*sc->p == ']') {
281
+ *p++ = *sc->p++;
282
+ rb_str_cat(result, buf, p - buf);
283
+ return result;
284
+ }
285
+
286
+ if (*sc->p == '\\')
287
+ sc->p++; /* discard backslash */
288
+ *p++ = *sc->p++;
289
+ if (p >= buf + BUFSIZE) {
290
+ /* flush buffer */
291
+ rb_str_cat(result, buf, BUFSIZE);
292
+ p = buf;
293
+ }
294
+ }
295
+
296
+ rb_raise(ScanError, "unterminated domain literal");
297
+ return Qnil;
298
+ }
299
+
300
+
301
+ static VALUE
302
+ scan_comment(sc)
303
+ struct scanner *sc;
304
+ {
305
+ int nest = 1;
306
+ char *p;
307
+ VALUE ret = rb_str_new("", 0);
308
+
309
+ sc->p++;
310
+ p = sc->p;
311
+ while (sc->p < sc->pend) {
312
+ if (ISO2022_MODE_P(sc) && *sc->p == ESC) {
313
+ skip_iso2022jp_string(sc);
314
+ }
315
+ else if (IS_JCHAR(*sc->p)) {
316
+ skip_japanese_string(sc);
317
+ }
318
+ else {
319
+ switch (*sc->p) {
320
+ case '(':
321
+ nest++;
322
+ break;
323
+ case ')':
324
+ nest--;
325
+ if (nest == 0) {
326
+ rb_str_cat(ret, p, sc->p - p);
327
+ sc->p++;
328
+ return ret;
329
+ }
330
+ break;
331
+ case '\\':
332
+ rb_str_cat(ret, p, sc->p - p);
333
+ sc->p++;
334
+ if (sc->p == sc->pend)
335
+ rb_raise(ScanError, "incomplete char quote");
336
+ p = sc->p;
337
+ break;
338
+ default:
339
+ break;
340
+ }
341
+ sc->p++;
342
+ }
343
+ }
344
+
345
+ rb_raise(ScanError, "unterminated comment");
346
+ return Qnil;
347
+ }
348
+
349
+
350
+ static void
351
+ skip_lwsp(sc)
352
+ struct scanner *sc;
353
+ {
354
+ while (sc->p < sc->pend) {
355
+ if (IS_LWSP(*sc->p)) sc->p++;
356
+ else break;
357
+ }
358
+ }
359
+
360
+ static int
361
+ nccmp(a, b)
362
+ char *a, *b;
363
+ {
364
+ while (*a && *b) {
365
+ if ((*a != *b) && (TO_LOWER(*a) != TO_LOWER(*b)))
366
+ return 0;
367
+ a++; b++;
368
+ }
369
+ return (*a == *b);
370
+ }
371
+
372
+ static int
373
+ digit_p(str)
374
+ VALUE str;
375
+ {
376
+ char *p;
377
+ int i;
378
+
379
+ p = RSTRING(str)->ptr;
380
+ for (i = 0; i < RSTRING(str)->len; i++) {
381
+ if (! IS_DIGIT(RSTRING(str)->ptr[i]))
382
+ return 0;
383
+ }
384
+ return 1;
385
+ }
386
+
387
+ static VALUE tok_atom, tok_digit, tok_token, tok_quoted, tok_domlit;
388
+ static VALUE tok_from, tok_by, tok_via, tok_with, tok_id, tok_for;
389
+
390
+ static VALUE
391
+ atomsym(sc, str)
392
+ struct scanner *sc;
393
+ VALUE str;
394
+ {
395
+ if (digit_p(str)) {
396
+ return tok_digit;
397
+ }
398
+ else if (RECV_MODE_P(sc)) {
399
+ char *p = RSTRING(str)->ptr;
400
+ if (nccmp(p, "from")) return tok_from;
401
+ else if (nccmp(p, "by")) return tok_by;
402
+ else if (nccmp(p, "via")) return tok_via;
403
+ else if (nccmp(p, "with")) return tok_with;
404
+ else if (nccmp(p, "id")) return tok_id;
405
+ else if (nccmp(p, "for")) return tok_for;
406
+ }
407
+ return tok_atom;
408
+ }
409
+
410
+ static void
411
+ debug_print(sc, sym, val)
412
+ struct scanner *sc;
413
+ VALUE sym, val;
414
+ {
415
+ VALUE s;
416
+
417
+ s = rb_funcall(sym, rb_intern("inspect"), 0),
418
+ printf("%7ld %-10s token=<%s>\n",
419
+ (unsigned long)(sc->pend - sc->p),
420
+ RSTRING(s)->ptr,
421
+ RSTRING(val)->ptr);
422
+ }
423
+
424
+ #define D(expr) do {\
425
+ if (sc->flags & MODE_DEBUG) {expr;}\
426
+ } while (0)
427
+
428
+ static void
429
+ pass_token(sc, sym, tok, arr)
430
+ struct scanner *sc;
431
+ VALUE sym, tok, arr;
432
+ {
433
+ D(debug_print(sc, sym, tok));
434
+ rb_ary_store(arr, 0, sym);
435
+ rb_ary_store(arr, 1, tok);
436
+ rb_yield(arr);
437
+ }
438
+
439
+ /*
440
+ * Document-method: mails_scan
441
+ *
442
+ * TODO: Documentation needed
443
+ *
444
+ */
445
+ static VALUE
446
+ mails_scan(self)
447
+ VALUE self;
448
+ {
449
+ struct scanner *sc;
450
+ VALUE arr;
451
+
452
+ #define PASS(s,v) pass_token(sc,s,v,arr)
453
+ GET_SCANNER(self, sc);
454
+ if (!sc->p) {
455
+ rb_raise(ScanError, "Mails#scan called before reset");
456
+ }
457
+ arr = rb_assoc_new(Qnil, Qnil);
458
+
459
+ while (sc->p < sc->pend) {
460
+ D(puts("new loop"));
461
+ D(printf("char='%c'\n", *sc->p));
462
+ if (IS_LWSP(*sc->p)) {
463
+ D(puts("lwsp"));
464
+ skip_lwsp(sc);
465
+ if (sc->p >= sc->pend)
466
+ break;
467
+ }
468
+
469
+ if (MIME_MODE_P(sc)) {
470
+ if (IS_TOKENCHAR(*sc->p) ||
471
+ (ISO2022_MODE_P(sc) && (*sc->p == ESC)) ||
472
+ IS_JCHAR(*sc->p)) {
473
+ D(puts("token"));
474
+ PASS(tok_token, scan_token(sc));
475
+ continue;
476
+ }
477
+ }
478
+ else {
479
+ if (IS_ATOMCHAR(*sc->p) ||
480
+ (ISO2022_MODE_P(sc) && (*sc->p == ESC)) ||
481
+ IS_JCHAR(*sc->p)) {
482
+ VALUE tmp;
483
+ D(puts("atom"));
484
+ tmp = scan_atom(sc);
485
+ PASS(atomsym(sc, tmp), tmp);
486
+ continue;
487
+ }
488
+ }
489
+
490
+ if (*sc->p == '"') {
491
+ D(puts("quoted"));
492
+ PASS(tok_quoted, scan_quoted_word(sc));
493
+ D(puts("quoted"));
494
+ }
495
+ else if (*sc->p == '(') {
496
+ VALUE c;
497
+ D(puts("comment"));
498
+ c = scan_comment(sc);
499
+ if (! NIL_P(sc->comments))
500
+ rb_ary_push(sc->comments, c);
501
+ }
502
+ else if (*sc->p == '[') {
503
+ D(puts("domlit"));
504
+ PASS(tok_domlit, scan_domain_literal(sc));
505
+ }
506
+ else {
507
+ VALUE ch;
508
+ D(puts("char"));
509
+ ch = rb_str_new(sc->p, 1);
510
+ sc->p++;
511
+ PASS(ch, ch);
512
+ }
513
+ }
514
+
515
+ PASS(Qfalse, rb_str_new("$", 1));
516
+ return Qnil;
517
+ }
518
+
519
+
520
+ /*
521
+ ------------------------------------------------------------------
522
+ ruby interface
523
+ ------------------------------------------------------------------
524
+ */
525
+
526
+ static VALUE
527
+ cstr2symbol(str)
528
+ char *str;
529
+ {
530
+ ID tmp;
531
+
532
+ tmp = rb_intern(str);
533
+ #ifdef ID2SYM
534
+ return ID2SYM(tmp);
535
+ #else
536
+ return INT2FIX(tmp);
537
+ #endif
538
+ }
539
+
540
+ void
541
+ Init_scanner_c()
542
+ {
543
+ VALUE TMail;
544
+ VALUE tmp;
545
+
546
+ if (rb_const_defined(rb_cObject, rb_intern("TMail"))) {
547
+ TMail = rb_const_get(rb_cObject, rb_intern("TMail"));
548
+ }
549
+ else {
550
+ TMail = rb_define_module("TMail");
551
+ }
552
+ MailScanner = rb_define_class_under(TMail, "Scanner_C", rb_cObject);
553
+
554
+ tmp = rb_str_new2(TMAIL_VERSION);
555
+ rb_obj_freeze(tmp);
556
+ rb_define_const(MailScanner, "Version", tmp);
557
+
558
+ rb_define_singleton_method(MailScanner, "new", mails_s_new, 3);
559
+ rb_define_method(MailScanner, "scan", mails_scan, 0);
560
+ rb_define_method(MailScanner, "debug", mails_debug_get, 0);
561
+ rb_define_method(MailScanner, "debug=", mails_debug_set, 1);
562
+
563
+ if (rb_const_defined(TMail, rb_intern("SyntaxError"))) {
564
+ ScanError = rb_const_get(rb_cObject, rb_intern("SyntaxError"));
565
+ }
566
+ else {
567
+ ScanError = rb_define_class_under(TMail, "SyntaxError", rb_eStandardError);
568
+ }
569
+
570
+ tok_atom = cstr2symbol("ATOM");
571
+ tok_digit = cstr2symbol("DIGIT");
572
+ tok_token = cstr2symbol("TOKEN");
573
+ tok_quoted = cstr2symbol("QUOTED");
574
+ tok_domlit = cstr2symbol("DOMLIT");
575
+
576
+ tok_from = cstr2symbol("FROM");
577
+ tok_by = cstr2symbol("BY");
578
+ tok_via = cstr2symbol("VIA");
579
+ tok_with = cstr2symbol("WITH");
580
+ tok_id = cstr2symbol("ID");
581
+ tok_for = cstr2symbol("FOR");
582
+ }