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.
- data/LICENSE +21 -0
- data/README +157 -0
- data/bat/changelog +19 -0
- data/bat/clobber/package +10 -0
- data/bat/compile +42 -0
- data/bat/config.yaml +8 -0
- data/bat/prepare +8 -0
- data/bat/publish +51 -0
- data/bat/rdoc +42 -0
- data/bat/release +12 -0
- data/bat/setup +1616 -0
- data/bat/stats +138 -0
- data/bat/tag +25 -0
- data/bat/test +25 -0
- data/ext/tmail/Makefile +25 -0
- data/ext/tmail/base64/MANIFEST +4 -0
- data/ext/tmail/base64/base64.c +264 -0
- data/ext/tmail/base64/depend +1 -0
- data/ext/tmail/base64/extconf.rb +38 -0
- data/ext/tmail/scanner_c/MANIFEST +4 -0
- data/ext/tmail/scanner_c/depend +1 -0
- data/ext/tmail/scanner_c/extconf.rb +38 -0
- data/ext/tmail/scanner_c/scanner_c.c +582 -0
- data/lib/tmail.rb +4 -0
- data/lib/tmail/Makefile +19 -0
- data/lib/tmail/address.rb +245 -0
- data/lib/tmail/attachments.rb +47 -0
- data/lib/tmail/base64.rb +75 -0
- data/lib/tmail/compat.rb +39 -0
- data/lib/tmail/config.rb +71 -0
- data/lib/tmail/core_extensions.rb +67 -0
- data/lib/tmail/encode.rb +524 -0
- data/lib/tmail/header.rb +931 -0
- data/lib/tmail/index.rb +8 -0
- data/lib/tmail/interface.rb +540 -0
- data/lib/tmail/loader.rb +1 -0
- data/lib/tmail/mail.rb +507 -0
- data/lib/tmail/mailbox.rb +435 -0
- data/lib/tmail/mbox.rb +1 -0
- data/lib/tmail/net.rb +282 -0
- data/lib/tmail/obsolete.rb +137 -0
- data/lib/tmail/parser.rb +1475 -0
- data/lib/tmail/parser.y +381 -0
- data/lib/tmail/port.rb +379 -0
- data/lib/tmail/quoting.rb +142 -0
- data/lib/tmail/require_arch.rb +56 -0
- data/lib/tmail/scanner.rb +44 -0
- data/lib/tmail/scanner_r.rb +263 -0
- data/lib/tmail/stringio.rb +279 -0
- data/lib/tmail/tmail.rb +1 -0
- data/lib/tmail/utils.rb +281 -0
- data/lib/tmail/version.rb +38 -0
- data/meta/icli.yaml +16 -0
- data/meta/tmail-1.1.1.roll +24 -0
- data/sample/data/multipart +23 -0
- data/sample/data/normal +29 -0
- data/sample/data/sendtest +5 -0
- data/sample/data/simple +14 -0
- data/sample/data/test +27 -0
- data/sample/extract-attachements.rb +33 -0
- data/sample/from-check.rb +26 -0
- data/sample/multipart.rb +26 -0
- data/sample/parse-bench.rb +68 -0
- data/sample/parse-test.rb +19 -0
- data/sample/sendmail.rb +94 -0
- data/test/extctrl.rb +6 -0
- data/test/fixtures/raw_base64_decoded_string +0 -0
- data/test/fixtures/raw_base64_email +83 -0
- data/test/fixtures/raw_base64_encoded_string +1 -0
- data/test/fixtures/raw_email +14 -0
- data/test/fixtures/raw_email10 +20 -0
- data/test/fixtures/raw_email11 +34 -0
- data/test/fixtures/raw_email12 +32 -0
- data/test/fixtures/raw_email13 +29 -0
- data/test/fixtures/raw_email2 +114 -0
- data/test/fixtures/raw_email3 +70 -0
- data/test/fixtures/raw_email4 +59 -0
- data/test/fixtures/raw_email5 +19 -0
- data/test/fixtures/raw_email6 +20 -0
- data/test/fixtures/raw_email7 +66 -0
- data/test/fixtures/raw_email8 +47 -0
- data/test/fixtures/raw_email9 +28 -0
- data/test/fixtures/raw_email_quoted_with_0d0a +14 -0
- data/test/fixtures/raw_email_simple +11 -0
- data/test/fixtures/raw_email_with_illegal_boundary +58 -0
- data/test/fixtures/raw_email_with_multipart_mixed_quoted_boundary +50 -0
- data/test/fixtures/raw_email_with_nested_attachment +100 -0
- data/test/fixtures/raw_email_with_partially_quoted_subject +14 -0
- data/test/fixtures/raw_email_with_quoted_illegal_boundary +58 -0
- data/test/kcode.rb +14 -0
- data/test/test_address.rb +1128 -0
- data/test/test_attachments.rb +35 -0
- data/test/test_base64.rb +63 -0
- data/test/test_encode.rb +77 -0
- data/test/test_header.rb +885 -0
- data/test/test_helper.rb +2 -0
- data/test/test_mail.rb +623 -0
- data/test/test_mbox.rb +126 -0
- data/test/test_port.rb +430 -0
- data/test/test_scanner.rb +209 -0
- data/test/test_utils.rb +37 -0
- 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 @@
|
|
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
|
+
}
|