tmail 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
}
|