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