tmail 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
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,138 @@
1
+ #!/usr/bin/env ratch
2
+
3
+ # Simple code count analysis.
4
+ #
5
+ # This ratchet scan source code counting files,
6
+ # lines of code and comments and presents a
7
+ # report of it's findings.
8
+
9
+ main :stats do
10
+ statistics
11
+ end
12
+
13
+ DEFAULT_STATS_FILES = [ 'lib/**/*', 'ext/**/*', 'bin/**/*' ]
14
+
15
+ # Basic statics on line count.
16
+ #
17
+ # This task counts the file and lines of code in your
18
+ # project and provided some statistical figures.
19
+ #
20
+ # files Files to include and/or exclude in
21
+ # analysis. '+' and '-' files patterns
22
+ # are accepted. The default includes all
23
+ # files in the lib/ and ext/ directories.
24
+ #
25
+ # TODO Support - and + augmentations for configuration.
26
+
27
+ def statistics
28
+ config = configuration['stats'] || {}
29
+ scripts = config['files'] || DEFAULT_STATS_FILES
30
+ files = scripts.inject([]){ |memo, find| memo.concat(glob(find)); memo }
31
+ #Dir.multiglob_with_default(DEFAULT_STATS_FILES)
32
+
33
+ fc, l, c, r, t, s = *line_count(*files)
34
+
35
+ fct, lt, ct, rt, tt, st = *([0]*6)
36
+ if File.directory?('test')
37
+ fct, lt, ct, rt, tt, st = *line_count('test/**/*')
38
+ t = lt if lt > 0
39
+ end
40
+
41
+ rat = lambda do |d,n|
42
+ if d > n and n != 0
43
+ "%.1f" % [ d.to_f / n ]
44
+ elsif n > d and d != 0
45
+ "-" #"%.1f:1" % [ n.to_f / d ]
46
+ elsif d == 0 or n == 0
47
+ "-"
48
+ else
49
+ "1.0"
50
+ end
51
+ end
52
+
53
+ per = lambda do |n,d|
54
+ if d != 0
55
+ (((n.to_f / d)*100).to_i).to_s + "%"
56
+ else
57
+ "-"
58
+ end
59
+ end
60
+
61
+ max = l.to_s.size + 4
62
+
63
+ puts
64
+ #puts "FILES:"
65
+ #puts " source: #{fc}"
66
+ #puts " test : #{fct}"
67
+ #puts " total : #{fc+fct}"
68
+ #puts
69
+ #puts "LINES:"
70
+ #puts " code : %#{max}s %4s" % [ c.to_s, per[c,l] ]
71
+ #puts " docs : %#{max}s %4s" % [ r.to_s, per[r,l] ]
72
+ #puts " space : %#{max}s %4s" % [ s.to_s, per[s,l] ]
73
+ #puts " test : %#{max}s %4s" % [ t.to_s, per[t,l] ]
74
+ #puts " total : %#{max}s %4s" % [ l.to_s, per[l,l] ]
75
+ #puts
76
+ #puts "Ratio to 1 :"
77
+ #puts " code to test : #{rat[c,t]} #{per[c,t]}"
78
+
79
+ head = ["Total", "Code", "-%-", "Docs", "-%-", "Blank", "-%-", "Files"]
80
+ prod = [l.to_s, c.to_s, per[c,l], r.to_s, per[r,l], s.to_s, per[s,l], fc]
81
+ test = [lt.to_s, ct.to_s, per[ct,l], rt.to_s, per[rt,l], st.to_s, per[st,l], fct]
82
+ totl = [(l+lt), (c+ct), per[c+ct,l+lt], (r+rt), per[r+rt,l+lt], (s+st), per[s+st,l+lt], (fc+fct)]
83
+
84
+ puts "TYPE %#{max}s %#{max}s %4s %#{max}s %4s %#{max}s %4s %#{max}s" % head
85
+ puts "Source %#{max}s %#{max}s %4s %#{max}s %4s %#{max}s %4s %#{max}s" % prod
86
+ puts "Test %#{max}s %#{max}s %4s %#{max}s %4s %#{max}s %4s %#{max}s" % test
87
+ puts "Total %#{max}s %#{max}s %4s %#{max}s %4s %#{max}s %4s %#{max}s" % totl
88
+ puts
89
+ puts "RATIO Code Docs Blank Test Total"
90
+ puts "Code %7s %7s %7s %7s %7s" % [ rat[c,c], rat[c,r], rat[c,s], rat[c,t], rat[c,l] ]
91
+ puts "Docs %7s %7s %7s %7s %7s" % [ rat[r,c], rat[r,r], rat[r,s], rat[r,t], rat[r,l] ]
92
+ puts "Blank %7s %7s %7s %7s %7s" % [ rat[s,c], rat[s,r], rat[s,s], rat[s,t], rat[s,l] ]
93
+ puts "Test %7s %7s %7s %7s %7s" % [ rat[t,c], rat[t,r], rat[t,s], rat[t,t], rat[t,l] ]
94
+ puts "Total %7s %7s %7s %7s %7s" % [ rat[l,c], rat[l,r], rat[l,s], rat[l,t], rat[l,l] ]
95
+ puts
96
+ end
97
+
98
+ private
99
+
100
+ # Return line counts for files.
101
+
102
+ def line_count( *files )
103
+ files = files.inject([]) do |memo, find|
104
+ memo.concat(Dir.glob(find)); memo
105
+ end
106
+
107
+ fc, l, c, t, r = 0, 0, 0, 0, 0
108
+ bt, rb = false, false
109
+
110
+ files.each do |fname|
111
+ next unless fname =~ /.*rb/ # TODO should this be done?
112
+ fc += 1
113
+ File.open( fname ) do |f|
114
+ while line = f.gets
115
+ l += 1
116
+ next if line =~ /^\s*$/
117
+ case line
118
+ when /^=begin\s+test/
119
+ tb = true; t+=1
120
+ when /^=begin/
121
+ rb = true; r+=1
122
+ when /^=end/
123
+ t+=1 if tb
124
+ r+=1 if rb
125
+ rb, tb = false, false
126
+ when /^\s*#/
127
+ r += 1
128
+ else
129
+ c+=1 if !(rb or tb)
130
+ r+=1 if rb
131
+ t+=1 if tb
132
+ end
133
+ end
134
+ end
135
+ end
136
+ s = l - c - r - t
137
+ return fc, l, c, r, t, s
138
+ end
data/bat/tag ADDED
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env ratch
2
+
3
+ # tag current version
4
+
5
+ main :tag do
6
+ rubyforge_username = ENV['RUBYFORGE_USERNAME']
7
+
8
+ abort "Need RUBYFORGE_USERNAME evironment setting." unless rubyforge_username
9
+
10
+ name, version = *File.basename(glob("meta/*.roll").first).chomp('.roll').split('-')
11
+
12
+ changes = /^===\s*#{version}(.*?)\n===/m.match(File.read('History.txt'))[0]
13
+ changes = changes.chomp('===').strip.sub(/^===\s+/, 'TAG ')
14
+
15
+ #puts "#{name}-#{version}"
16
+ puts changes
17
+ puts
18
+
19
+ case ask("Continue? [yN]").strip.downcase
20
+ when 'y', 'yes'
21
+ svn "copy", "svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{name}/trunk",
22
+ "svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{name}/tags/REL-#{version}"
23
+ end
24
+
25
+ end
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env ratch
2
+
3
+ # Run unit tests
4
+
5
+ live = ARGV.delete('--live')
6
+
7
+ unless live
8
+ $LOAD_PATH.unshift(File.expand_path('lib'))
9
+ end
10
+
11
+ main :test do
12
+ if find = argv[0]
13
+ unless file?(find)
14
+ find = File.join(find, '**', 'test_*.rb')
15
+ end
16
+ else
17
+ find = 'test/**/test_*.rb'
18
+ end
19
+
20
+ Dir.glob(find).each do |file|
21
+ next if dir?(file)
22
+ load file
23
+ end
24
+ end
25
+
@@ -0,0 +1,25 @@
1
+ #
2
+ # ext/tmail/Makefile
3
+ #
4
+
5
+ .PHONY: scanner_c base64 clean distclean
6
+
7
+ all: scanner_c base64
8
+
9
+ scanner_c: scanner_c/Makefile
10
+ cd scanner_c; $(MAKE)
11
+ scanner_c/Makefile: scanner_c/extconf.rb
12
+ cd scanner_c; ruby extconf.rb
13
+
14
+ base64: base64/Makefile
15
+ cd base64; $(MAKE)
16
+ base64/Makefile: base64/extconf.rb
17
+ cd base64; ruby extconf.rb
18
+
19
+ clean:
20
+ cd base64; $(MAKE) clean
21
+ cd scanner_c; $(MAKE) clean
22
+
23
+ distclean:
24
+ cd base64; $(MAKE) distclean
25
+ cd scanner_c; $(MAKE) distclean
@@ -0,0 +1,4 @@
1
+ MANIFEST
2
+ tmbase64.c
3
+ extconf.rb
4
+ depend
@@ -0,0 +1,264 @@
1
+ /*
2
+
3
+ base64.c
4
+
5
+ Copyright (c) 2001-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 "ruby.h"
14
+ #include "version.h"
15
+ #include <stdio.h>
16
+
17
+ #ifdef DEBUG
18
+ # define D(code) code
19
+ #else
20
+ # define D(code)
21
+ #endif
22
+
23
+ static char *CONVTAB =
24
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
25
+ static int REVTAB[256];
26
+ #define INIT (-1)
27
+ #define SKIP (-2)
28
+ #define ILLEGAL (-3)
29
+
30
+ #if RUBY_VERSION_CODE < 170 /* Ruby 1.6 */
31
+ # define StringValue(s) tmail_rb_string_value(&(s))
32
+ static void
33
+ tmail_rb_string_value(s)
34
+ VALUE *s;
35
+ {
36
+ if (TYPE(*s) != T_STRING) {
37
+ *s = rb_str_to_str(*s);
38
+ }
39
+ }
40
+ #endif
41
+
42
+ static void
43
+ get_ptrlen(s, ptr, len)
44
+ VALUE *s;
45
+ char **ptr;
46
+ long *len;
47
+ {
48
+ StringValue(*s);
49
+ *ptr = RSTRING(*s)->ptr;
50
+ if (!*ptr) *ptr = "";
51
+ *len = RSTRING(*s)->len;
52
+ }
53
+
54
+ static long
55
+ calculate_buflen(len, eollen, limit)
56
+ long len, eollen;
57
+ {
58
+ long result;
59
+
60
+ result = (len/3 + 1) * 4;
61
+ if (eollen) {
62
+ result += (result/limit + 1) * eollen;
63
+ }
64
+ return result;
65
+ }
66
+
67
+ static VALUE
68
+ do_base64(str, eolv, limit)
69
+ VALUE str, eolv;
70
+ long limit;
71
+ {
72
+ char *buf, *b;
73
+ char *p, *pend;
74
+ long len;
75
+ char *eol;
76
+ long eollen;
77
+ VALUE s;
78
+ char *linehead;
79
+
80
+ get_ptrlen(&str, &p, &len);
81
+ pend = p + len;
82
+ if (NIL_P(eolv)) {
83
+ eol = "";
84
+ eollen = 0;
85
+ }
86
+ else {
87
+ get_ptrlen(&eolv, &eol, &eollen);
88
+ }
89
+ b = buf = ALLOC_N(char, calculate_buflen(len, eollen, limit));
90
+ linehead = b;
91
+
92
+ while (pend - p >= 3) {
93
+ if (eollen) {
94
+ if (b - linehead + 4 > limit) {
95
+ memcpy(b, eol, eollen); b += eollen;
96
+ linehead = b;
97
+ }
98
+ }
99
+ *b++ = CONVTAB[0x3f & (p[0] >> 2)];
100
+ *b++ = CONVTAB[0x3f & (((p[0] << 4) & 0x30) | ((p[1] >> 4) & 0xf))];
101
+ *b++ = CONVTAB[0x3f & (((p[1] << 2) & 0x3c) | ((p[2] >> 6) & 0x3))];
102
+ *b++ = CONVTAB[0x3f & p[2]];
103
+ p += 3;
104
+ }
105
+ if ((b - linehead) + (pend - p) > limit) {
106
+ if (eollen) {
107
+ memcpy(b, eol, eollen); b += eollen;
108
+ }
109
+ }
110
+ if (pend - p == 2) {
111
+ *b++ = CONVTAB[0x3f & (p[0] >> 2)];
112
+ *b++ = CONVTAB[0x3f & (((p[0] << 4) & 0x30) | ((p[1] >> 4) &0xf))];
113
+ *b++ = CONVTAB[0x3f & (((p[1] << 2) & 0x3c) | 0)];
114
+ *b++ = '=';
115
+ }
116
+ else if (pend - p == 1) {
117
+ *b++ = CONVTAB[0x3f & (p[0] >> 2)];
118
+ *b++ = CONVTAB[0x3f & (((p[0] << 4) & 0x30) | 0)];
119
+ *b++ = '=';
120
+ *b++ = '=';
121
+ }
122
+ if (eollen) {
123
+ memcpy(b, eol, eollen); b += eollen;
124
+ }
125
+
126
+ s = rb_str_new("", 0);
127
+ rb_str_cat(s, buf, b - buf);
128
+ free(buf);
129
+
130
+ return s;
131
+ }
132
+
133
+ #define DEFAULT_LINE_LIMIT 72
134
+
135
+ /* def folding_encode( str, eol, limit ) */
136
+ static VALUE
137
+ b64_fold_encode(argc, argv, self)
138
+ int argc;
139
+ VALUE *argv;
140
+ VALUE self;
141
+ {
142
+ VALUE str, eol, limit_v;
143
+ long limit = DEFAULT_LINE_LIMIT;
144
+
145
+ switch (rb_scan_args(argc, argv, "12", &str, &eol, &limit_v)) {
146
+ case 1:
147
+ eol = rb_str_new("\n", 1);
148
+ break;
149
+ case 2:
150
+ break;
151
+ case 3:
152
+ limit = NUM2LONG(limit_v);
153
+ if (limit < 4) {
154
+ rb_raise(rb_eArgError, "too small line length limit");
155
+ }
156
+ break;
157
+ default:
158
+ break;
159
+ }
160
+ return do_base64(str, eol, limit);
161
+ }
162
+
163
+ static VALUE
164
+ b64_encode(self, str)
165
+ VALUE self, str;
166
+ {
167
+ return do_base64(str, Qnil, 0);
168
+ }
169
+
170
+ static VALUE
171
+ b64_decode(argc, argv, self)
172
+ int argc;
173
+ VALUE *argv;
174
+ VALUE self;
175
+ {
176
+ VALUE str, strict;
177
+ char *buf, *bp;
178
+ char *p, *pend;
179
+ long len;
180
+ int a, b, c, d;
181
+ VALUE s;
182
+
183
+ if (rb_scan_args(argc, argv, "11", &str, &strict) == 1) {
184
+ strict = Qfalse;
185
+ }
186
+
187
+ get_ptrlen(&str, &p, &len);
188
+ pend = p + len;
189
+ bp = buf = ALLOC_N(char, (len/4 + 1) * 3);
190
+
191
+ #define FETCH(ch) \
192
+ while (1) { \
193
+ if (p >= pend) goto brk; \
194
+ ch = REVTAB[(int)(*p++)]; \
195
+ if (ch == ILLEGAL) { \
196
+ rb_raise(rb_eArgError, "corrupted base64 string"); \
197
+ } \
198
+ else if (ch == SKIP) { \
199
+ ; \
200
+ } \
201
+ else { \
202
+ break; \
203
+ } \
204
+ ch = INIT; \
205
+ }
206
+ a = b = c = d = INIT;
207
+ while (p < pend) {
208
+ FETCH(a); D(printf("fetch a: %d\n", (int)a));
209
+ FETCH(b); D(printf("fetch b: %d\n", (int)b));
210
+ FETCH(c); D(printf("fetch c: %d\n", (int)c));
211
+ FETCH(d); D(printf("fetch d: %d\n", (int)d));
212
+
213
+ *bp++ = (a << 2) | (b >> 4);
214
+ *bp++ = (b << 4) | (c >> 2);
215
+ *bp++ = (c << 6) | d;
216
+ a = b = c = d = INIT;
217
+ }
218
+ brk:
219
+ if (a != INIT && b != INIT && c != INIT) {
220
+ D(puts("3bytes"));
221
+ *bp++ = (a << 2) | (b >> 4);
222
+ *bp++ = (b << 4) | (c >> 2);
223
+ }
224
+ else if (a != INIT && b != INIT) {
225
+ D(puts("2bytes"));
226
+ *bp++ = (a << 2) | (b >> 4);
227
+ }
228
+ /* ignore if only 'a' */
229
+
230
+ D(printf("decoded len=%d\n", (int)(bp - buf)));
231
+ s = rb_str_new("", 0);
232
+ rb_str_cat(s, buf, bp - buf);
233
+ free(buf);
234
+
235
+ return s;
236
+ }
237
+
238
+ static void
239
+ initialize_reverse_table()
240
+ {
241
+ int i;
242
+
243
+ for (i = 0; i < 256; i++) {
244
+ REVTAB[i] = ILLEGAL;
245
+ }
246
+ REVTAB[(int)'='] = SKIP;
247
+ REVTAB[(int)'\r'] = SKIP;
248
+ REVTAB[(int)'\n'] = SKIP;
249
+ for (i = 0; i < 64; i++) {
250
+ REVTAB[(int)CONVTAB[i]] = (char)i;
251
+ }
252
+ }
253
+
254
+ void
255
+ Init_base64()
256
+ {
257
+ VALUE Base64;
258
+
259
+ Base64 = rb_eval_string("module TMail; module Base64; end end; ::TMail::Base64");
260
+ rb_define_module_function(Base64, "c_folding_encode", b64_fold_encode, -1);
261
+ rb_define_module_function(Base64, "c_encode", b64_encode, 1);
262
+ rb_define_module_function(Base64, "c_decode", b64_decode, -1);
263
+ initialize_reverse_table();
264
+ }