diff options
author | rsc <devnull@localhost> | 2006-02-15 12:39:09 +0000 |
---|---|---|
committer | rsc <devnull@localhost> | 2006-02-15 12:39:09 +0000 |
commit | 941e17134e92de7f12977f1899860b57bbf83330 (patch) | |
tree | e0c7dc5b23b603b24c2ec0cb8d3544f91bb36101 /src/cmd/upas/nfs/decode.c | |
parent | 1ea614ffaf9378df45410995d0a8c13042bba123 (diff) | |
download | plan9port-941e17134e92de7f12977f1899860b57bbf83330.tar.gz plan9port-941e17134e92de7f12977f1899860b57bbf83330.tar.bz2 plan9port-941e17134e92de7f12977f1899860b57bbf83330.zip |
imap-based new upas/fs
Diffstat (limited to 'src/cmd/upas/nfs/decode.c')
-rw-r--r-- | src/cmd/upas/nfs/decode.c | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/src/cmd/upas/nfs/decode.c b/src/cmd/upas/nfs/decode.c new file mode 100644 index 00000000..0e46dbff --- /dev/null +++ b/src/cmd/upas/nfs/decode.c @@ -0,0 +1,257 @@ +/* Quick and dirty RFC 2047 */ + +#include "a.h" + +static int +unhex1(char c) +{ + if('0' <= c && c <= '9') + return c-'0'; + if('a' <= c && c <= 'f') + return c-'a'+10; + if('A' <= c && c <= 'F') + return c-'A'+10; + return 15; +} + +static int +unhex(char *s) +{ + return unhex1(s[0])*16+unhex1(s[1]); +} + +int +decqp(uchar *out, int lim, char *in, int n) +{ + char *p, *ep; + uchar *eout, *out0; + + out0 = out; + eout = out+lim; + for(p=in, ep=in+n; p<ep && out<eout; ){ + if(*p == '_'){ + *out++ = ' '; + p++; + } + else if(*p == '='){ + if(p+1 >= ep) + break; + if(*(p+1) == '\n'){ + p += 2; + continue; + } + if(p+3 > ep) + break; + *out++ = unhex(p+1); + p += 3; + }else + *out++ = *p++; + } + return out-out0; +} + +char* +decode(int kind, char *s, int *len) +{ + char *t; + int l; + + if(s == nil) + return s; + switch(kind){ + case QuotedPrintable: + l = strlen(s)+1; + t = emalloc(l); + l = decqp((uchar*)t, l, s, l-1); + *len = l; + t[l] = 0; + return t; + + case Base64: + l = strlen(s)+1; + t = emalloc(l); + l = dec64((uchar*)t, l, s, l-1); + *len = l; + t[l] = 0; + return t; + + default: + *len = strlen(s); + return estrdup(s); + } +} + +struct { + char *mime; + char *tcs; +} tcstab[] = { + "iso-8859-2", "8859-2", + "iso-8859-3", "8859-3", + "iso-8859-4", "8859-4", + "iso-8859-5", "8859-5", + "iso-8859-6", "8859-6", + "iso-8859-7", "8859-7", + "iso-8859-8", "8859-8", + "iso-8859-9", "8859-9", + "iso-8859-10", "8859-10", + "iso-8859-15", "8859-15", + "big5", "big5", + "iso-2022-jp", "jis-kanji", + "windows-1251", "cp1251", + "koi8-r", "koi8", +}; + +char* +tcs(char *charset, char *s) +{ + static char buf[4096]; + int i, n; + int fd[3], p[2], pp[2]; + uchar *us; + char *t, *u; + char *argv[4]; + Rune r; + + if(s == nil || charset == nil || *s == 0) + return s; + + if(cistrcmp(charset, "utf-8") == 0) + return s; + if(cistrcmp(charset, "iso-8859-1") == 0 || cistrcmp(charset, "us-ascii") == 0){ +latin1: + n = 0; + for(us=(uchar*)s; *us; us++) + n += runelen(*us); + n++; + t = emalloc(n); + for(us=(uchar*)s, u=t; *us; us++){ + r = *us; + u += runetochar(u, &r); + } + *u = 0; + free(s); + return t; + } + for(i=0; i<nelem(tcstab); i++) + if(cistrcmp(charset, tcstab[i].mime) == 0) + goto tcs; + goto latin1; + +tcs: + argv[0] = "tcs"; + argv[1] = "-f"; + argv[2] = charset; + argv[3] = nil; + + if(pipe(p) < 0 || pipe(pp) < 0) + sysfatal("pipe: %r"); + fd[0] = p[0]; + fd[1] = pp[0]; + fd[2] = dup(2, -1); + if(threadspawnl(fd, "tcs", "tcs", "-f", tcstab[i].tcs, nil) < 0){ + close(p[0]); + close(p[1]); + close(pp[0]); + close(pp[1]); + close(fd[2]); + goto latin1; + } + close(p[0]); + close(pp[0]); + write(p[1], s, strlen(s)); + close(p[1]); + n = readn(pp[1], buf, sizeof buf-1); + close(pp[1]); + if(n <= 0) + goto latin1; + free(s); + buf[n] = 0; + return estrdup(buf); +} + +char* +unrfc2047(char *s) +{ + char *p, *q, *t, *u, *v; + int len; + Rune r; + Fmt fmt; + + if(s == nil) + return nil; + + if(strstr(s, "=?") == nil) + return s; + + fmtstrinit(&fmt); + for(p=s; *p; ){ + /* =?charset?e?text?= */ + if(*p=='=' && *(p+1)=='?'){ + p += 2; + q = strchr(p, '?'); + if(q == nil) + goto emit; + q++; + if(*q == '?' || *(q+1) != '?') + goto emit; + t = q+2; + u = strchr(t, '?'); + if(u == nil || *(u+1) != '=') + goto emit; + switch(*q){ + case 'q': + case 'Q': + *u = 0; + v = decode(QuotedPrintable, t, &len); + break; + case 'b': + case 'B': + *u = 0; + v = decode(Base64, t, &len); + break; + default: + goto emit; + } + *(q-1) = 0; + v = tcs(p, v); + fmtstrcpy(&fmt, v); + free(v); + p = u+2; + } + emit: + p += chartorune(&r, p); + fmtrune(&fmt, r); + } + p = fmtstrflush(&fmt); + if(p == nil) + sysfatal("out of memory"); + free(s); + return p; +} + +#ifdef TEST +char *test[] = +{ + "hello world", + "hello =?iso-8859-1?q?this is some text?=", + "=?US-ASCII?Q?Keith_Moore?=", + "=?ISO-8859-1?Q?Keld_J=F8rn_Simonsen?=", + "=?ISO-8859-1?Q?Andr=E9?= Pirard", + "=?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?=", + "=?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?=", + "=?ISO-8859-1?Q?Olle_J=E4rnefors?=", + "=?iso-2022-jp?B?GyRCTTVKISRKP006SiRyS34kPyQ3JEZKcz03JCIkahsoQg==?=", + "=?UTF-8?B?Ik5pbHMgTy4gU2Vsw6VzZGFsIg==?=" +}; + +void +threadmain(int argc, char **argv) +{ + int i; + + for(i=0; i<nelem(test); i++) + print("%s\n\t%s\n", test[i], unrfc2047(estrdup(test[i]))); + threadexitsall(0); +} + +#endif |