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
data/bat/stats
ADDED
@@ -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
|
data/bat/test
ADDED
@@ -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
|
+
|
data/ext/tmail/Makefile
ADDED
@@ -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,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
|
+
}
|