|
1
|
/* |
|
2
|
** This program reads a raw email file and attempts to decode it into |
|
3
|
** a more human-readable format. The following decodings are done: |
|
4
|
** |
|
5
|
** (1) Header values are prefixed by "| " at the left margin. |
|
6
|
** |
|
7
|
** (2) Content-Transfer-Encoding is recognized and the content is |
|
8
|
** decoded for display. |
|
9
|
*/ |
|
10
|
#define _GNU_SOURCE |
|
11
|
#include <stdio.h> |
|
12
|
#include <string.h> |
|
13
|
#include <ctype.h> |
|
14
|
|
|
15
|
#define BINARY 0 |
|
16
|
#define BASE64 1 |
|
17
|
#define QUOTED 2 |
|
18
|
|
|
19
|
static int decode_hex(char c){ |
|
20
|
if( c>='0' && c<='9' ) return c - '0'; |
|
21
|
if( c>='A' && c<='F' ) return c - 'A' + 10; |
|
22
|
if( c>='a' && c<='f' ) return c - 'a' + 10; |
|
23
|
return -1; |
|
24
|
} |
|
25
|
|
|
26
|
static void convert_file(const char *zFilename, FILE *in){ |
|
27
|
int inHdr = 1; |
|
28
|
int n; |
|
29
|
int nBoundary; |
|
30
|
int decodeType = 0; |
|
31
|
int textMimetype = 1; |
|
32
|
char *zB; |
|
33
|
char zBoundary[200]; |
|
34
|
char zLine[5000]; |
|
35
|
char zOut[5000]; |
|
36
|
while( fgets(zLine, sizeof(zLine), in) ){ |
|
37
|
if( !inHdr |
|
38
|
&& zLine[0]=='-' |
|
39
|
&& zLine[1]=='-' |
|
40
|
&& strncmp(zLine+2,zBoundary,nBoundary)==0 |
|
41
|
){ |
|
42
|
printf("|----------------- end of body section ---------|\n"); |
|
43
|
inHdr = 1; |
|
44
|
} |
|
45
|
if( !inHdr ){ |
|
46
|
if( textMimetype && decodeType==BASE64 ){ |
|
47
|
int ii, jj, c, x, y; |
|
48
|
int bits = 0; |
|
49
|
for(ii=jj=0; (c = zLine[ii])!=0; ii++){ |
|
50
|
if( c>='A' && c<='Z' ){ |
|
51
|
x = c - 'A'; |
|
52
|
}else if( c>='a' && c<='z' ){ |
|
53
|
x = c - 'a' + 26; |
|
54
|
}else if( c>='0' && c<='9' ){ |
|
55
|
x = c - '0' + 52; |
|
56
|
}else if( c=='+' ){ |
|
57
|
x = 62; |
|
58
|
}else if( c=='/' ){ |
|
59
|
x = 63; |
|
60
|
}else if( c=='=' ){ |
|
61
|
x = 0; |
|
62
|
}else{ |
|
63
|
continue; |
|
64
|
} |
|
65
|
if( bits==0 ){ |
|
66
|
y = x; |
|
67
|
bits = 6; |
|
68
|
}else if( bits==6 ){ |
|
69
|
zOut[jj++] = ((y<<2) & 0xfc) | ((x>>4) & 0x03); |
|
70
|
y = x & 0xf; |
|
71
|
bits = 4; |
|
72
|
}else if( bits==4 ){ |
|
73
|
zOut[jj++] = ((y<<4) & 0xf0) | ((x>>2) & 0x0f); |
|
74
|
y = x & 0x3; |
|
75
|
bits = 2; |
|
76
|
}else if( bits==2 ){ |
|
77
|
zOut[jj++] = ((y<<6) & 0xc0) | (x & 0x3f); |
|
78
|
bits = 0; |
|
79
|
} |
|
80
|
} |
|
81
|
zOut[jj] = 0; |
|
82
|
printf("%s", zOut); |
|
83
|
}else if( textMimetype && decodeType==QUOTED ){ |
|
84
|
int ii, jj, c; |
|
85
|
for(ii=jj=0; (c = zLine[ii])!=0; ii++){ |
|
86
|
if( c=='=' ){ |
|
87
|
int x1 = decode_hex(zLine[ii+1]); |
|
88
|
int x2 = decode_hex(zLine[ii+2]); |
|
89
|
if( x1>=0 && x2>=0 ){ |
|
90
|
zOut[jj++] = (x1<<4) | x2; |
|
91
|
ii += 2; |
|
92
|
}else if( zLine[ii+1]=='\r' && zLine[ii+2]=='\n' ){ |
|
93
|
ii += 2; |
|
94
|
} |
|
95
|
}else{ |
|
96
|
zOut[jj++] = c; |
|
97
|
} |
|
98
|
} |
|
99
|
zOut[jj] = 0; |
|
100
|
printf("%s", zOut); |
|
101
|
}else{ |
|
102
|
printf("%s", zLine); |
|
103
|
} |
|
104
|
continue; |
|
105
|
} |
|
106
|
n = (int)strlen(zLine); |
|
107
|
while( n>0 && isspace(zLine[n-1]) ){ n--; } |
|
108
|
zLine[n] = 0; |
|
109
|
if( n==0 ){ |
|
110
|
inHdr = 0; |
|
111
|
printf("|----------------- end of header ---------------|\n"); |
|
112
|
continue; |
|
113
|
} |
|
114
|
printf("| %s\n", zLine); |
|
115
|
if( strncasecmp(zLine,"Content-Type:", 13)==0 ){ |
|
116
|
textMimetype = strstr(zLine, "text/")!=0; |
|
117
|
printf("|** %s content type **|\n", |
|
118
|
textMimetype ? "Text" : "Non-text"); |
|
119
|
} |
|
120
|
if( strncasecmp(zLine,"Content-Transfer-Encoding:", 26)==0 ){ |
|
121
|
if( strcasestr(zLine, "base64") ){ |
|
122
|
decodeType = BASE64; |
|
123
|
}else if( strcasestr(zLine, "quoted-printable") ){ |
|
124
|
decodeType = QUOTED; |
|
125
|
}else{ |
|
126
|
decodeType = BINARY; |
|
127
|
} |
|
128
|
printf("|** Content encoding %s **|\n", |
|
129
|
decodeType==BASE64 ? "BASE64" : |
|
130
|
decodeType==QUOTED ? "QUOTED" : "BINARY"); |
|
131
|
} |
|
132
|
zB = strstr(zLine, "boundary=\""); |
|
133
|
if( zB ){ |
|
134
|
int kk; |
|
135
|
zB += 10; |
|
136
|
for(kk=0; zB[kk] && zB[kk]!='"' && kk<sizeof(zBoundary)-1; kk++){ |
|
137
|
zBoundary[kk] = zB[kk]; |
|
138
|
} |
|
139
|
zBoundary[kk] = 0; |
|
140
|
nBoundary = kk; |
|
141
|
printf("|** boundary [%s] **|\n", zBoundary); |
|
142
|
} |
|
143
|
} |
|
144
|
} |
|
145
|
|
|
146
|
int main(int argc, char **argv){ |
|
147
|
if( argc==1 ){ |
|
148
|
convert_file("<stdin>", stdin); |
|
149
|
return 0; |
|
150
|
}else{ |
|
151
|
int i; |
|
152
|
for(i=1; i<argc; i++){ |
|
153
|
FILE *in = fopen(argv[i], "rb"); |
|
154
|
if( in==0 ){ |
|
155
|
fprintf(stderr, "cannot open \"%s\"", argv[i]); |
|
156
|
}else{ |
|
157
|
convert_file(argv[i], in); |
|
158
|
fclose(in); |
|
159
|
} |
|
160
|
} |
|
161
|
} |
|
162
|
return 0; |
|
163
|
} |
|
164
|
|