14#define WHO "822mimeparts"
35 logmsg(
WHO,111,FATAL,
"out of memory");
38static int issafe(
char ch)
40 if ((ch >=
'a') && (ch <=
'z'))
return 1;
41 if ((ch >=
'A') && (ch <=
'Z'))
return 1;
42 if ((ch >=
'0') && (ch <=
'9'))
return 1;
46static void die_write(
char *fn) { unlink(fn); _exit(1); };
52char name[11] = {
'0',
'0',
'0',
'u',
'n',
'k',
'n',
'o',
'w',
'n',
'\0' };
53char pname[7] = {
'0',
'0',
'0',
'0',
'0',
'0',
'\0' };
55static int msgname(
char *
out,
const char *in)
60 int at = str_chr(in,
'@');
61 if (in[at] ==
'@' && at > 9) {
65 if (issafe(
c))
out[j--] =
c;
73static int mime_partname(
char *
out,
char *in,
int len)
80 if (issafe(
c))
out[j--] =
c;
93 case 1:
case -1:
return "7bit";
94 case 2:
case -2:
return "8bit";
95 case 3:
case -3:
return "base64";
96 case 4:
case -4:
return "binary";
97 case 5:
case -5:
return "quoted-printable";
98 default:
return "unkown";
103static int printpart(
char *
name,stralloc *in,
int mimetype,stralloc *
alias)
108 char size[FMT_ULONG];
112 fd = open_trunc(
name);
113 if (fd == -1) die_write(
name);
117 size[fmt_ulong(size,(
unsigned long) len)] = 0;
123 buffer_put(&
bo,in->s,
out);
126 }
while (in->len > 0);
128 if (buffer_flush(&
bo)) die_write(
name);
129 if (close(fd) == -1) die_write(
name);
132 logmsg(
WHO,0,INFO,B(
"Created: ",
name,
" (",
type,
", ",size,
" byte) [",
alias->s,
"]."));
137 logmsg(
WHO,0,INFO,B(
"Created: ",
name,
" (",
type,
", ",size,
" byte)."));
144 {
"Message-ID", &
flag, 0, &
valuem, 0, 0, 0 } , { 0, 0, 0, 0, 0, 0, 0 }
148 {
"Content-Type", &
flag, 0, &
valuet, 0, 0, 0 } , { 0, 0, 0, 0, 0, 0, 0 }
152 {
"Content-Transfer-Encoding", &
flag, 0, &
valuec, 0, 0, 0 } , { 0, 0, 0, 0, 0, 0, 0 }
158 char sizes[FMT_ULONG];
159 char sizee[FMT_ULONG];
162 if (!stralloc_cats(&
partname,
".body,0")) nomem();
163 if (!stralloc_0(&
partname)) nomem();
165 stralloc decoded = {0};
166 if (!stralloc_ready(&decoded,
bodybuf.len)) nomem();
168 if (mimetype == -1) {
170 if (r < 0) logmsg(
WHO,111,WARN,
"malformed base64 mime part");
171 }
else if (mimetype == -2) {
173 if (r < 0) logmsg(
WHO,111,WARN,
"malformed quoted-printable part");
178 sizes[fmt_ulong(sizes,(
unsigned long)
start + 3)] = 0;
179 sizee[fmt_ulong(sizee,(
unsigned long) end + 2)] = 0;
180 if (
verbose) logmsg(
WHO,0,INFO,B(
"Start of part: @line=",sizes,
" End of part: @line=",sizee));
188 char sizes[FMT_ULONG];
189 char sizee[FMT_ULONG];
195 sizes[fmt_ulong(sizes,(
unsigned long) num)] = 0;
196 if (!stralloc_0(&
partbuf)) nomem();
198 mime_partname(
pname,bound->s,bound->len);
200 if (!stralloc_cats(&
partname,
".")) nomem();
202 if (!stralloc_cats(&
partname,
",")) nomem();
203 if (!stralloc_cats(&
partname,sizes)) nomem();
204 if (!stralloc_0(&
partname)) nomem();
206 stralloc decoded = {0};
207 if (!stralloc_ready(&decoded,
partbuf.len)) nomem();
211 if (r < 0) logmsg(
WHO,111,INFO,
"malformed base64 mime part");
212 }
else if (mimetype == 5) {
214 if (r < 0) logmsg(
WHO,111,INFO,
"malformed quoted-printable part");
219 sizes[fmt_ulong(sizes,(
unsigned long)
start + 3)] = 0;
220 sizee[fmt_ulong(sizee,(
unsigned long) end + 2)] = 0;
221 if (
verbose) logmsg(
WHO,0,INFO,B(
"Start of part: @line=",sizes,
" End of part: @line=",sizee));
227 if (!stralloc_copys(&
partbuf,
"")) nomem();
242 if (*(
name->s) !=
'=' && *(
name->s + 1) !=
'?')
return 0;
247 if (!stralloc_copys(&in,
"")) nomem();
248 if (!stralloc_copys(&
out,
"")) nomem();
250 for (
int i = 0; i <
name->len; i++) {
253 if (ch ==
'\0')
break;
254 if (ch ==
'?') seenq++;
256 if (!stralloc_copys(&in,
"")) nomem();
258 if (ch ==
'q' || ch ==
'Q') {
260 }
else if (ch ==
'b' || ch ==
'B') {
269 if (seenq == 3 && ch !=
'?')
if (!stralloc_append(&in,&ch)) nomem();
270 if (seenq == 4) { done = 1;
if (!stralloc_0(&in)) nomem(); }
272 if (!stralloc_append(&in,&ch)) nomem();
274 if (i ==
name->len - 1) done = 1;
280 case 3:
if (!stralloc_copys(&word,
"")) nomem();
282 if (!stralloc_catb(&
out,word.s,done)) nomem();
284 logmsg(
WHO,0,WARN,B(
"error in decoding 'Name:' ",word.s));
285 if (!stralloc_catb(&
out,in.s,in.len)) nomem();
286 } done = 0; seenq = 0;
break;
287 case 5:
if (!stralloc_copys(&word,
"")) nomem();
289 if (!stralloc_catb(&
out,word.s,done)) nomem();
291 if (!stralloc_catb(&
out,in.s,in.len)) nomem();
292 logmsg(
WHO,0,WARN,B(
"error in decoding 'Name:' ",word.s));
293 if (!stralloc_catb(&
out,in.s,in.len)) nomem();
294 } done = 0; seenq = 0;
break;
298 if (!stralloc_copy(
name,&
out)) nomem();
299 if (!stralloc_0(
name)) nomem();
310 if (*(
name->s) !=
'=' && *(
name->s + 1) !=
'?')
return 0;
315 if (!stralloc_copys(&in,
"")) nomem();
317 for (
int i = 2; i <
name->len; i++) {
319 if (ch ==
'?') { seen++;
continue; }
320 if (seen == 2)
if (!stralloc_append(&in,&ch)) nomem();
322 if (!stralloc_0(&in)) nomem();
326 logmsg(
WHO,0,WARN,B(
"error in BASE64 decoding: ",in.s));
327 if (!stralloc_copy(
name,&in)) nomem();
329 if (!stralloc_copy(
name,&
out)) nomem();
342 if (ch ==
'C' || ch ==
'\n') seen = 3;
344 if (seen == 0 && in->len > 10) {
345 for (
int i = 0; i < in->len - 5; i++) {
346 if (!case_diffb(in->s + i,5,
"name=")) {
347 if (!stralloc_copys(
name,
"")) nomem();
351 for (
int j = i; j < in->len - 2; j++) {
353 if (ch ==
'"') { seena++;
continue; }
354 if (ch ==
';') { seen = 3;
goto DONE; }
355 if (!stralloc_append(
name,&ch)) nomem();
358 if (seena == 2) { seen = 3;
goto DONE; }
364 if (seen && seen < 3) {
365 if (ch ==
' ' || ch ==
'\t') {
366 for (
int j = 1 ; j < in->len - 2; j++) {
368 if (ch ==
'"') { seena++;
continue; }
369 if (ch ==
';') { seen = 3;
goto DONE; }
370 if (!stralloc_append(
name,&ch)) nomem();
373 if (seen == 3 || seena == 2)
goto DONE;
376 if (ch ==
'\n') { seen == 3;
goto DONE; }
383 if (!stralloc_0(
name)) nomem();
396 int part[4] = {0, 0, 0, 0};
404 while ((opt = getoptb(argc,argv,
"hlv")) != opteof)
406 case 'h': logmsg(
WHO,99,USAGE,
"822mimeparts [-v|-l] < message.");
break;
407 case 'l':
slink = 1;
break;
409 default : logmsg(
WHO,99,USAGE,
"822mimeparts [-v|-l] < message.");
break;
418 for (len = 0;;len++) {
419 if (getln(buffer_0,&
line,&
match,
'\n') == -1)
420 logmsg(
WHO,111,FATAL,
"unable to read input: ");
428 logmsg(
WHO,111,ERROR,
"malformed message (first non-header line not blank)");
434 if (!stralloc_0(&
mname)) nomem();
440 if (!case_diffb(
valuec.s,16,
"quoted-printable")) { mimetype = -2; part[3] = -1; }
441 else if (!case_diffb(
valuec.s,6,
"base64")) { mimetype = -1; part[3] = -1; }
442 if (mimetype < 0) {
if (!stralloc_cats(&
bodybuf,
""))
return -1; }
448 for (
int i = 0; i <
valuet.len - 12; i++) {
449 if (*(
valuet.s + i) ==
'\0')
break;
450 if (!case_diffb(
valuet.s + i,9,
"boundary=")) {
451 if (!stralloc_copys(&
boundary,
"--")) nomem();
454 for (
int j = i; j <
valuet.len - 2; j++) {
456 if (ch ==
';' || ch ==
'"')
continue;
457 if (!stralloc_append(&
boundary,&ch)) nomem();
466 for (
int l = len;;l++) {
467 if (getln(buffer_0,&
line,&
match,
'\n') == -1)
468 logmsg(
WHO,111,FATAL,
"unable to read input: ");
471 if (!stralloc_0(&
line)) nomem();
478 if (!part[1]) part[1] = l; part[2] = l;
483 if (case_startb(
line.s,26,
"Content-Transfer-Encoding:")) {
484 part[0] += 1; part[1] = l; part[3] = 1;
486 if (case_startb(
line.s + 27,4,
"7bit")) mimetype = 1;
487 else if (case_startb(
line.s + 27,4,
"8bit")) mimetype = 2;
488 else if (case_startb(
line.s + 27,6,
"base64")) mimetype = 3;
489 else if (case_startb(
line.s + 27,6,
"binary")) mimetype = 4;
490 else if (case_startb(
line.s + 27,16,
"quoted-printable")) mimetype = 5;
491 if (!stralloc_copys(&
partbuf,
"")) nomem();
497 if (case_startb(
line.s,13,
"Content-Type:")) {
499 if (*(
line.s +
line.len - 3) ==
';') skip = 1;
500 if (case_startb(
line.s + 14,27,
"application/pgp-signature")) mimetype = 10;
502 if (case_startb(
line.s,2,
"X-"))
continue;
506 for (
int i = 0; i <
line.len - 12; i++) {
508 if (*(
line.s + i) ==
'\n')
break;
509 if (!case_diffb(
line.s + i,9,
"boundary=")) {
510 if (!stralloc_copys(&
boundary,
"--")) nomem();
513 for (
int j = i; j <
line.len - 2; j++) {
515 if (ch ==
';')
break;
516 if (ch ==
'"')
continue;
517 if (!stralloc_append(&
boundary,&ch)) nomem();
521 if (!stralloc_0(&
boundary)) nomem();
533 if (case_startb(
line.s,12,
"MIME-Version")) { part[3] = 3;
continue; }
534 if (case_startb(
line.s,25,
"Content-Type: application") ||
535 case_startb(
line.s,23,
"Content-Type: text/html") ||
536 case_startb(
line.s,19,
"Content-Type: image") ||
537 case_startb(
line.s,19,
"Content-Type: audio") ||
538 case_startb(
line.s,19,
"Content-Type: video") ||
539 case_startb(
line.s,19,
"Content-Type: octet") ||
540 case_startb(
line.s,19,
"Content-Disposition")) { part[3] = 4; }
547 if (seen == 1)
continue;
554 if (*
line.s ==
'\n')
continue;
555 if (case_startb(
line.s,10,
"Content-"))
continue;
556 if (skip == 1) { skip = 0;
continue; }
564 case 3:
if (*
line.s ==
' ' || *
line.s ==
'-' || *
line.s ==
'\t')
break;
566 part[2] = l; part[3] = 5;
569 part[2] = l; part[3] = 5;
576 if (mimetype != 5 && !str_diffn(
line.s,
"--",2)) {
578 if (!stralloc_copys(&
partbuf,
"")) nomem();
587 if (!stralloc_0(&
bodybuf)) nomem();
void mime_partproc(stralloc *bound, int mimetype, int start, int end)
char * mime_type(int type)
int attachment_name(stralloc *name, stralloc *in)
int b64name(stralloc *name)
int decode_name(stralloc *name)
void msg_bodyproc(int mimetype, int start, int end)
int mess822_qpdecode(stralloc *, const char *, int, int)
int mess822_line(mess822_header *, stralloc *)
int mess822_end(mess822_header *)
int mess822_ok(stralloc *)
int mess822_begin(mess822_header *, mess822_action *)
int mess822_b64decode(stralloc *, const char *, int, int)
void c(char *, char *, char *, int, int, int)