| /* |
| * For decoding the files that get passed to validateattachment. |
| * NOT a general mime decoder. |
| */ |
| #include <u.h> |
| #include <libc.h> |
| #include <bio.h> |
| |
| enum { None, Base64, Quoted }; |
| static int decquoted(char *out, char *in, char *e); |
| |
| void |
| main(void) |
| { |
| Biobuf b, b1; |
| char *p, *encoding; |
| int e, len; |
| |
| Binit(&b, 0, OREAD); |
| Binit(&b1, 1, OWRITE); |
| |
| /* header */ |
| encoding = nil; |
| while((p = Brdstr(&b, '\n', 1)) != nil){ |
| if(p[0] == 0) |
| break; |
| if(cistrncmp(p, "Content-Transfer-Encoding: ", 27) == 0) |
| encoding = strdup(p+27); |
| free(p); |
| } |
| |
| e = None; |
| if(encoding == nil) |
| e = None; |
| else if(strcmp(encoding, "base64") == 0) |
| e = Base64; |
| else if(strcmp(encoding, "quoted-printable") == 0) |
| e = Quoted; |
| |
| while((p = Brdstr(&b, '\n', 0)) != nil){ |
| if(strncmp(p, "--", 2) == 0 && e != None) |
| break; |
| len = strlen(p); |
| switch(e){ |
| case None: |
| break; |
| case Base64: |
| len = dec64((uchar*)p, len, p, len); |
| break; |
| case Quoted: |
| len = decquoted(p, p, p+len); |
| break; |
| } |
| Bwrite(&b1, p, len); |
| free(p); |
| } |
| exits(0); |
| } |
| |
| /* |
| * decode quoted |
| */ |
| enum |
| { |
| Self= 1, |
| Hex= 2 |
| }; |
| uchar tableqp[256]; |
| |
| static void |
| initquoted(void) |
| { |
| int c; |
| |
| memset(tableqp, 0, 256); |
| for(c = ' '; c <= '<'; c++) |
| tableqp[c] = Self; |
| for(c = '>'; c <= '~'; c++) |
| tableqp[c] = Self; |
| tableqp['\t'] = Self; |
| tableqp['='] = Hex; |
| } |
| |
| static int |
| hex2int(int x) |
| { |
| if(x >= '0' && x <= '9') |
| return x - '0'; |
| if(x >= 'A' && x <= 'F') |
| return (x - 'A') + 10; |
| if(x >= 'a' && x <= 'f') |
| return (x - 'a') + 10; |
| return 0; |
| } |
| |
| static char* |
| decquotedline(char *out, char *in, char *e) |
| { |
| int c, soft; |
| |
| /* dump trailing white space */ |
| while(e >= in && (*e == ' ' || *e == '\t' || *e == '\r' || *e == '\n')) |
| e--; |
| |
| /* trailing '=' means no newline */ |
| if(*e == '='){ |
| soft = 1; |
| e--; |
| } else |
| soft = 0; |
| |
| while(in <= e){ |
| c = (*in++) & 0xff; |
| switch(tableqp[c]){ |
| case Self: |
| *out++ = c; |
| break; |
| case Hex: |
| c = hex2int(*in++)<<4; |
| c |= hex2int(*in++); |
| *out++ = c; |
| break; |
| } |
| } |
| if(!soft) |
| *out++ = '\n'; |
| *out = 0; |
| |
| return out; |
| } |
| |
| static int |
| decquoted(char *out, char *in, char *e) |
| { |
| char *p, *nl; |
| |
| if(tableqp[' '] == 0) |
| initquoted(); |
| |
| p = out; |
| while((nl = strchr(in, '\n')) != nil && nl < e){ |
| p = decquotedline(p, in, nl); |
| in = nl + 1; |
| } |
| if(in < e) |
| p = decquotedline(p, in, e-1); |
| |
| /* make sure we end with a new line */ |
| if(*(p-1) != '\n'){ |
| *p++ = '\n'; |
| *p = 0; |
| } |
| |
| return p - out; |
| } |
| |