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,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
+ }