17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
47dd7cddfSDavid du Colombier #include <libsec.h>
580ee5cbfSDavid du Colombier #include <auth.h>
680ee5cbfSDavid du Colombier #include <fcall.h>
77dd7cddfSDavid du Colombier #include "imap4d.h"
87dd7cddfSDavid du Colombier
97dd7cddfSDavid du Colombier static void body64(int in, int out);
1080ee5cbfSDavid du Colombier static void bodystrip(int in, int out);
117dd7cddfSDavid du Colombier static void cleanupHeader(Header *h);
127dd7cddfSDavid du Colombier static char *domBang(char *s);
137dd7cddfSDavid du Colombier static void freeMAddr(MAddr *a);
147dd7cddfSDavid du Colombier static void freeMimeHdr(MimeHdr *mh);
157dd7cddfSDavid du Colombier static char *headAddrSpec(char *e, char *w);
167dd7cddfSDavid du Colombier static MAddr *headAddresses(void);
177dd7cddfSDavid du Colombier static MAddr *headAddress(void);
187dd7cddfSDavid du Colombier static char *headAtom(char *disallowed);
197dd7cddfSDavid du Colombier static int headChar(int eat);
207dd7cddfSDavid du Colombier static char *headDomain(char *e);
217dd7cddfSDavid du Colombier static MAddr *headMAddr(MAddr *old);
227dd7cddfSDavid du Colombier static char *headPhrase(char *e, char *w);
237dd7cddfSDavid du Colombier static char *headQuoted(int start, int stop);
247dd7cddfSDavid du Colombier static char *headSkipWhite(int);
257dd7cddfSDavid du Colombier static void headSkip(void);
267dd7cddfSDavid du Colombier static char *headSubDomain(void);
277dd7cddfSDavid du Colombier static char *headText(void);
287dd7cddfSDavid du Colombier static void headToEnd(void);
297dd7cddfSDavid du Colombier static char *headWord(void);
307dd7cddfSDavid du Colombier static void mimeDescription(Header *h);
317dd7cddfSDavid du Colombier static void mimeDisposition(Header *h);
327dd7cddfSDavid du Colombier static void mimeEncoding(Header *h);
337dd7cddfSDavid du Colombier static void mimeId(Header *h);
347dd7cddfSDavid du Colombier static void mimeLanguage(Header *h);
357dd7cddfSDavid du Colombier static void mimeMd5(Header *h);
367dd7cddfSDavid du Colombier static MimeHdr *mimeParams(void);
377dd7cddfSDavid du Colombier static void mimeType(Header *h);
387dd7cddfSDavid du Colombier static MimeHdr *mkMimeHdr(char *s, char *t, MimeHdr *next);
397dd7cddfSDavid du Colombier static void msgAddDate(Msg *m);
407dd7cddfSDavid du Colombier static void msgAddHead(Msg *m, char *head, char *body);
417dd7cddfSDavid du Colombier static int msgBodySize(Msg *m);
427dd7cddfSDavid du Colombier static int msgHeader(Msg *m, Header *h, char *file);
437dd7cddfSDavid du Colombier static long msgReadFile(Msg *m, char *file, char **ss);
447dd7cddfSDavid du Colombier static int msgUnix(Msg *m, int top);
457dd7cddfSDavid du Colombier static void stripQuotes(char *q);
467dd7cddfSDavid du Colombier static MAddr *unixFrom(char *s);
477dd7cddfSDavid du Colombier
4880ee5cbfSDavid du Colombier
4980ee5cbfSDavid du Colombier static char bogusBody[] =
5080ee5cbfSDavid du Colombier "This message contains null characters, so it cannot be displayed correctly.\r\n"
5180ee5cbfSDavid du Colombier "Most likely you were sent a bogus message or a binary file.\r\n"
5280ee5cbfSDavid du Colombier "\r\n"
5380ee5cbfSDavid du Colombier "Each of the following attachments has a different version of the message.\r\n"
5480ee5cbfSDavid du Colombier "The first is inlined with all non-printable characters stripped.\r\n"
5580ee5cbfSDavid du Colombier "The second contains the message as it was stored in your mailbox.\r\n"
5680ee5cbfSDavid du Colombier "The third has the initial header stripped.\r\n";
5780ee5cbfSDavid du Colombier
5880ee5cbfSDavid du Colombier static char bogusMimeText[] =
5980ee5cbfSDavid du Colombier "Content-Disposition: inline\r\n"
6080ee5cbfSDavid du Colombier "Content-Type: text/plain; charset=\"US-ASCII\"\r\n"
6180ee5cbfSDavid du Colombier "Content-Transfer-Encoding: 7bit\r\n";
6280ee5cbfSDavid du Colombier
6380ee5cbfSDavid du Colombier static char bogusMimeBinary[] =
6480ee5cbfSDavid du Colombier "Content-Disposition: attachment\r\n"
6580ee5cbfSDavid du Colombier "Content-Type: application/octet-stream\r\n"
6680ee5cbfSDavid du Colombier "Content-Transfer-Encoding: base64\r\n";
6780ee5cbfSDavid du Colombier
687dd7cddfSDavid du Colombier /*
697dd7cddfSDavid du Colombier * stop list for header fields
707dd7cddfSDavid du Colombier */
717dd7cddfSDavid du Colombier static char *headFieldStop = ":";
727dd7cddfSDavid du Colombier static char *mimeTokenStop = "()<>@,;:\\\"/[]?=";
737dd7cddfSDavid du Colombier static char *headAtomStop = "()<>@,;:\\\".[]";
747dd7cddfSDavid du Colombier static uchar *headStr;
757dd7cddfSDavid du Colombier static uchar *lastWhite;
767dd7cddfSDavid du Colombier
777dd7cddfSDavid du Colombier long
selectFields(char * dst,long n,char * hdr,SList * fields,int matches)787dd7cddfSDavid du Colombier selectFields(char *dst, long n, char *hdr, SList *fields, int matches)
797dd7cddfSDavid du Colombier {
807dd7cddfSDavid du Colombier SList *f;
817dd7cddfSDavid du Colombier uchar *start;
827dd7cddfSDavid du Colombier char *s;
837dd7cddfSDavid du Colombier long m, nf;
847dd7cddfSDavid du Colombier
857dd7cddfSDavid du Colombier headStr = (uchar*)hdr;
867dd7cddfSDavid du Colombier m = 0;
877dd7cddfSDavid du Colombier for(;;){
887dd7cddfSDavid du Colombier start = headStr;
897dd7cddfSDavid du Colombier s = headAtom(headFieldStop);
907dd7cddfSDavid du Colombier if(s == nil)
917dd7cddfSDavid du Colombier break;
927dd7cddfSDavid du Colombier headSkip();
937dd7cddfSDavid du Colombier for(f = fields; f != nil; f = f->next){
947dd7cddfSDavid du Colombier if(cistrcmp(s, f->s) == !matches){
957dd7cddfSDavid du Colombier nf = headStr - start;
967dd7cddfSDavid du Colombier if(m + nf > n)
977dd7cddfSDavid du Colombier return 0;
987dd7cddfSDavid du Colombier memmove(&dst[m], start, nf);
997dd7cddfSDavid du Colombier m += nf;
1007dd7cddfSDavid du Colombier }
1017dd7cddfSDavid du Colombier }
1027dd7cddfSDavid du Colombier free(s);
1037dd7cddfSDavid du Colombier }
1047dd7cddfSDavid du Colombier if(m + 3 > n)
1057dd7cddfSDavid du Colombier return 0;
1067dd7cddfSDavid du Colombier dst[m++] = '\r';
1077dd7cddfSDavid du Colombier dst[m++] = '\n';
1087dd7cddfSDavid du Colombier dst[m] = '\0';
1097dd7cddfSDavid du Colombier return m;
1107dd7cddfSDavid du Colombier }
1117dd7cddfSDavid du Colombier
1127dd7cddfSDavid du Colombier void
freeMsg(Msg * m)1137dd7cddfSDavid du Colombier freeMsg(Msg *m)
1147dd7cddfSDavid du Colombier {
1157dd7cddfSDavid du Colombier Msg *k, *last;
1167dd7cddfSDavid du Colombier
1177dd7cddfSDavid du Colombier free(m->iBuf);
1187dd7cddfSDavid du Colombier freeMAddr(m->to);
1197dd7cddfSDavid du Colombier if(m->replyTo != m->from)
1207dd7cddfSDavid du Colombier freeMAddr(m->replyTo);
1217dd7cddfSDavid du Colombier if(m->sender != m->from)
1227dd7cddfSDavid du Colombier freeMAddr(m->sender);
1237dd7cddfSDavid du Colombier if(m->from != m->unixFrom)
1247dd7cddfSDavid du Colombier freeMAddr(m->from);
1257dd7cddfSDavid du Colombier freeMAddr(m->unixFrom);
1267dd7cddfSDavid du Colombier freeMAddr(m->cc);
1277dd7cddfSDavid du Colombier freeMAddr(m->bcc);
1287dd7cddfSDavid du Colombier free(m->unixDate);
1297dd7cddfSDavid du Colombier cleanupHeader(&m->head);
1307dd7cddfSDavid du Colombier cleanupHeader(&m->mime);
1317dd7cddfSDavid du Colombier for(k = m->kids; k != nil; ){
1327dd7cddfSDavid du Colombier last = k;
1337dd7cddfSDavid du Colombier k = k->next;
1347dd7cddfSDavid du Colombier freeMsg(last);
1357dd7cddfSDavid du Colombier }
1366852fd5aSDavid du Colombier free(m->fs);
1377dd7cddfSDavid du Colombier free(m);
1387dd7cddfSDavid du Colombier }
1397dd7cddfSDavid du Colombier
1407dd7cddfSDavid du Colombier ulong
msgSize(Msg * m)1417dd7cddfSDavid du Colombier msgSize(Msg *m)
1427dd7cddfSDavid du Colombier {
1437dd7cddfSDavid du Colombier return m->head.size + m->size;
1447dd7cddfSDavid du Colombier }
1457dd7cddfSDavid du Colombier
1467dd7cddfSDavid du Colombier int
infoIsNil(char * s)1477dd7cddfSDavid du Colombier infoIsNil(char *s)
1487dd7cddfSDavid du Colombier {
1497dd7cddfSDavid du Colombier return s == nil || s[0] == '\0';
1507dd7cddfSDavid du Colombier }
1517dd7cddfSDavid du Colombier
1527dd7cddfSDavid du Colombier char*
maddrStr(MAddr * a)1537dd7cddfSDavid du Colombier maddrStr(MAddr *a)
1547dd7cddfSDavid du Colombier {
1557dd7cddfSDavid du Colombier char *host, *addr;
1567dd7cddfSDavid du Colombier int n;
1577dd7cddfSDavid du Colombier
1587dd7cddfSDavid du Colombier host = a->host;
1597dd7cddfSDavid du Colombier if(host == nil)
1607dd7cddfSDavid du Colombier host = "";
1617dd7cddfSDavid du Colombier n = strlen(a->box) + strlen(host) + 2;
1627dd7cddfSDavid du Colombier if(a->personal != nil)
1637dd7cddfSDavid du Colombier n += strlen(a->personal) + 3;
1647dd7cddfSDavid du Colombier addr = emalloc(n);
1657dd7cddfSDavid du Colombier if(a->personal != nil)
1667dd7cddfSDavid du Colombier snprint(addr, n, "%s <%s@%s>", a->personal, a->box, host);
1677dd7cddfSDavid du Colombier else
1687dd7cddfSDavid du Colombier snprint(addr, n, "%s@%s", a->box, host);
1697dd7cddfSDavid du Colombier return addr;
1707dd7cddfSDavid du Colombier }
1717dd7cddfSDavid du Colombier
1727dd7cddfSDavid du Colombier /*
1737dd7cddfSDavid du Colombier * return actual name of f in m's fs directory
1747dd7cddfSDavid du Colombier * this is special cased when opening m/rawbody, m/mimeheader, or m/rawheader,
1757dd7cddfSDavid du Colombier * if the message was corrupted. in that case,
1767dd7cddfSDavid du Colombier * a temporary file is made to hold the base64 encoding of m/raw.
1777dd7cddfSDavid du Colombier */
1787dd7cddfSDavid du Colombier int
msgFile(Msg * m,char * f)1797dd7cddfSDavid du Colombier msgFile(Msg *m, char *f)
1807dd7cddfSDavid du Colombier {
18180ee5cbfSDavid du Colombier Msg *parent, *p;
18280ee5cbfSDavid du Colombier Dir d;
1837dd7cddfSDavid du Colombier Tm tm;
1849a747e4fSDavid du Colombier char buf[64], nbuf[2];
1859a747e4fSDavid du Colombier uchar dbuf[64];
18680ee5cbfSDavid du Colombier int i, n, fd, fd1, fd2;
1877dd7cddfSDavid du Colombier
1887dd7cddfSDavid du Colombier if(!m->bogus
18980ee5cbfSDavid du Colombier || strcmp(f, "") != 0 && strcmp(f, "rawbody") != 0
19080ee5cbfSDavid du Colombier && strcmp(f, "rawheader") != 0 && strcmp(f, "mimeheader") != 0
1913ff48bf5SDavid du Colombier && strcmp(f, "info") != 0 && strcmp(f, "unixheader") != 0){
1929a747e4fSDavid du Colombier if(strlen(f) > MsgNameLen)
1937dd7cddfSDavid du Colombier bye("internal error: msgFile name too long");
1947dd7cddfSDavid du Colombier strcpy(m->efs, f);
1957dd7cddfSDavid du Colombier return cdOpen(m->fsDir, m->fs, OREAD);
1967dd7cddfSDavid du Colombier }
19780ee5cbfSDavid du Colombier
19880ee5cbfSDavid du Colombier /*
19980ee5cbfSDavid du Colombier * walk up the stupid runt message parts for non-multipart messages
20080ee5cbfSDavid du Colombier */
20180ee5cbfSDavid du Colombier parent = m->parent;
20280ee5cbfSDavid du Colombier if(parent != nil && parent->parent != nil){
20380ee5cbfSDavid du Colombier m = parent;
20480ee5cbfSDavid du Colombier parent = m->parent;
20580ee5cbfSDavid du Colombier }
20680ee5cbfSDavid du Colombier p = m;
20780ee5cbfSDavid du Colombier if(parent != nil)
20880ee5cbfSDavid du Colombier p = parent;
20980ee5cbfSDavid du Colombier
2103ff48bf5SDavid du Colombier if(strcmp(f, "info") == 0 || strcmp(f, "unixheader") == 0){
21180ee5cbfSDavid du Colombier strcpy(p->efs, f);
21280ee5cbfSDavid du Colombier return cdOpen(p->fsDir, p->fs, OREAD);
21380ee5cbfSDavid du Colombier }
21480ee5cbfSDavid du Colombier
2157dd7cddfSDavid du Colombier fd = imapTmp();
2167dd7cddfSDavid du Colombier if(fd < 0)
2177dd7cddfSDavid du Colombier return -1;
21880ee5cbfSDavid du Colombier
21980ee5cbfSDavid du Colombier /*
22080ee5cbfSDavid du Colombier * craft the message parts for bogus messages
22180ee5cbfSDavid du Colombier */
22280ee5cbfSDavid du Colombier if(strcmp(f, "") == 0){
22380ee5cbfSDavid du Colombier /*
22480ee5cbfSDavid du Colombier * make a fake directory for each kid
22580ee5cbfSDavid du Colombier * all we care about is the name
22680ee5cbfSDavid du Colombier */
22780ee5cbfSDavid du Colombier if(parent == nil){
2289a747e4fSDavid du Colombier nulldir(&d);
2299a747e4fSDavid du Colombier d.mode = DMDIR|0600;
2309a747e4fSDavid du Colombier d.qid.type = QTDIR;
2319a747e4fSDavid du Colombier d.name = nbuf;
2329a747e4fSDavid du Colombier nbuf[1] = '\0';
23380ee5cbfSDavid du Colombier for(i = '1'; i <= '4'; i++){
2349a747e4fSDavid du Colombier nbuf[0] = i;
2359a747e4fSDavid du Colombier n = convD2M(&d, dbuf, sizeof(dbuf));
2369a747e4fSDavid du Colombier if(n <= BIT16SZ)
23780ee5cbfSDavid du Colombier fprint(2, "bad convD2M %d\n", n);
23880ee5cbfSDavid du Colombier write(fd, dbuf, n);
23980ee5cbfSDavid du Colombier }
24080ee5cbfSDavid du Colombier }
24180ee5cbfSDavid du Colombier }else if(strcmp(f, "mimeheader") == 0){
24280ee5cbfSDavid du Colombier if(parent != nil){
24380ee5cbfSDavid du Colombier switch(m->id){
24480ee5cbfSDavid du Colombier case 1:
24580ee5cbfSDavid du Colombier case 2:
24680ee5cbfSDavid du Colombier fprint(fd, "%s", bogusMimeText);
24780ee5cbfSDavid du Colombier break;
24880ee5cbfSDavid du Colombier case 3:
24980ee5cbfSDavid du Colombier case 4:
25080ee5cbfSDavid du Colombier fprint(fd, "%s", bogusMimeBinary);
25180ee5cbfSDavid du Colombier break;
25280ee5cbfSDavid du Colombier }
25380ee5cbfSDavid du Colombier }
25480ee5cbfSDavid du Colombier }else if(strcmp(f, "rawheader") == 0){
25580ee5cbfSDavid du Colombier if(parent == nil){
2567dd7cddfSDavid du Colombier date2tm(&tm, m->unixDate);
2577dd7cddfSDavid du Colombier rfc822date(buf, sizeof(buf), &tm);
25880ee5cbfSDavid du Colombier fprint(fd,
25980ee5cbfSDavid du Colombier "Date: %s\r\n"
26080ee5cbfSDavid du Colombier "From: imap4 daemon <%s@%s>\r\n"
26180ee5cbfSDavid du Colombier "To: <%s@%s>\r\n"
26280ee5cbfSDavid du Colombier "Subject: This message was illegal or corrupted\r\n"
26380ee5cbfSDavid du Colombier "MIME-Version: 1.0\r\n"
26480ee5cbfSDavid du Colombier "Content-Type: multipart/mixed;\r\n\tboundary=\"upas-%s\"\r\n",
26580ee5cbfSDavid du Colombier buf, username, site, username, site, m->info[IDigest]);
26680ee5cbfSDavid du Colombier }
26780ee5cbfSDavid du Colombier }else if(strcmp(f, "rawbody") == 0){
26880ee5cbfSDavid du Colombier fd1 = msgFile(p, "raw");
26980ee5cbfSDavid du Colombier strcpy(p->efs, "rawbody");
27080ee5cbfSDavid du Colombier fd2 = cdOpen(p->fsDir, p->fs, OREAD);
27180ee5cbfSDavid du Colombier if(fd1 < 0 || fd2 < 0){
2727dd7cddfSDavid du Colombier close(fd);
27380ee5cbfSDavid du Colombier close(fd1);
27480ee5cbfSDavid du Colombier close(fd2);
2757dd7cddfSDavid du Colombier return -1;
2767dd7cddfSDavid du Colombier }
27780ee5cbfSDavid du Colombier if(parent == nil){
27880ee5cbfSDavid du Colombier fprint(fd,
27980ee5cbfSDavid du Colombier "This is a multi-part message in MIME format.\r\n"
28080ee5cbfSDavid du Colombier "--upas-%s\r\n"
28180ee5cbfSDavid du Colombier "%s"
28280ee5cbfSDavid du Colombier "\r\n"
28380ee5cbfSDavid du Colombier "%s"
28480ee5cbfSDavid du Colombier "\r\n",
28580ee5cbfSDavid du Colombier m->info[IDigest], bogusMimeText, bogusBody);
28680ee5cbfSDavid du Colombier
28780ee5cbfSDavid du Colombier fprint(fd,
28880ee5cbfSDavid du Colombier "--upas-%s\r\n"
28980ee5cbfSDavid du Colombier "%s"
29080ee5cbfSDavid du Colombier "\r\n",
29180ee5cbfSDavid du Colombier m->info[IDigest], bogusMimeText);
29280ee5cbfSDavid du Colombier bodystrip(fd1, fd);
29380ee5cbfSDavid du Colombier
29480ee5cbfSDavid du Colombier fprint(fd,
29580ee5cbfSDavid du Colombier "--upas-%s\r\n"
29680ee5cbfSDavid du Colombier "%s"
29780ee5cbfSDavid du Colombier "\r\n",
29880ee5cbfSDavid du Colombier m->info[IDigest], bogusMimeBinary);
29980ee5cbfSDavid du Colombier seek(fd1, 0, 0);
3007dd7cddfSDavid du Colombier body64(fd1, fd);
30180ee5cbfSDavid du Colombier
30280ee5cbfSDavid du Colombier fprint(fd,
30380ee5cbfSDavid du Colombier "--upas-%s\r\n"
30480ee5cbfSDavid du Colombier "%s"
30580ee5cbfSDavid du Colombier "\r\n",
30680ee5cbfSDavid du Colombier m->info[IDigest], bogusMimeBinary);
30780ee5cbfSDavid du Colombier body64(fd2, fd);
30880ee5cbfSDavid du Colombier
30980ee5cbfSDavid du Colombier fprint(fd, "--upas-%s--\r\n", m->info[IDigest]);
31080ee5cbfSDavid du Colombier }else{
31180ee5cbfSDavid du Colombier switch(m->id){
31280ee5cbfSDavid du Colombier case 1:
31380ee5cbfSDavid du Colombier fprint(fd, "%s", bogusBody);
31480ee5cbfSDavid du Colombier break;
31580ee5cbfSDavid du Colombier case 2:
31680ee5cbfSDavid du Colombier bodystrip(fd1, fd);
31780ee5cbfSDavid du Colombier break;
31880ee5cbfSDavid du Colombier case 3:
31980ee5cbfSDavid du Colombier body64(fd1, fd);
32080ee5cbfSDavid du Colombier break;
32180ee5cbfSDavid du Colombier case 4:
32280ee5cbfSDavid du Colombier body64(fd2, fd);
32380ee5cbfSDavid du Colombier break;
32480ee5cbfSDavid du Colombier }
32580ee5cbfSDavid du Colombier }
3267dd7cddfSDavid du Colombier close(fd1);
32780ee5cbfSDavid du Colombier close(fd2);
3287dd7cddfSDavid du Colombier }
3297dd7cddfSDavid du Colombier seek(fd, 0, 0);
3307dd7cddfSDavid du Colombier return fd;
3317dd7cddfSDavid du Colombier }
3327dd7cddfSDavid du Colombier
3337dd7cddfSDavid du Colombier int
msgIsMulti(Header * h)3347dd7cddfSDavid du Colombier msgIsMulti(Header *h)
3357dd7cddfSDavid du Colombier {
3367dd7cddfSDavid du Colombier return h->type != nil && cistrcmp("multipart", h->type->s) == 0;
3377dd7cddfSDavid du Colombier }
3387dd7cddfSDavid du Colombier
3397dd7cddfSDavid du Colombier int
msgIsRfc822(Header * h)3407dd7cddfSDavid du Colombier msgIsRfc822(Header *h)
3417dd7cddfSDavid du Colombier {
3427dd7cddfSDavid du Colombier return h->type != nil && cistrcmp("message", h->type->s) == 0 && cistrcmp("rfc822", h->type->t) == 0;
3437dd7cddfSDavid du Colombier }
3447dd7cddfSDavid du Colombier
3457dd7cddfSDavid du Colombier /*
3467dd7cddfSDavid du Colombier * check if a message has been deleted by someone else
3477dd7cddfSDavid du Colombier */
3487dd7cddfSDavid du Colombier void
msgDead(Msg * m)3497dd7cddfSDavid du Colombier msgDead(Msg *m)
3507dd7cddfSDavid du Colombier {
3517dd7cddfSDavid du Colombier if(m->expunged)
3527dd7cddfSDavid du Colombier return;
3537dd7cddfSDavid du Colombier *m->efs = '\0';
3549a747e4fSDavid du Colombier if(!cdExists(m->fsDir, m->fs))
3557dd7cddfSDavid du Colombier m->expunged = 1;
3567dd7cddfSDavid du Colombier }
3577dd7cddfSDavid du Colombier
3587dd7cddfSDavid du Colombier /*
3597dd7cddfSDavid du Colombier * make sure the message has valid associated info
3607dd7cddfSDavid du Colombier * used for ISubject, IDigest, IInReplyTo, IMessageId.
3617dd7cddfSDavid du Colombier */
3627dd7cddfSDavid du Colombier int
msgInfo(Msg * m)3637dd7cddfSDavid du Colombier msgInfo(Msg *m)
3647dd7cddfSDavid du Colombier {
3657dd7cddfSDavid du Colombier char *s;
3667dd7cddfSDavid du Colombier int i;
3677dd7cddfSDavid du Colombier
3687dd7cddfSDavid du Colombier if(m->info[0] != nil)
3697dd7cddfSDavid du Colombier return 1;
3707dd7cddfSDavid du Colombier
3717dd7cddfSDavid du Colombier i = msgReadFile(m, "info", &m->iBuf);
3727dd7cddfSDavid du Colombier if(i < 0)
3737dd7cddfSDavid du Colombier return 0;
3747dd7cddfSDavid du Colombier
3757dd7cddfSDavid du Colombier s = m->iBuf;
3767dd7cddfSDavid du Colombier for(i = 0; i < IMax; i++){
3777dd7cddfSDavid du Colombier m->info[i] = s;
3787dd7cddfSDavid du Colombier s = strchr(s, '\n');
3797dd7cddfSDavid du Colombier if(s == nil)
3807dd7cddfSDavid du Colombier break;
3817dd7cddfSDavid du Colombier *s++ = '\0';
3827dd7cddfSDavid du Colombier }
3837dd7cddfSDavid du Colombier for(; i < IMax; i++)
3847dd7cddfSDavid du Colombier m->info[i] = nil;
3857dd7cddfSDavid du Colombier
3867dd7cddfSDavid du Colombier for(i = 0; i < IMax; i++)
3877dd7cddfSDavid du Colombier if(infoIsNil(m->info[i]))
3887dd7cddfSDavid du Colombier m->info[i] = nil;
3897dd7cddfSDavid du Colombier
3907dd7cddfSDavid du Colombier return 1;
3917dd7cddfSDavid du Colombier }
3927dd7cddfSDavid du Colombier
3937dd7cddfSDavid du Colombier /*
3947dd7cddfSDavid du Colombier * make sure the message has valid mime structure
3957dd7cddfSDavid du Colombier * and sub-messages
3967dd7cddfSDavid du Colombier */
3977dd7cddfSDavid du Colombier int
msgStruct(Msg * m,int top)3987dd7cddfSDavid du Colombier msgStruct(Msg *m, int top)
3997dd7cddfSDavid du Colombier {
4007dd7cddfSDavid du Colombier Msg *k, head, *last;
4019a747e4fSDavid du Colombier Dir *d;
4027dd7cddfSDavid du Colombier char *s;
4037dd7cddfSDavid du Colombier ulong max, id;
4047dd7cddfSDavid du Colombier int i, nd, fd, ns;
4057dd7cddfSDavid du Colombier
4067dd7cddfSDavid du Colombier if(m->kids != nil)
4077dd7cddfSDavid du Colombier return 1;
4087dd7cddfSDavid du Colombier
4097dd7cddfSDavid du Colombier if(m->expunged
4107dd7cddfSDavid du Colombier || !msgInfo(m)
4117dd7cddfSDavid du Colombier || !msgUnix(m, top)
4127dd7cddfSDavid du Colombier || !msgBodySize(m)
4137dd7cddfSDavid du Colombier || !msgHeader(m, &m->mime, "mimeheader")
4149a747e4fSDavid du Colombier || (top || msgIsRfc822(&m->mime) || msgIsMulti(&m->mime)) && !msgHeader(m, &m->head, "rawheader")){
41580ee5cbfSDavid du Colombier if(top && m->bogus && !(m->bogus & BogusTried)){
41680ee5cbfSDavid du Colombier m->bogus |= BogusTried;
4177dd7cddfSDavid du Colombier return msgStruct(m, top);
4187dd7cddfSDavid du Colombier }
4197dd7cddfSDavid du Colombier msgDead(m);
4207dd7cddfSDavid du Colombier return 0;
4217dd7cddfSDavid du Colombier }
4227dd7cddfSDavid du Colombier
4237dd7cddfSDavid du Colombier /*
4247dd7cddfSDavid du Colombier * if a message has no kids, it has a kid which is just the body of the real message
4257dd7cddfSDavid du Colombier */
4269a747e4fSDavid du Colombier if(!msgIsMulti(&m->head) && !msgIsMulti(&m->mime) && !msgIsRfc822(&m->head) && !msgIsRfc822(&m->mime)){
4277dd7cddfSDavid du Colombier k = MKZ(Msg);
4287dd7cddfSDavid du Colombier k->id = 1;
4297dd7cddfSDavid du Colombier k->fsDir = m->fsDir;
43080ee5cbfSDavid du Colombier k->bogus = m->bogus;
43180ee5cbfSDavid du Colombier k->parent = m->parent;
4327dd7cddfSDavid du Colombier ns = m->efs - m->fs;
4339a747e4fSDavid du Colombier k->fs = emalloc(ns + (MsgNameLen + 1));
4347dd7cddfSDavid du Colombier memmove(k->fs, m->fs, ns);
4357dd7cddfSDavid du Colombier k->efs = k->fs + ns;
4367dd7cddfSDavid du Colombier *k->efs = '\0';
4377dd7cddfSDavid du Colombier k->size = m->size;
4387dd7cddfSDavid du Colombier m->kids = k;
4397dd7cddfSDavid du Colombier return 1;
4407dd7cddfSDavid du Colombier }
4417dd7cddfSDavid du Colombier
4427dd7cddfSDavid du Colombier /*
4437dd7cddfSDavid du Colombier * read in all child messages messages
4447dd7cddfSDavid du Colombier */
4457dd7cddfSDavid du Colombier fd = msgFile(m, "");
4467dd7cddfSDavid du Colombier if(fd < 0){
4477dd7cddfSDavid du Colombier msgDead(m);
4487dd7cddfSDavid du Colombier return 0;
4497dd7cddfSDavid du Colombier }
4507dd7cddfSDavid du Colombier
4517dd7cddfSDavid du Colombier max = 0;
4527dd7cddfSDavid du Colombier head.next = nil;
4537dd7cddfSDavid du Colombier last = &head;
4549a747e4fSDavid du Colombier while((nd = dirread(fd, &d)) > 0){
4557dd7cddfSDavid du Colombier for(i = 0; i < nd; i++){
4567dd7cddfSDavid du Colombier s = d[i].name;
4577dd7cddfSDavid du Colombier id = strtol(s, &s, 10);
4587dd7cddfSDavid du Colombier if(id <= max || *s != '\0'
4599a747e4fSDavid du Colombier || (d[i].mode & DMDIR) != DMDIR)
4607dd7cddfSDavid du Colombier continue;
4617dd7cddfSDavid du Colombier
4627dd7cddfSDavid du Colombier max = id;
4637dd7cddfSDavid du Colombier
4647dd7cddfSDavid du Colombier k = MKZ(Msg);
4657dd7cddfSDavid du Colombier k->id = id;
4667dd7cddfSDavid du Colombier k->fsDir = m->fsDir;
46780ee5cbfSDavid du Colombier k->bogus = m->bogus;
46880ee5cbfSDavid du Colombier k->parent = m;
4699a747e4fSDavid du Colombier ns = strlen(m->fs);
4709a747e4fSDavid du Colombier k->fs = emalloc(ns + 2 * (MsgNameLen + 1));
4719a747e4fSDavid du Colombier k->efs = seprint(k->fs, k->fs + ns + (MsgNameLen + 1), "%s%lud/", m->fs, id);
4727dd7cddfSDavid du Colombier k->prev = last;
4737dd7cddfSDavid du Colombier k->size = ~0UL;
4747dd7cddfSDavid du Colombier k->lines = ~0UL;
4757dd7cddfSDavid du Colombier last->next = k;
4767dd7cddfSDavid du Colombier last = k;
4777dd7cddfSDavid du Colombier }
4787dd7cddfSDavid du Colombier }
4797dd7cddfSDavid du Colombier close(fd);
4807dd7cddfSDavid du Colombier m->kids = head.next;
4817dd7cddfSDavid du Colombier
4827dd7cddfSDavid du Colombier /*
4839a747e4fSDavid du Colombier * if kids fail, just whack them
4847dd7cddfSDavid du Colombier */
4859a747e4fSDavid du Colombier top = top && (msgIsRfc822(&m->head) || msgIsMulti(&m->head));
4867dd7cddfSDavid du Colombier for(k = m->kids; k != nil; k = k->next){
4877dd7cddfSDavid du Colombier if(!msgStruct(k, top)){
4887dd7cddfSDavid du Colombier for(k = m->kids; k != nil; ){
4897dd7cddfSDavid du Colombier last = k;
4907dd7cddfSDavid du Colombier k = k->next;
4917dd7cddfSDavid du Colombier freeMsg(last);
4927dd7cddfSDavid du Colombier }
4937dd7cddfSDavid du Colombier m->kids = nil;
4947dd7cddfSDavid du Colombier break;
4957dd7cddfSDavid du Colombier }
4967dd7cddfSDavid du Colombier }
4977dd7cddfSDavid du Colombier return 1;
4987dd7cddfSDavid du Colombier }
4997dd7cddfSDavid du Colombier
5007dd7cddfSDavid du Colombier static long
msgReadFile(Msg * m,char * file,char ** ss)5017dd7cddfSDavid du Colombier msgReadFile(Msg *m, char *file, char **ss)
5027dd7cddfSDavid du Colombier {
5039a747e4fSDavid du Colombier Dir *d;
5047dd7cddfSDavid du Colombier char *s, buf[BufSize];
5059a747e4fSDavid du Colombier vlong length;
5067dd7cddfSDavid du Colombier long n, nn;
5077dd7cddfSDavid du Colombier int fd;
5087dd7cddfSDavid du Colombier
5097dd7cddfSDavid du Colombier fd = msgFile(m, file);
5107dd7cddfSDavid du Colombier if(fd < 0){
5117dd7cddfSDavid du Colombier msgDead(m);
5129a747e4fSDavid du Colombier return -1;
5137dd7cddfSDavid du Colombier }
5147dd7cddfSDavid du Colombier
5157dd7cddfSDavid du Colombier n = read(fd, buf, BufSize);
5167dd7cddfSDavid du Colombier if(n < BufSize){
5177dd7cddfSDavid du Colombier close(fd);
5187dd7cddfSDavid du Colombier if(n < 0){
5197dd7cddfSDavid du Colombier *ss = nil;
5207dd7cddfSDavid du Colombier return -1;
5217dd7cddfSDavid du Colombier }
5227dd7cddfSDavid du Colombier s = emalloc(n + 1);
5237dd7cddfSDavid du Colombier memmove(s, buf, n);
5247dd7cddfSDavid du Colombier s[n] = '\0';
5257dd7cddfSDavid du Colombier *ss = s;
5267dd7cddfSDavid du Colombier return n;
5277dd7cddfSDavid du Colombier }
5287dd7cddfSDavid du Colombier
5299a747e4fSDavid du Colombier d = dirfstat(fd);
5309a747e4fSDavid du Colombier if(d == nil){
5317dd7cddfSDavid du Colombier close(fd);
5329a747e4fSDavid du Colombier return -1;
5337dd7cddfSDavid du Colombier }
5349a747e4fSDavid du Colombier length = d->length;
5359a747e4fSDavid du Colombier free(d);
5369a747e4fSDavid du Colombier nn = length;
5377dd7cddfSDavid du Colombier s = emalloc(nn + 1);
5387dd7cddfSDavid du Colombier memmove(s, buf, n);
5397dd7cddfSDavid du Colombier if(nn > n)
5409a747e4fSDavid du Colombier nn = readn(fd, s+n, nn-n) + n;
5417dd7cddfSDavid du Colombier close(fd);
5429a747e4fSDavid du Colombier if(nn != length){
5437dd7cddfSDavid du Colombier free(s);
5449a747e4fSDavid du Colombier return -1;
5457dd7cddfSDavid du Colombier }
5467dd7cddfSDavid du Colombier s[nn] = '\0';
5477dd7cddfSDavid du Colombier *ss = s;
5487dd7cddfSDavid du Colombier return nn;
5497dd7cddfSDavid du Colombier }
5507dd7cddfSDavid du Colombier
5517dd7cddfSDavid du Colombier static void
freeMAddr(MAddr * a)5527dd7cddfSDavid du Colombier freeMAddr(MAddr *a)
5537dd7cddfSDavid du Colombier {
5547dd7cddfSDavid du Colombier MAddr *p;
5557dd7cddfSDavid du Colombier
5567dd7cddfSDavid du Colombier while(a != nil){
5577dd7cddfSDavid du Colombier p = a;
5587dd7cddfSDavid du Colombier a = a->next;
5597dd7cddfSDavid du Colombier free(p->personal);
5607dd7cddfSDavid du Colombier free(p->box);
5617dd7cddfSDavid du Colombier free(p->host);
5627dd7cddfSDavid du Colombier free(p);
5637dd7cddfSDavid du Colombier }
5647dd7cddfSDavid du Colombier }
5657dd7cddfSDavid du Colombier
5667dd7cddfSDavid du Colombier /*
5677dd7cddfSDavid du Colombier * the message is corrupted or illegal.
5687dd7cddfSDavid du Colombier * reset message fields. msgStruct will reparse the message,
5697dd7cddfSDavid du Colombier * relying on msgFile to make up corrected body parts.
5707dd7cddfSDavid du Colombier */
5717dd7cddfSDavid du Colombier static int
msgBogus(Msg * m,int flags)57280ee5cbfSDavid du Colombier msgBogus(Msg *m, int flags)
5737dd7cddfSDavid du Colombier {
57480ee5cbfSDavid du Colombier if(!(m->bogus & flags))
57580ee5cbfSDavid du Colombier m->bogus |= flags;
5767dd7cddfSDavid du Colombier m->lines = ~0;
5777dd7cddfSDavid du Colombier free(m->head.buf);
5787dd7cddfSDavid du Colombier free(m->mime.buf);
5797dd7cddfSDavid du Colombier memset(&m->head, 0, sizeof(Header));
5807dd7cddfSDavid du Colombier memset(&m->mime, 0, sizeof(Header));
5817dd7cddfSDavid du Colombier return 0;
5827dd7cddfSDavid du Colombier }
5837dd7cddfSDavid du Colombier
58480ee5cbfSDavid du Colombier /*
5859a747e4fSDavid du Colombier * stolen from upas/marshal; base64 encodes from one fd to another.
58680ee5cbfSDavid du Colombier *
58780ee5cbfSDavid du Colombier * the size of buf is very important to enc64. Anything other than
58880ee5cbfSDavid du Colombier * a multiple of 3 will cause enc64 to output a termination sequence.
58980ee5cbfSDavid du Colombier * To ensure that a full buf corresponds to a multiple of complete lines,
59080ee5cbfSDavid du Colombier * we make buf a multiple of 3*18 since that's how many enc64 sticks on
59180ee5cbfSDavid du Colombier * a single line. This avoids short lines in the output which is pleasing
59280ee5cbfSDavid du Colombier * but not necessary.
59380ee5cbfSDavid du Colombier */
5947dd7cddfSDavid du Colombier static int
enc64x18(char * out,int lim,uchar * in,int n)5957dd7cddfSDavid du Colombier enc64x18(char *out, int lim, uchar *in, int n)
5967dd7cddfSDavid du Colombier {
5977dd7cddfSDavid du Colombier int m, mm, nn;
5987dd7cddfSDavid du Colombier
5997dd7cddfSDavid du Colombier nn = 0;
6007dd7cddfSDavid du Colombier for(; n > 0; n -= m){
6017dd7cddfSDavid du Colombier m = 18 * 3;
6027dd7cddfSDavid du Colombier if(m > n)
6037dd7cddfSDavid du Colombier m = n;
6047dd7cddfSDavid du Colombier mm = enc64(out, lim - nn, in, m);
6057dd7cddfSDavid du Colombier in += m;
6067dd7cddfSDavid du Colombier out += mm;
6077dd7cddfSDavid du Colombier *out++ = '\r';
6087dd7cddfSDavid du Colombier *out++ = '\n';
6097dd7cddfSDavid du Colombier nn += mm + 2;
6107dd7cddfSDavid du Colombier }
6117dd7cddfSDavid du Colombier return nn;
6127dd7cddfSDavid du Colombier }
6137dd7cddfSDavid du Colombier
6147dd7cddfSDavid du Colombier static void
body64(int in,int out)6157dd7cddfSDavid du Colombier body64(int in, int out)
6167dd7cddfSDavid du Colombier {
6177dd7cddfSDavid du Colombier uchar buf[3*18*54];
6187dd7cddfSDavid du Colombier char obuf[3*18*54*2];
6197dd7cddfSDavid du Colombier int m, n;
6207dd7cddfSDavid du Colombier
6217dd7cddfSDavid du Colombier for(;;){
6227dd7cddfSDavid du Colombier n = read(in, buf, sizeof(buf));
6237dd7cddfSDavid du Colombier if(n < 0)
6247dd7cddfSDavid du Colombier return;
6257dd7cddfSDavid du Colombier if(n == 0)
6267dd7cddfSDavid du Colombier break;
6277dd7cddfSDavid du Colombier m = enc64x18(obuf, sizeof(obuf), buf, n);
6287dd7cddfSDavid du Colombier if(write(out, obuf, m) < 0)
6297dd7cddfSDavid du Colombier return;
6307dd7cddfSDavid du Colombier }
6317dd7cddfSDavid du Colombier }
6327dd7cddfSDavid du Colombier
6337dd7cddfSDavid du Colombier /*
63480ee5cbfSDavid du Colombier * strip all non-printable characters from a file
63580ee5cbfSDavid du Colombier */
63680ee5cbfSDavid du Colombier static void
bodystrip(int in,int out)63780ee5cbfSDavid du Colombier bodystrip(int in, int out)
63880ee5cbfSDavid du Colombier {
63980ee5cbfSDavid du Colombier uchar buf[3*18*54];
64080ee5cbfSDavid du Colombier int m, n, i, c;
64180ee5cbfSDavid du Colombier
64280ee5cbfSDavid du Colombier for(;;){
64380ee5cbfSDavid du Colombier n = read(in, buf, sizeof(buf));
64480ee5cbfSDavid du Colombier if(n < 0)
64580ee5cbfSDavid du Colombier return;
64680ee5cbfSDavid du Colombier if(n == 0)
64780ee5cbfSDavid du Colombier break;
64880ee5cbfSDavid du Colombier m = 0;
64980ee5cbfSDavid du Colombier for(i = 0; i < n; i++){
65080ee5cbfSDavid du Colombier c = buf[i];
65180ee5cbfSDavid du Colombier if(c > 0x1f && c < 0x7f /* normal characters */
65280ee5cbfSDavid du Colombier || c >= 0x9 && c <= 0xd) /* \t, \n, vertical tab, form feed, \r */
65380ee5cbfSDavid du Colombier buf[m++] = c;
65480ee5cbfSDavid du Colombier }
65580ee5cbfSDavid du Colombier
65680ee5cbfSDavid du Colombier if(m && write(out, buf, m) < 0)
65780ee5cbfSDavid du Colombier return;
65880ee5cbfSDavid du Colombier }
65980ee5cbfSDavid du Colombier }
66080ee5cbfSDavid du Colombier
66180ee5cbfSDavid du Colombier /*
6629a747e4fSDavid du Colombier * read in the message body to count \n without a preceding \r
6637dd7cddfSDavid du Colombier */
6647dd7cddfSDavid du Colombier static int
msgBodySize(Msg * m)6657dd7cddfSDavid du Colombier msgBodySize(Msg *m)
6667dd7cddfSDavid du Colombier {
6679a747e4fSDavid du Colombier Dir *d;
6687dd7cddfSDavid du Colombier char buf[BufSize + 2], *s, *se;
6699a747e4fSDavid du Colombier vlong length;
6707dd7cddfSDavid du Colombier ulong size, lines, bad;
6717dd7cddfSDavid du Colombier int n, fd, c;
6727dd7cddfSDavid du Colombier
6737dd7cddfSDavid du Colombier if(m->lines != ~0UL)
6747dd7cddfSDavid du Colombier return 1;
6757dd7cddfSDavid du Colombier fd = msgFile(m, "rawbody");
6767dd7cddfSDavid du Colombier if(fd < 0)
6777dd7cddfSDavid du Colombier return 0;
6789a747e4fSDavid du Colombier d = dirfstat(fd);
6799a747e4fSDavid du Colombier if(d == nil){
6807dd7cddfSDavid du Colombier close(fd);
6817dd7cddfSDavid du Colombier return 0;
6827dd7cddfSDavid du Colombier }
6839a747e4fSDavid du Colombier length = d->length;
6849a747e4fSDavid du Colombier free(d);
6857dd7cddfSDavid du Colombier
6867dd7cddfSDavid du Colombier size = 0;
6877dd7cddfSDavid du Colombier lines = 0;
6887dd7cddfSDavid du Colombier bad = 0;
6897dd7cddfSDavid du Colombier buf[0] = ' ';
6907dd7cddfSDavid du Colombier for(;;){
6917dd7cddfSDavid du Colombier n = read(fd, &buf[1], BufSize);
6927dd7cddfSDavid du Colombier if(n <= 0)
6937dd7cddfSDavid du Colombier break;
6947dd7cddfSDavid du Colombier size += n;
6957dd7cddfSDavid du Colombier se = &buf[n + 1];
6967dd7cddfSDavid du Colombier for(s = &buf[1]; s < se; s++){
6977dd7cddfSDavid du Colombier c = *s;
6987dd7cddfSDavid du Colombier if(c == '\0'){
6997dd7cddfSDavid du Colombier close(fd);
70080ee5cbfSDavid du Colombier return msgBogus(m, BogusBody);
7017dd7cddfSDavid du Colombier }
7027dd7cddfSDavid du Colombier if(c != '\n')
7037dd7cddfSDavid du Colombier continue;
7047dd7cddfSDavid du Colombier if(s[-1] != '\r')
7057dd7cddfSDavid du Colombier bad++;
7067dd7cddfSDavid du Colombier lines++;
7077dd7cddfSDavid du Colombier }
7087dd7cddfSDavid du Colombier buf[0] = buf[n];
7097dd7cddfSDavid du Colombier }
7109a747e4fSDavid du Colombier if(size != length)
7117dd7cddfSDavid du Colombier bye("bad length reading rawbody");
7127dd7cddfSDavid du Colombier size += bad;
7137dd7cddfSDavid du Colombier m->size = size;
7147dd7cddfSDavid du Colombier m->lines = lines;
7157dd7cddfSDavid du Colombier close(fd);
7167dd7cddfSDavid du Colombier return 1;
7177dd7cddfSDavid du Colombier }
7187dd7cddfSDavid du Colombier
7197dd7cddfSDavid du Colombier /*
7207dd7cddfSDavid du Colombier * retrieve information from the unixheader file
7217dd7cddfSDavid du Colombier */
7227dd7cddfSDavid du Colombier static int
msgUnix(Msg * m,int top)7237dd7cddfSDavid du Colombier msgUnix(Msg *m, int top)
7247dd7cddfSDavid du Colombier {
7257dd7cddfSDavid du Colombier Tm tm;
7267dd7cddfSDavid du Colombier char *s, *ss;
7277dd7cddfSDavid du Colombier
7287dd7cddfSDavid du Colombier if(m->unixDate != nil)
7297dd7cddfSDavid du Colombier return 1;
7307dd7cddfSDavid du Colombier
7317dd7cddfSDavid du Colombier if(!top){
732dc5a79c1SDavid du Colombier bogus:
7337dd7cddfSDavid du Colombier m->unixDate = estrdup("");
7347dd7cddfSDavid du Colombier m->unixFrom = unixFrom(nil);
7357dd7cddfSDavid du Colombier return 1;
7367dd7cddfSDavid du Colombier }
7377dd7cddfSDavid du Colombier
7387dd7cddfSDavid du Colombier if(msgReadFile(m, "unixheader", &ss) < 0)
7397dd7cddfSDavid du Colombier return 0;
7407dd7cddfSDavid du Colombier s = ss;
7417dd7cddfSDavid du Colombier s = strchr(s, ' ');
7427dd7cddfSDavid du Colombier if(s == nil){
7437dd7cddfSDavid du Colombier free(ss);
744dc5a79c1SDavid du Colombier goto bogus;
7457dd7cddfSDavid du Colombier }
7467dd7cddfSDavid du Colombier s++;
7477dd7cddfSDavid du Colombier m->unixFrom = unixFrom(s);
7487dd7cddfSDavid du Colombier s = (char*)headStr;
7497dd7cddfSDavid du Colombier if(date2tm(&tm, s) == nil)
7507dd7cddfSDavid du Colombier s = m->info[IUnixDate];
7515e91980fSDavid du Colombier if(s == nil){
7525e91980fSDavid du Colombier free(ss);
7535e91980fSDavid du Colombier goto bogus;
7545e91980fSDavid du Colombier }
7557dd7cddfSDavid du Colombier m->unixDate = estrdup(s);
7567dd7cddfSDavid du Colombier free(ss);
7577dd7cddfSDavid du Colombier return 1;
7587dd7cddfSDavid du Colombier }
7597dd7cddfSDavid du Colombier
7607dd7cddfSDavid du Colombier /*
7617dd7cddfSDavid du Colombier * parse the address in the unix header
7627dd7cddfSDavid du Colombier * last line of defence, so must return something
7637dd7cddfSDavid du Colombier */
7647dd7cddfSDavid du Colombier static MAddr *
unixFrom(char * s)7657dd7cddfSDavid du Colombier unixFrom(char *s)
7667dd7cddfSDavid du Colombier {
7677dd7cddfSDavid du Colombier MAddr *a;
7687dd7cddfSDavid du Colombier char *e, *t;
7697dd7cddfSDavid du Colombier
7707dd7cddfSDavid du Colombier if(s == nil)
771dc5a79c1SDavid du Colombier return nil;
7727dd7cddfSDavid du Colombier headStr = (uchar*)s;
7737dd7cddfSDavid du Colombier t = emalloc(strlen(s) + 2);
7747dd7cddfSDavid du Colombier e = headAddrSpec(t, nil);
7757dd7cddfSDavid du Colombier if(e == nil)
776dc5a79c1SDavid du Colombier a = nil;
7777dd7cddfSDavid du Colombier else{
7787dd7cddfSDavid du Colombier if(*e != '\0')
7797dd7cddfSDavid du Colombier *e++ = '\0';
7807dd7cddfSDavid du Colombier else
7817dd7cddfSDavid du Colombier e = site;
7827dd7cddfSDavid du Colombier a = MKZ(MAddr);
7837dd7cddfSDavid du Colombier
7847dd7cddfSDavid du Colombier a->box = estrdup(t);
7857dd7cddfSDavid du Colombier a->host = estrdup(e);
7867dd7cddfSDavid du Colombier }
7877dd7cddfSDavid du Colombier free(t);
7887dd7cddfSDavid du Colombier return a;
7897dd7cddfSDavid du Colombier }
7907dd7cddfSDavid du Colombier
7917dd7cddfSDavid du Colombier /*
7927dd7cddfSDavid du Colombier * read in the entire header,
7937dd7cddfSDavid du Colombier * and parse out any existing mime headers
7947dd7cddfSDavid du Colombier */
7957dd7cddfSDavid du Colombier static int
msgHeader(Msg * m,Header * h,char * file)7967dd7cddfSDavid du Colombier msgHeader(Msg *m, Header *h, char *file)
7977dd7cddfSDavid du Colombier {
7987dd7cddfSDavid du Colombier char *s, *ss, *t, *te;
7997dd7cddfSDavid du Colombier ulong lines, n, nn;
8007dd7cddfSDavid du Colombier long ns;
8017dd7cddfSDavid du Colombier int dated, c;
8027dd7cddfSDavid du Colombier
8037dd7cddfSDavid du Colombier if(h->buf != nil)
8047dd7cddfSDavid du Colombier return 1;
8057dd7cddfSDavid du Colombier
8067dd7cddfSDavid du Colombier ns = msgReadFile(m, file, &ss);
8077dd7cddfSDavid du Colombier if(ns < 0)
8087dd7cddfSDavid du Colombier return 0;
8097dd7cddfSDavid du Colombier s = ss;
8107dd7cddfSDavid du Colombier n = ns;
8117dd7cddfSDavid du Colombier
8127dd7cddfSDavid du Colombier /*
8137dd7cddfSDavid du Colombier * count lines ending with \n and \r\n
8147dd7cddfSDavid du Colombier * add an extra line at the end, since upas/fs headers
8157dd7cddfSDavid du Colombier * don't have a terminating \r\n
8167dd7cddfSDavid du Colombier */
8177dd7cddfSDavid du Colombier lines = 1;
8187dd7cddfSDavid du Colombier te = s + ns;
8197dd7cddfSDavid du Colombier for(t = s; t < te; t++){
8207dd7cddfSDavid du Colombier c = *t;
8217dd7cddfSDavid du Colombier if(c == '\0')
82280ee5cbfSDavid du Colombier return msgBogus(m, BogusHeader);
8237dd7cddfSDavid du Colombier if(c != '\n')
8247dd7cddfSDavid du Colombier continue;
8257dd7cddfSDavid du Colombier if(t == s || t[-1] != '\r')
8267dd7cddfSDavid du Colombier n++;
8277dd7cddfSDavid du Colombier lines++;
8287dd7cddfSDavid du Colombier }
8297dd7cddfSDavid du Colombier if(t > s && t[-1] != '\n'){
8307dd7cddfSDavid du Colombier if(t[-1] != '\r')
8317dd7cddfSDavid du Colombier n++;
8327dd7cddfSDavid du Colombier n++;
8337dd7cddfSDavid du Colombier }
8347dd7cddfSDavid du Colombier n += 2;
8357dd7cddfSDavid du Colombier h->buf = emalloc(n + 1);
8367dd7cddfSDavid du Colombier h->size = n;
8377dd7cddfSDavid du Colombier h->lines = lines;
8387dd7cddfSDavid du Colombier
8397dd7cddfSDavid du Colombier /*
8407dd7cddfSDavid du Colombier * make sure all headers end in \r\n
8417dd7cddfSDavid du Colombier */
8427dd7cddfSDavid du Colombier nn = 0;
8437dd7cddfSDavid du Colombier for(t = s; t < te; t++){
8447dd7cddfSDavid du Colombier c = *t;
8457dd7cddfSDavid du Colombier if(c == '\n'){
8467dd7cddfSDavid du Colombier if(!nn || h->buf[nn - 1] != '\r')
8477dd7cddfSDavid du Colombier h->buf[nn++] = '\r';
8487dd7cddfSDavid du Colombier lines++;
8497dd7cddfSDavid du Colombier }
8507dd7cddfSDavid du Colombier h->buf[nn++] = c;
8517dd7cddfSDavid du Colombier }
8527dd7cddfSDavid du Colombier if(nn && h->buf[nn-1] != '\n'){
8537dd7cddfSDavid du Colombier if(h->buf[nn-1] != '\r')
8547dd7cddfSDavid du Colombier h->buf[nn++] = '\r';
8557dd7cddfSDavid du Colombier h->buf[nn++] = '\n';
8567dd7cddfSDavid du Colombier }
8577dd7cddfSDavid du Colombier h->buf[nn++] = '\r';
8587dd7cddfSDavid du Colombier h->buf[nn++] = '\n';
8597dd7cddfSDavid du Colombier h->buf[nn] = '\0';
8607dd7cddfSDavid du Colombier if(nn != n)
861*fed0fa9eSDavid du Colombier bye("misconverted header %ld %ld", nn, n);
8627dd7cddfSDavid du Colombier free(s);
8637dd7cddfSDavid du Colombier
8647dd7cddfSDavid du Colombier /*
8657dd7cddfSDavid du Colombier * and parse some mime headers
8667dd7cddfSDavid du Colombier */
8677dd7cddfSDavid du Colombier headStr = (uchar*)h->buf;
8687dd7cddfSDavid du Colombier dated = 0;
8697dd7cddfSDavid du Colombier while(s = headAtom(headFieldStop)){
8707dd7cddfSDavid du Colombier if(cistrcmp(s, "content-type") == 0)
8717dd7cddfSDavid du Colombier mimeType(h);
8727dd7cddfSDavid du Colombier else if(cistrcmp(s, "content-transfer-encoding") == 0)
8737dd7cddfSDavid du Colombier mimeEncoding(h);
8747dd7cddfSDavid du Colombier else if(cistrcmp(s, "content-id") == 0)
8757dd7cddfSDavid du Colombier mimeId(h);
8767dd7cddfSDavid du Colombier else if(cistrcmp(s, "content-description") == 0)
8777dd7cddfSDavid du Colombier mimeDescription(h);
8787dd7cddfSDavid du Colombier else if(cistrcmp(s, "content-disposition") == 0)
8797dd7cddfSDavid du Colombier mimeDisposition(h);
8807dd7cddfSDavid du Colombier else if(cistrcmp(s, "content-md5") == 0)
8817dd7cddfSDavid du Colombier mimeMd5(h);
8827dd7cddfSDavid du Colombier else if(cistrcmp(s, "content-language") == 0)
8837dd7cddfSDavid du Colombier mimeLanguage(h);
8847dd7cddfSDavid du Colombier else if(h == &m->head && cistrcmp(s, "from") == 0)
8857dd7cddfSDavid du Colombier m->from = headMAddr(m->from);
8867dd7cddfSDavid du Colombier else if(h == &m->head && cistrcmp(s, "to") == 0)
8877dd7cddfSDavid du Colombier m->to = headMAddr(m->to);
8887dd7cddfSDavid du Colombier else if(h == &m->head && cistrcmp(s, "reply-to") == 0)
8897dd7cddfSDavid du Colombier m->replyTo = headMAddr(m->replyTo);
8907dd7cddfSDavid du Colombier else if(h == &m->head && cistrcmp(s, "sender") == 0)
8917dd7cddfSDavid du Colombier m->sender = headMAddr(m->sender);
8927dd7cddfSDavid du Colombier else if(h == &m->head && cistrcmp(s, "cc") == 0)
8937dd7cddfSDavid du Colombier m->cc = headMAddr(m->cc);
8947dd7cddfSDavid du Colombier else if(h == &m->head && cistrcmp(s, "bcc") == 0)
8957dd7cddfSDavid du Colombier m->bcc = headMAddr(m->bcc);
8967dd7cddfSDavid du Colombier else if(h == &m->head && cistrcmp(s, "date") == 0)
8977dd7cddfSDavid du Colombier dated = 1;
8987dd7cddfSDavid du Colombier headSkip();
8997dd7cddfSDavid du Colombier free(s);
9007dd7cddfSDavid du Colombier }
9017dd7cddfSDavid du Colombier
9027dd7cddfSDavid du Colombier if(h == &m->head){
9037dd7cddfSDavid du Colombier if(m->from == nil){
9047dd7cddfSDavid du Colombier m->from = m->unixFrom;
905dc5a79c1SDavid du Colombier if(m->from != nil){
9067dd7cddfSDavid du Colombier s = maddrStr(m->from);
9077dd7cddfSDavid du Colombier msgAddHead(m, "From", s);
9087dd7cddfSDavid du Colombier free(s);
9097dd7cddfSDavid du Colombier }
910dc5a79c1SDavid du Colombier }
9117dd7cddfSDavid du Colombier if(m->sender == nil)
9127dd7cddfSDavid du Colombier m->sender = m->from;
9137dd7cddfSDavid du Colombier if(m->replyTo == nil)
9147dd7cddfSDavid du Colombier m->replyTo = m->from;
9157dd7cddfSDavid du Colombier
9167dd7cddfSDavid du Colombier if(infoIsNil(m->info[IDate]))
9177dd7cddfSDavid du Colombier m->info[IDate] = m->unixDate;
918dc5a79c1SDavid du Colombier if(!dated && m->from != nil)
9197dd7cddfSDavid du Colombier msgAddDate(m);
9207dd7cddfSDavid du Colombier }
9217dd7cddfSDavid du Colombier return 1;
9227dd7cddfSDavid du Colombier }
9237dd7cddfSDavid du Colombier
9247dd7cddfSDavid du Colombier /*
9257dd7cddfSDavid du Colombier * prepend head: body to the cached header
9267dd7cddfSDavid du Colombier */
9277dd7cddfSDavid du Colombier static void
msgAddHead(Msg * m,char * head,char * body)9287dd7cddfSDavid du Colombier msgAddHead(Msg *m, char *head, char *body)
9297dd7cddfSDavid du Colombier {
9307dd7cddfSDavid du Colombier char *s;
9317dd7cddfSDavid du Colombier long size, n;
9327dd7cddfSDavid du Colombier
9337dd7cddfSDavid du Colombier n = strlen(head) + strlen(body) + 4;
9347dd7cddfSDavid du Colombier size = m->head.size + n;
9357dd7cddfSDavid du Colombier s = emalloc(size + 1);
9367dd7cddfSDavid du Colombier snprint(s, size + 1, "%s: %s\r\n%s", head, body, m->head.buf);
9377dd7cddfSDavid du Colombier free(m->head.buf);
9387dd7cddfSDavid du Colombier m->head.buf = s;
9397dd7cddfSDavid du Colombier m->head.size = size;
9407dd7cddfSDavid du Colombier m->head.lines++;
9417dd7cddfSDavid du Colombier }
9427dd7cddfSDavid du Colombier
9437dd7cddfSDavid du Colombier static void
msgAddDate(Msg * m)9447dd7cddfSDavid du Colombier msgAddDate(Msg *m)
9457dd7cddfSDavid du Colombier {
9467dd7cddfSDavid du Colombier Tm tm;
9477dd7cddfSDavid du Colombier char buf[64];
9487dd7cddfSDavid du Colombier
949dc5a79c1SDavid du Colombier /* don't bother if we don't have a date */
950dc5a79c1SDavid du Colombier if(infoIsNil(m->info[IDate]))
951dc5a79c1SDavid du Colombier return;
952dc5a79c1SDavid du Colombier
9537dd7cddfSDavid du Colombier date2tm(&tm, m->info[IDate]);
9547dd7cddfSDavid du Colombier rfc822date(buf, sizeof(buf), &tm);
9557dd7cddfSDavid du Colombier msgAddHead(m, "Date", buf);
9567dd7cddfSDavid du Colombier }
9577dd7cddfSDavid du Colombier
9587dd7cddfSDavid du Colombier static MimeHdr*
mkMimeHdr(char * s,char * t,MimeHdr * next)9597dd7cddfSDavid du Colombier mkMimeHdr(char *s, char *t, MimeHdr *next)
9607dd7cddfSDavid du Colombier {
9617dd7cddfSDavid du Colombier MimeHdr *mh;
9627dd7cddfSDavid du Colombier
9637dd7cddfSDavid du Colombier mh = MK(MimeHdr);
9647dd7cddfSDavid du Colombier mh->s = s;
9657dd7cddfSDavid du Colombier mh->t = t;
9667dd7cddfSDavid du Colombier mh->next = next;
9677dd7cddfSDavid du Colombier return mh;
9687dd7cddfSDavid du Colombier }
9697dd7cddfSDavid du Colombier
9707dd7cddfSDavid du Colombier static void
freeMimeHdr(MimeHdr * mh)9717dd7cddfSDavid du Colombier freeMimeHdr(MimeHdr *mh)
9727dd7cddfSDavid du Colombier {
9737dd7cddfSDavid du Colombier MimeHdr *last;
9747dd7cddfSDavid du Colombier
9757dd7cddfSDavid du Colombier while(mh != nil){
9767dd7cddfSDavid du Colombier last = mh;
9777dd7cddfSDavid du Colombier mh = mh->next;
9787dd7cddfSDavid du Colombier free(last->s);
9797dd7cddfSDavid du Colombier free(last->t);
9807dd7cddfSDavid du Colombier free(last);
9817dd7cddfSDavid du Colombier }
9827dd7cddfSDavid du Colombier }
9837dd7cddfSDavid du Colombier
9847dd7cddfSDavid du Colombier static void
cleanupHeader(Header * h)9857dd7cddfSDavid du Colombier cleanupHeader(Header *h)
9867dd7cddfSDavid du Colombier {
9877dd7cddfSDavid du Colombier freeMimeHdr(h->type);
9887dd7cddfSDavid du Colombier freeMimeHdr(h->id);
9897dd7cddfSDavid du Colombier freeMimeHdr(h->description);
9907dd7cddfSDavid du Colombier freeMimeHdr(h->encoding);
9917dd7cddfSDavid du Colombier freeMimeHdr(h->md5);
9927dd7cddfSDavid du Colombier freeMimeHdr(h->disposition);
9937dd7cddfSDavid du Colombier freeMimeHdr(h->language);
9947dd7cddfSDavid du Colombier }
9957dd7cddfSDavid du Colombier
9967dd7cddfSDavid du Colombier /*
9977dd7cddfSDavid du Colombier * parser for rfc822 & mime header fields
9987dd7cddfSDavid du Colombier */
9997dd7cddfSDavid du Colombier
10007dd7cddfSDavid du Colombier /*
10017dd7cddfSDavid du Colombier * type : 'content-type' ':' token '/' token params
10027dd7cddfSDavid du Colombier */
10037dd7cddfSDavid du Colombier static void
mimeType(Header * h)10047dd7cddfSDavid du Colombier mimeType(Header *h)
10057dd7cddfSDavid du Colombier {
10067dd7cddfSDavid du Colombier char *s, *t;
10077dd7cddfSDavid du Colombier
10087dd7cddfSDavid du Colombier if(headChar(1) != ':')
10097dd7cddfSDavid du Colombier return;
10107dd7cddfSDavid du Colombier s = headAtom(mimeTokenStop);
10117dd7cddfSDavid du Colombier if(s == nil || headChar(1) != '/'){
10127dd7cddfSDavid du Colombier free(s);
10137dd7cddfSDavid du Colombier return;
10147dd7cddfSDavid du Colombier }
10157dd7cddfSDavid du Colombier t = headAtom(mimeTokenStop);
10167dd7cddfSDavid du Colombier if(t == nil){
10177dd7cddfSDavid du Colombier free(s);
10187dd7cddfSDavid du Colombier return;
10197dd7cddfSDavid du Colombier }
10207dd7cddfSDavid du Colombier h->type = mkMimeHdr(s, t, mimeParams());
10217dd7cddfSDavid du Colombier }
10227dd7cddfSDavid du Colombier
10237dd7cddfSDavid du Colombier /*
10247dd7cddfSDavid du Colombier * params :
10257dd7cddfSDavid du Colombier * | params ';' token '=' token
10267dd7cddfSDavid du Colombier * | params ';' token '=' quoted-str
10277dd7cddfSDavid du Colombier */
10287dd7cddfSDavid du Colombier static MimeHdr*
mimeParams(void)10297dd7cddfSDavid du Colombier mimeParams(void)
10307dd7cddfSDavid du Colombier {
10317dd7cddfSDavid du Colombier MimeHdr head, *last;
10327dd7cddfSDavid du Colombier char *s, *t;
10337dd7cddfSDavid du Colombier
10347dd7cddfSDavid du Colombier head.next = nil;
10357dd7cddfSDavid du Colombier last = &head;
10367dd7cddfSDavid du Colombier for(;;){
10377dd7cddfSDavid du Colombier if(headChar(1) != ';')
10387dd7cddfSDavid du Colombier break;
10397dd7cddfSDavid du Colombier s = headAtom(mimeTokenStop);
10407dd7cddfSDavid du Colombier if(s == nil || headChar(1) != '='){
10417dd7cddfSDavid du Colombier free(s);
10427dd7cddfSDavid du Colombier break;
10437dd7cddfSDavid du Colombier }
10447dd7cddfSDavid du Colombier if(headChar(0) == '"'){
10457dd7cddfSDavid du Colombier t = headQuoted('"', '"');
10467dd7cddfSDavid du Colombier stripQuotes(t);
10477dd7cddfSDavid du Colombier }else
10487dd7cddfSDavid du Colombier t = headAtom(mimeTokenStop);
10497dd7cddfSDavid du Colombier if(t == nil){
10507dd7cddfSDavid du Colombier free(s);
10517dd7cddfSDavid du Colombier break;
10527dd7cddfSDavid du Colombier }
10537dd7cddfSDavid du Colombier last->next = mkMimeHdr(s, t, nil);
10547dd7cddfSDavid du Colombier last = last->next;
10557dd7cddfSDavid du Colombier }
10567dd7cddfSDavid du Colombier return head.next;
10577dd7cddfSDavid du Colombier }
10587dd7cddfSDavid du Colombier
10597dd7cddfSDavid du Colombier /*
10607dd7cddfSDavid du Colombier * encoding : 'content-transfer-encoding' ':' token
10617dd7cddfSDavid du Colombier */
10627dd7cddfSDavid du Colombier static void
mimeEncoding(Header * h)10637dd7cddfSDavid du Colombier mimeEncoding(Header *h)
10647dd7cddfSDavid du Colombier {
10657dd7cddfSDavid du Colombier char *s;
10667dd7cddfSDavid du Colombier
10677dd7cddfSDavid du Colombier if(headChar(1) != ':')
10687dd7cddfSDavid du Colombier return;
10697dd7cddfSDavid du Colombier s = headAtom(mimeTokenStop);
10707dd7cddfSDavid du Colombier if(s == nil)
10717dd7cddfSDavid du Colombier return;
10727dd7cddfSDavid du Colombier h->encoding = mkMimeHdr(s, nil, nil);
10737dd7cddfSDavid du Colombier }
10747dd7cddfSDavid du Colombier
10757dd7cddfSDavid du Colombier /*
10767dd7cddfSDavid du Colombier * mailaddr : ':' addresses
10777dd7cddfSDavid du Colombier */
10787dd7cddfSDavid du Colombier static MAddr*
headMAddr(MAddr * old)10797dd7cddfSDavid du Colombier headMAddr(MAddr *old)
10807dd7cddfSDavid du Colombier {
10817dd7cddfSDavid du Colombier MAddr *a;
10827dd7cddfSDavid du Colombier
10837dd7cddfSDavid du Colombier if(headChar(1) != ':')
10847dd7cddfSDavid du Colombier return old;
10857dd7cddfSDavid du Colombier
10867dd7cddfSDavid du Colombier if(headChar(0) == '\n')
10877dd7cddfSDavid du Colombier return old;
10887dd7cddfSDavid du Colombier
10897dd7cddfSDavid du Colombier a = headAddresses();
10907dd7cddfSDavid du Colombier if(a == nil)
10917dd7cddfSDavid du Colombier return old;
10927dd7cddfSDavid du Colombier
10937dd7cddfSDavid du Colombier freeMAddr(old);
10947dd7cddfSDavid du Colombier return a;
10957dd7cddfSDavid du Colombier }
10967dd7cddfSDavid du Colombier
10977dd7cddfSDavid du Colombier /*
10987dd7cddfSDavid du Colombier * addresses : address | addresses ',' address
10997dd7cddfSDavid du Colombier */
11007dd7cddfSDavid du Colombier static MAddr*
headAddresses(void)11017dd7cddfSDavid du Colombier headAddresses(void)
11027dd7cddfSDavid du Colombier {
11037dd7cddfSDavid du Colombier MAddr *addr, *tail, *a;
11047dd7cddfSDavid du Colombier
11057dd7cddfSDavid du Colombier addr = headAddress();
11067dd7cddfSDavid du Colombier if(addr == nil)
11077dd7cddfSDavid du Colombier return nil;
11087dd7cddfSDavid du Colombier tail = addr;
11097dd7cddfSDavid du Colombier while(headChar(0) == ','){
11107dd7cddfSDavid du Colombier headChar(1);
11117dd7cddfSDavid du Colombier a = headAddress();
11127dd7cddfSDavid du Colombier if(a == nil){
11137dd7cddfSDavid du Colombier freeMAddr(addr);
11147dd7cddfSDavid du Colombier return nil;
11157dd7cddfSDavid du Colombier }
11167dd7cddfSDavid du Colombier tail->next = a;
11177dd7cddfSDavid du Colombier tail = a;
11187dd7cddfSDavid du Colombier }
11197dd7cddfSDavid du Colombier return addr;
11207dd7cddfSDavid du Colombier }
11217dd7cddfSDavid du Colombier
11227dd7cddfSDavid du Colombier /*
11237dd7cddfSDavid du Colombier * address : mailbox | group
11247dd7cddfSDavid du Colombier * group : phrase ':' mboxes ';' | phrase ':' ';'
11257dd7cddfSDavid du Colombier * mailbox : addr-spec
11267dd7cddfSDavid du Colombier * | optphrase '<' addr-spec '>'
11277dd7cddfSDavid du Colombier * | optphrase '<' route ':' addr-spec '>'
11287dd7cddfSDavid du Colombier * optphrase : | phrase
11297dd7cddfSDavid du Colombier * route : '@' domain
11307dd7cddfSDavid du Colombier * | route ',' '@' domain
11317dd7cddfSDavid du Colombier * personal names are the phrase before '<',
11327dd7cddfSDavid du Colombier * or a comment before or after a simple addr-spec
11337dd7cddfSDavid du Colombier */
11347dd7cddfSDavid du Colombier static MAddr*
headAddress(void)11357dd7cddfSDavid du Colombier headAddress(void)
11367dd7cddfSDavid du Colombier {
11377dd7cddfSDavid du Colombier MAddr *addr;
11387dd7cddfSDavid du Colombier uchar *hs;
11397dd7cddfSDavid du Colombier char *s, *e, *w, *personal;
11407dd7cddfSDavid du Colombier int c;
11417dd7cddfSDavid du Colombier
11427dd7cddfSDavid du Colombier s = emalloc(strlen((char*)headStr) + 2);
11437dd7cddfSDavid du Colombier e = s;
11447dd7cddfSDavid du Colombier personal = headSkipWhite(1);
11457dd7cddfSDavid du Colombier c = headChar(0);
11467dd7cddfSDavid du Colombier if(c == '<')
11477dd7cddfSDavid du Colombier w = nil;
11487dd7cddfSDavid du Colombier else{
11497dd7cddfSDavid du Colombier w = headWord();
11507dd7cddfSDavid du Colombier c = headChar(0);
11517dd7cddfSDavid du Colombier }
11527dd7cddfSDavid du Colombier if(c == '.' || c == '@' || c == ',' || c == '\n' || c == '\0'){
11537dd7cddfSDavid du Colombier lastWhite = headStr;
11547dd7cddfSDavid du Colombier e = headAddrSpec(s, w);
11557dd7cddfSDavid du Colombier if(personal == nil){
11567dd7cddfSDavid du Colombier hs = headStr;
11577dd7cddfSDavid du Colombier headStr = lastWhite;
11587dd7cddfSDavid du Colombier personal = headSkipWhite(1);
11597dd7cddfSDavid du Colombier headStr = hs;
11607dd7cddfSDavid du Colombier }
11617dd7cddfSDavid du Colombier }else{
11627dd7cddfSDavid du Colombier if(c != '<' || w != nil){
11637dd7cddfSDavid du Colombier free(personal);
11647dd7cddfSDavid du Colombier if(!headPhrase(e, w)){
11657dd7cddfSDavid du Colombier free(s);
11667dd7cddfSDavid du Colombier return nil;
11677dd7cddfSDavid du Colombier }
11687dd7cddfSDavid du Colombier
11697dd7cddfSDavid du Colombier /*
11707dd7cddfSDavid du Colombier * ignore addresses with groups,
11717dd7cddfSDavid du Colombier * so the only thing left if <
11727dd7cddfSDavid du Colombier */
11737dd7cddfSDavid du Colombier c = headChar(1);
11747dd7cddfSDavid du Colombier if(c != '<'){
11757dd7cddfSDavid du Colombier free(s);
11767dd7cddfSDavid du Colombier return nil;
11777dd7cddfSDavid du Colombier }
11787dd7cddfSDavid du Colombier personal = estrdup(s);
11797dd7cddfSDavid du Colombier }else
11807dd7cddfSDavid du Colombier headChar(1);
11817dd7cddfSDavid du Colombier
11827dd7cddfSDavid du Colombier /*
11837dd7cddfSDavid du Colombier * after this point, we need to free personal before returning.
11847dd7cddfSDavid du Colombier * set e to nil to everything afterwards fails.
11857dd7cddfSDavid du Colombier *
11867dd7cddfSDavid du Colombier * ignore routes, they are useless, and heavily discouraged in rfc1123.
11877dd7cddfSDavid du Colombier * imap4 reports them up to, but not including, the terminating :
11887dd7cddfSDavid du Colombier */
11897dd7cddfSDavid du Colombier e = s;
11907dd7cddfSDavid du Colombier c = headChar(0);
11917dd7cddfSDavid du Colombier if(c == '@'){
11927dd7cddfSDavid du Colombier for(;;){
11937dd7cddfSDavid du Colombier c = headChar(1);
11947dd7cddfSDavid du Colombier if(c != '@'){
11957dd7cddfSDavid du Colombier e = nil;
11967dd7cddfSDavid du Colombier break;
11977dd7cddfSDavid du Colombier }
11987dd7cddfSDavid du Colombier headDomain(e);
11997dd7cddfSDavid du Colombier c = headChar(1);
12007dd7cddfSDavid du Colombier if(c != ','){
12017dd7cddfSDavid du Colombier e = s;
12027dd7cddfSDavid du Colombier break;
12037dd7cddfSDavid du Colombier }
12047dd7cddfSDavid du Colombier }
12057dd7cddfSDavid du Colombier if(c != ':')
12067dd7cddfSDavid du Colombier e = nil;
12077dd7cddfSDavid du Colombier }
12087dd7cddfSDavid du Colombier
12097dd7cddfSDavid du Colombier if(e != nil)
12107dd7cddfSDavid du Colombier e = headAddrSpec(s, nil);
12117dd7cddfSDavid du Colombier if(headChar(1) != '>')
12127dd7cddfSDavid du Colombier e = nil;
12137dd7cddfSDavid du Colombier }
12147dd7cddfSDavid du Colombier
12157dd7cddfSDavid du Colombier /*
12167dd7cddfSDavid du Colombier * e points to @host, or nil if an error occured
12177dd7cddfSDavid du Colombier */
12187dd7cddfSDavid du Colombier if(e == nil){
12197dd7cddfSDavid du Colombier free(personal);
12207dd7cddfSDavid du Colombier addr = nil;
12217dd7cddfSDavid du Colombier }else{
12227dd7cddfSDavid du Colombier if(*e != '\0')
12237dd7cddfSDavid du Colombier *e++ = '\0';
12247dd7cddfSDavid du Colombier else
12257dd7cddfSDavid du Colombier e = site;
12267dd7cddfSDavid du Colombier addr = MKZ(MAddr);
12277dd7cddfSDavid du Colombier
12287dd7cddfSDavid du Colombier addr->personal = personal;
12297dd7cddfSDavid du Colombier addr->box = estrdup(s);
12307dd7cddfSDavid du Colombier addr->host = estrdup(e);
12317dd7cddfSDavid du Colombier }
12327dd7cddfSDavid du Colombier free(s);
12337dd7cddfSDavid du Colombier return addr;
12347dd7cddfSDavid du Colombier }
12357dd7cddfSDavid du Colombier
12367dd7cddfSDavid du Colombier /*
12377dd7cddfSDavid du Colombier * phrase : word
12387dd7cddfSDavid du Colombier * | phrase word
12397dd7cddfSDavid du Colombier * w is the optional initial word of the phrase
12407dd7cddfSDavid du Colombier * returns the end of the phrase, or nil if a failure occured
12417dd7cddfSDavid du Colombier */
12427dd7cddfSDavid du Colombier static char*
headPhrase(char * e,char * w)12437dd7cddfSDavid du Colombier headPhrase(char *e, char *w)
12447dd7cddfSDavid du Colombier {
12457dd7cddfSDavid du Colombier int c;
12467dd7cddfSDavid du Colombier
12477dd7cddfSDavid du Colombier for(;;){
12487dd7cddfSDavid du Colombier if(w == nil){
12497dd7cddfSDavid du Colombier w = headWord();
12507dd7cddfSDavid du Colombier if(w == nil)
12517dd7cddfSDavid du Colombier return nil;
12527dd7cddfSDavid du Colombier }
12537dd7cddfSDavid du Colombier if(w[0] == '"')
12547dd7cddfSDavid du Colombier stripQuotes(w);
12557dd7cddfSDavid du Colombier strcpy(e, w);
12567dd7cddfSDavid du Colombier free(w);
12577dd7cddfSDavid du Colombier w = nil;
12587dd7cddfSDavid du Colombier e = strchr(e, '\0');
12597dd7cddfSDavid du Colombier c = headChar(0);
12607dd7cddfSDavid du Colombier if(c <= ' ' || strchr(headAtomStop, c) != nil && c != '"')
12617dd7cddfSDavid du Colombier break;
12627dd7cddfSDavid du Colombier *e++ = ' ';
12637dd7cddfSDavid du Colombier *e = '\0';
12647dd7cddfSDavid du Colombier }
12657dd7cddfSDavid du Colombier return e;
12667dd7cddfSDavid du Colombier }
12677dd7cddfSDavid du Colombier
12687dd7cddfSDavid du Colombier /*
12697dd7cddfSDavid du Colombier * addr-spec : local-part '@' domain
12707dd7cddfSDavid du Colombier * | local-part extension to allow ! and local names
12717dd7cddfSDavid du Colombier * local-part : word
12727dd7cddfSDavid du Colombier * | local-part '.' word
12737dd7cddfSDavid du Colombier *
12747dd7cddfSDavid du Colombier * if no '@' is present, rewrite d!e!f!u as @d,@e:u@f,
12757dd7cddfSDavid du Colombier * where d, e, f are valid domain components.
12767dd7cddfSDavid du Colombier * the @d,@e: is ignored, since routes are ignored.
12777dd7cddfSDavid du Colombier * perhaps they should be rewritten as e!f!u@d, but that is inconsistent with upas.
12787dd7cddfSDavid du Colombier *
12797dd7cddfSDavid du Colombier * returns a pointer to '@', the end if none, or nil if there was an error
12807dd7cddfSDavid du Colombier */
12817dd7cddfSDavid du Colombier static char*
headAddrSpec(char * e,char * w)12827dd7cddfSDavid du Colombier headAddrSpec(char *e, char *w)
12837dd7cddfSDavid du Colombier {
12847dd7cddfSDavid du Colombier char *s, *at, *b, *bang, *dom;
12857dd7cddfSDavid du Colombier int c;
12867dd7cddfSDavid du Colombier
12877dd7cddfSDavid du Colombier s = e;
12887dd7cddfSDavid du Colombier for(;;){
12897dd7cddfSDavid du Colombier if(w == nil){
12907dd7cddfSDavid du Colombier w = headWord();
12917dd7cddfSDavid du Colombier if(w == nil)
12927dd7cddfSDavid du Colombier return nil;
12937dd7cddfSDavid du Colombier }
12947dd7cddfSDavid du Colombier strcpy(e, w);
12957dd7cddfSDavid du Colombier free(w);
12967dd7cddfSDavid du Colombier w = nil;
12977dd7cddfSDavid du Colombier e = strchr(e, '\0');
12987dd7cddfSDavid du Colombier lastWhite = headStr;
12997dd7cddfSDavid du Colombier c = headChar(0);
13007dd7cddfSDavid du Colombier if(c != '.')
13017dd7cddfSDavid du Colombier break;
13027dd7cddfSDavid du Colombier headChar(1);
13037dd7cddfSDavid du Colombier *e++ = '.';
13047dd7cddfSDavid du Colombier *e = '\0';
13057dd7cddfSDavid du Colombier }
13067dd7cddfSDavid du Colombier
13077dd7cddfSDavid du Colombier if(c != '@'){
13087dd7cddfSDavid du Colombier /*
13097dd7cddfSDavid du Colombier * extenstion: allow name without domain
13107dd7cddfSDavid du Colombier * check for domain!xxx
13117dd7cddfSDavid du Colombier */
13127dd7cddfSDavid du Colombier bang = domBang(s);
13137dd7cddfSDavid du Colombier if(bang == nil)
13147dd7cddfSDavid du Colombier return e;
13157dd7cddfSDavid du Colombier
13167dd7cddfSDavid du Colombier /*
13177dd7cddfSDavid du Colombier * if dom1!dom2!xxx, ignore dom1!
13187dd7cddfSDavid du Colombier */
13197dd7cddfSDavid du Colombier dom = s;
13207dd7cddfSDavid du Colombier for(; b = domBang(bang + 1); bang = b)
13217dd7cddfSDavid du Colombier dom = bang + 1;
13227dd7cddfSDavid du Colombier
13237dd7cddfSDavid du Colombier /*
13247dd7cddfSDavid du Colombier * convert dom!mbox into mbox@dom
13257dd7cddfSDavid du Colombier */
13267dd7cddfSDavid du Colombier *bang = '@';
13277dd7cddfSDavid du Colombier strrev(dom, bang);
13287dd7cddfSDavid du Colombier strrev(bang+1, e);
13297dd7cddfSDavid du Colombier strrev(dom, e);
13307dd7cddfSDavid du Colombier bang = &dom[e - bang - 1];
13317dd7cddfSDavid du Colombier if(dom > s){
13327dd7cddfSDavid du Colombier bang -= dom - s;
13337dd7cddfSDavid du Colombier for(e = s; *e = *dom; e++)
13347dd7cddfSDavid du Colombier dom++;
13357dd7cddfSDavid du Colombier }
13367dd7cddfSDavid du Colombier
13377dd7cddfSDavid du Colombier /*
13387dd7cddfSDavid du Colombier * eliminate a trailing '.'
13397dd7cddfSDavid du Colombier */
13407dd7cddfSDavid du Colombier if(e[-1] == '.')
13417dd7cddfSDavid du Colombier e[-1] = '\0';
13427dd7cddfSDavid du Colombier return bang;
13437dd7cddfSDavid du Colombier }
13447dd7cddfSDavid du Colombier headChar(1);
13457dd7cddfSDavid du Colombier
13467dd7cddfSDavid du Colombier at = e;
13477dd7cddfSDavid du Colombier *e++ = '@';
13487dd7cddfSDavid du Colombier *e = '\0';
13497dd7cddfSDavid du Colombier if(!headDomain(e))
13507dd7cddfSDavid du Colombier return nil;
13517dd7cddfSDavid du Colombier return at;
13527dd7cddfSDavid du Colombier }
13537dd7cddfSDavid du Colombier
13547dd7cddfSDavid du Colombier /*
13557dd7cddfSDavid du Colombier * find the ! in domain!rest, where domain must have at least
13569a747e4fSDavid du Colombier * one internal '.'
13577dd7cddfSDavid du Colombier */
13587dd7cddfSDavid du Colombier static char*
domBang(char * s)13597dd7cddfSDavid du Colombier domBang(char *s)
13607dd7cddfSDavid du Colombier {
13617dd7cddfSDavid du Colombier int dot, c;
13627dd7cddfSDavid du Colombier
13637dd7cddfSDavid du Colombier dot = 0;
13647dd7cddfSDavid du Colombier for(; c = *s; s++){
13657dd7cddfSDavid du Colombier if(c == '!'){
13667dd7cddfSDavid du Colombier if(!dot || dot == 1 && s[-1] == '.' || s[1] == '\0')
13677dd7cddfSDavid du Colombier return nil;
13687dd7cddfSDavid du Colombier return s;
13697dd7cddfSDavid du Colombier }
13707dd7cddfSDavid du Colombier if(c == '"')
13717dd7cddfSDavid du Colombier break;
13727dd7cddfSDavid du Colombier if(c == '.')
13737dd7cddfSDavid du Colombier dot++;
13747dd7cddfSDavid du Colombier }
13757dd7cddfSDavid du Colombier return nil;
13767dd7cddfSDavid du Colombier }
13777dd7cddfSDavid du Colombier
13787dd7cddfSDavid du Colombier /*
13797dd7cddfSDavid du Colombier * domain : sub-domain
13807dd7cddfSDavid du Colombier * | domain '.' sub-domain
13817dd7cddfSDavid du Colombier * returns the end of the domain, or nil if a failure occured
13827dd7cddfSDavid du Colombier */
13837dd7cddfSDavid du Colombier static char*
headDomain(char * e)13847dd7cddfSDavid du Colombier headDomain(char *e)
13857dd7cddfSDavid du Colombier {
13867dd7cddfSDavid du Colombier char *w;
13877dd7cddfSDavid du Colombier
13887dd7cddfSDavid du Colombier for(;;){
13897dd7cddfSDavid du Colombier w = headSubDomain();
13907dd7cddfSDavid du Colombier if(w == nil)
13917dd7cddfSDavid du Colombier return nil;
13927dd7cddfSDavid du Colombier strcpy(e, w);
13937dd7cddfSDavid du Colombier free(w);
13947dd7cddfSDavid du Colombier e = strchr(e, '\0');
13957dd7cddfSDavid du Colombier lastWhite = headStr;
13967dd7cddfSDavid du Colombier if(headChar(0) != '.')
13977dd7cddfSDavid du Colombier break;
13987dd7cddfSDavid du Colombier headChar(1);
13997dd7cddfSDavid du Colombier *e++ = '.';
14007dd7cddfSDavid du Colombier *e = '\0';
14017dd7cddfSDavid du Colombier }
14027dd7cddfSDavid du Colombier return e;
14037dd7cddfSDavid du Colombier }
14047dd7cddfSDavid du Colombier
14057dd7cddfSDavid du Colombier /*
14067dd7cddfSDavid du Colombier * id : 'content-id' ':' msg-id
14077dd7cddfSDavid du Colombier * msg-id : '<' addr-spec '>'
14087dd7cddfSDavid du Colombier */
14097dd7cddfSDavid du Colombier static void
mimeId(Header * h)14107dd7cddfSDavid du Colombier mimeId(Header *h)
14117dd7cddfSDavid du Colombier {
14127dd7cddfSDavid du Colombier char *s, *e, *w;
14137dd7cddfSDavid du Colombier
14147dd7cddfSDavid du Colombier if(headChar(1) != ':')
14157dd7cddfSDavid du Colombier return;
14167dd7cddfSDavid du Colombier if(headChar(1) != '<')
14177dd7cddfSDavid du Colombier return;
14187dd7cddfSDavid du Colombier
14197dd7cddfSDavid du Colombier s = emalloc(strlen((char*)headStr) + 3);
14207dd7cddfSDavid du Colombier e = s;
14217dd7cddfSDavid du Colombier *e++ = '<';
14227dd7cddfSDavid du Colombier e = headAddrSpec(e, nil);
14237dd7cddfSDavid du Colombier if(e == nil || headChar(1) != '>'){
14247dd7cddfSDavid du Colombier free(s);
14257dd7cddfSDavid du Colombier return;
14267dd7cddfSDavid du Colombier }
14277dd7cddfSDavid du Colombier e = strchr(e, '\0');
14287dd7cddfSDavid du Colombier *e++ = '>';
14297dd7cddfSDavid du Colombier e[0] = '\0';
14307dd7cddfSDavid du Colombier w = strdup(s);
14317dd7cddfSDavid du Colombier free(s);
14327dd7cddfSDavid du Colombier h->id = mkMimeHdr(w, nil, nil);
14337dd7cddfSDavid du Colombier }
14347dd7cddfSDavid du Colombier
14357dd7cddfSDavid du Colombier /*
14367dd7cddfSDavid du Colombier * description : 'content-description' ':' *text
14377dd7cddfSDavid du Colombier */
14387dd7cddfSDavid du Colombier static void
mimeDescription(Header * h)14397dd7cddfSDavid du Colombier mimeDescription(Header *h)
14407dd7cddfSDavid du Colombier {
14417dd7cddfSDavid du Colombier if(headChar(1) != ':')
14427dd7cddfSDavid du Colombier return;
14437dd7cddfSDavid du Colombier headSkipWhite(0);
14447dd7cddfSDavid du Colombier h->description = mkMimeHdr(headText(), nil, nil);
14457dd7cddfSDavid du Colombier }
14467dd7cddfSDavid du Colombier
14477dd7cddfSDavid du Colombier /*
14487dd7cddfSDavid du Colombier * disposition : 'content-disposition' ':' token params
14497dd7cddfSDavid du Colombier */
14507dd7cddfSDavid du Colombier static void
mimeDisposition(Header * h)14517dd7cddfSDavid du Colombier mimeDisposition(Header *h)
14527dd7cddfSDavid du Colombier {
14537dd7cddfSDavid du Colombier char *s;
14547dd7cddfSDavid du Colombier
14557dd7cddfSDavid du Colombier if(headChar(1) != ':')
14567dd7cddfSDavid du Colombier return;
14577dd7cddfSDavid du Colombier s = headAtom(mimeTokenStop);
14587dd7cddfSDavid du Colombier if(s == nil)
14597dd7cddfSDavid du Colombier return;
14607dd7cddfSDavid du Colombier h->disposition = mkMimeHdr(s, nil, mimeParams());
14617dd7cddfSDavid du Colombier }
14627dd7cddfSDavid du Colombier
14637dd7cddfSDavid du Colombier /*
14647dd7cddfSDavid du Colombier * md5 : 'content-md5' ':' token
14657dd7cddfSDavid du Colombier */
14667dd7cddfSDavid du Colombier static void
mimeMd5(Header * h)14677dd7cddfSDavid du Colombier mimeMd5(Header *h)
14687dd7cddfSDavid du Colombier {
14697dd7cddfSDavid du Colombier char *s;
14707dd7cddfSDavid du Colombier
14717dd7cddfSDavid du Colombier if(headChar(1) != ':')
14727dd7cddfSDavid du Colombier return;
14737dd7cddfSDavid du Colombier s = headAtom(mimeTokenStop);
14747dd7cddfSDavid du Colombier if(s == nil)
14757dd7cddfSDavid du Colombier return;
14767dd7cddfSDavid du Colombier h->md5 = mkMimeHdr(s, nil, nil);
14777dd7cddfSDavid du Colombier }
14787dd7cddfSDavid du Colombier
14797dd7cddfSDavid du Colombier /*
14807dd7cddfSDavid du Colombier * language : 'content-language' ':' langs
14817dd7cddfSDavid du Colombier * langs : token
14827dd7cddfSDavid du Colombier * | langs commas token
14837dd7cddfSDavid du Colombier * commas : ','
14847dd7cddfSDavid du Colombier * | commas ','
14857dd7cddfSDavid du Colombier */
14867dd7cddfSDavid du Colombier static void
mimeLanguage(Header * h)14877dd7cddfSDavid du Colombier mimeLanguage(Header *h)
14887dd7cddfSDavid du Colombier {
14897dd7cddfSDavid du Colombier MimeHdr head, *last;
14907dd7cddfSDavid du Colombier char *s;
14917dd7cddfSDavid du Colombier
14927dd7cddfSDavid du Colombier head.next = nil;
14937dd7cddfSDavid du Colombier last = &head;
14947dd7cddfSDavid du Colombier for(;;){
14957dd7cddfSDavid du Colombier s = headAtom(mimeTokenStop);
14967dd7cddfSDavid du Colombier if(s == nil)
14977dd7cddfSDavid du Colombier break;
14987dd7cddfSDavid du Colombier last->next = mkMimeHdr(s, nil, nil);
14997dd7cddfSDavid du Colombier last = last->next;
15007dd7cddfSDavid du Colombier while(headChar(0) != ',')
15017dd7cddfSDavid du Colombier headChar(1);
15027dd7cddfSDavid du Colombier }
15037dd7cddfSDavid du Colombier h->language = head.next;
15047dd7cddfSDavid du Colombier }
15057dd7cddfSDavid du Colombier
15067dd7cddfSDavid du Colombier /*
15077dd7cddfSDavid du Colombier * token : 1*<char 33-255, except "()<>@,;:\\\"/[]?=" aka mimeTokenStop>
15087dd7cddfSDavid du Colombier * atom : 1*<chars 33-255, except "()<>@,;:\\\".[]" aka headAtomStop>
15097dd7cddfSDavid du Colombier * note this allows 8 bit characters, which occur in utf.
15107dd7cddfSDavid du Colombier */
15117dd7cddfSDavid du Colombier static char*
headAtom(char * disallowed)15127dd7cddfSDavid du Colombier headAtom(char *disallowed)
15137dd7cddfSDavid du Colombier {
15147dd7cddfSDavid du Colombier char *s;
15157dd7cddfSDavid du Colombier int c, ns, as;
15167dd7cddfSDavid du Colombier
15177dd7cddfSDavid du Colombier headSkipWhite(0);
15187dd7cddfSDavid du Colombier
15197dd7cddfSDavid du Colombier s = emalloc(StrAlloc);
15207dd7cddfSDavid du Colombier as = StrAlloc;
15217dd7cddfSDavid du Colombier ns = 0;
15227dd7cddfSDavid du Colombier for(;;){
15237dd7cddfSDavid du Colombier c = *headStr++;
15247dd7cddfSDavid du Colombier if(c <= ' ' || strchr(disallowed, c) != nil){
15257dd7cddfSDavid du Colombier headStr--;
15267dd7cddfSDavid du Colombier break;
15277dd7cddfSDavid du Colombier }
15287dd7cddfSDavid du Colombier s[ns++] = c;
15297dd7cddfSDavid du Colombier if(ns >= as){
15307dd7cddfSDavid du Colombier as += StrAlloc;
15317dd7cddfSDavid du Colombier s = erealloc(s, as);
15327dd7cddfSDavid du Colombier }
15337dd7cddfSDavid du Colombier }
15347dd7cddfSDavid du Colombier if(ns == 0){
15357dd7cddfSDavid du Colombier free(s);
15367dd7cddfSDavid du Colombier return 0;
15377dd7cddfSDavid du Colombier }
15387dd7cddfSDavid du Colombier s[ns] = '\0';
15397dd7cddfSDavid du Colombier return s;
15407dd7cddfSDavid du Colombier }
15417dd7cddfSDavid du Colombier
15427dd7cddfSDavid du Colombier /*
15437dd7cddfSDavid du Colombier * sub-domain : atom | domain-lit
15447dd7cddfSDavid du Colombier */
15457dd7cddfSDavid du Colombier static char *
headSubDomain(void)15467dd7cddfSDavid du Colombier headSubDomain(void)
15477dd7cddfSDavid du Colombier {
15487dd7cddfSDavid du Colombier if(headChar(0) == '[')
15497dd7cddfSDavid du Colombier return headQuoted('[', ']');
15507dd7cddfSDavid du Colombier return headAtom(headAtomStop);
15517dd7cddfSDavid du Colombier }
15527dd7cddfSDavid du Colombier
15537dd7cddfSDavid du Colombier /*
15547dd7cddfSDavid du Colombier * word : atom | quoted-str
15557dd7cddfSDavid du Colombier */
15567dd7cddfSDavid du Colombier static char *
headWord(void)15577dd7cddfSDavid du Colombier headWord(void)
15587dd7cddfSDavid du Colombier {
15597dd7cddfSDavid du Colombier if(headChar(0) == '"')
15607dd7cddfSDavid du Colombier return headQuoted('"', '"');
15617dd7cddfSDavid du Colombier return headAtom(headAtomStop);
15627dd7cddfSDavid du Colombier }
15637dd7cddfSDavid du Colombier
15647dd7cddfSDavid du Colombier /*
15657dd7cddfSDavid du Colombier * q is a quoted string. remove enclosing " and and \ escapes
15667dd7cddfSDavid du Colombier */
15677dd7cddfSDavid du Colombier static void
stripQuotes(char * q)15687dd7cddfSDavid du Colombier stripQuotes(char *q)
15697dd7cddfSDavid du Colombier {
15707dd7cddfSDavid du Colombier char *s;
15717dd7cddfSDavid du Colombier int c;
15727dd7cddfSDavid du Colombier
1573223a736eSDavid du Colombier if(q == nil)
1574223a736eSDavid du Colombier return;
15757dd7cddfSDavid du Colombier s = q++;
15767dd7cddfSDavid du Colombier while(c = *q++){
15777dd7cddfSDavid du Colombier if(c == '\\'){
15787dd7cddfSDavid du Colombier c = *q++;
15797dd7cddfSDavid du Colombier if(!c)
15807dd7cddfSDavid du Colombier return;
15817dd7cddfSDavid du Colombier }
15827dd7cddfSDavid du Colombier *s++ = c;
15837dd7cddfSDavid du Colombier }
15847dd7cddfSDavid du Colombier s[-1] = '\0';
15857dd7cddfSDavid du Colombier }
15867dd7cddfSDavid du Colombier
15877dd7cddfSDavid du Colombier /*
1588223a736eSDavid du Colombier * quoted-str : '"' *(any char but '"\\\r', or '\' any char, or linear-white-space) '"'
1589223a736eSDavid du Colombier * domain-lit : '[' *(any char but '[]\\\r', or '\' any char, or linear-white-space) ']'
15907dd7cddfSDavid du Colombier */
15917dd7cddfSDavid du Colombier static char *
headQuoted(int start,int stop)15927dd7cddfSDavid du Colombier headQuoted(int start, int stop)
15937dd7cddfSDavid du Colombier {
15947dd7cddfSDavid du Colombier char *s;
15957dd7cddfSDavid du Colombier int c, ns, as;
15967dd7cddfSDavid du Colombier
15977dd7cddfSDavid du Colombier if(headChar(1) != start)
15987dd7cddfSDavid du Colombier return nil;
15997dd7cddfSDavid du Colombier s = emalloc(StrAlloc);
16007dd7cddfSDavid du Colombier as = StrAlloc;
16017dd7cddfSDavid du Colombier ns = 0;
16027dd7cddfSDavid du Colombier s[ns++] = start;
16037dd7cddfSDavid du Colombier for(;;){
16047dd7cddfSDavid du Colombier c = *headStr;
16057dd7cddfSDavid du Colombier if(c == stop){
16067dd7cddfSDavid du Colombier headStr++;
16077dd7cddfSDavid du Colombier break;
16087dd7cddfSDavid du Colombier }
16097dd7cddfSDavid du Colombier if(c == '\0'){
16107dd7cddfSDavid du Colombier free(s);
16117dd7cddfSDavid du Colombier return nil;
16127dd7cddfSDavid du Colombier }
1613223a736eSDavid du Colombier if(c == '\r'){
1614223a736eSDavid du Colombier headStr++;
16157dd7cddfSDavid du Colombier continue;
1616223a736eSDavid du Colombier }
16177dd7cddfSDavid du Colombier if(c == '\n'){
16187dd7cddfSDavid du Colombier headStr++;
16197dd7cddfSDavid du Colombier while(*headStr == ' ' || *headStr == '\t' || *headStr == '\r' || *headStr == '\n')
16207dd7cddfSDavid du Colombier headStr++;
16217dd7cddfSDavid du Colombier c = ' ';
16227dd7cddfSDavid du Colombier }else if(c == '\\'){
16237dd7cddfSDavid du Colombier headStr++;
16247dd7cddfSDavid du Colombier s[ns++] = c;
16257dd7cddfSDavid du Colombier c = *headStr;
16267dd7cddfSDavid du Colombier if(c == '\0'){
16277dd7cddfSDavid du Colombier free(s);
16287dd7cddfSDavid du Colombier return nil;
16297dd7cddfSDavid du Colombier }
16307dd7cddfSDavid du Colombier headStr++;
16317dd7cddfSDavid du Colombier }else
16327dd7cddfSDavid du Colombier headStr++;
16337dd7cddfSDavid du Colombier s[ns++] = c;
16347dd7cddfSDavid du Colombier if(ns + 1 >= as){ /* leave room for \c or "0 */
16357dd7cddfSDavid du Colombier as += StrAlloc;
16367dd7cddfSDavid du Colombier s = erealloc(s, as);
16377dd7cddfSDavid du Colombier }
16387dd7cddfSDavid du Colombier }
16397dd7cddfSDavid du Colombier s[ns++] = stop;
16407dd7cddfSDavid du Colombier s[ns] = '\0';
16417dd7cddfSDavid du Colombier return s;
16427dd7cddfSDavid du Colombier }
16437dd7cddfSDavid du Colombier
16447dd7cddfSDavid du Colombier /*
16457dd7cddfSDavid du Colombier * headText : contents of rest of header line
16467dd7cddfSDavid du Colombier */
16477dd7cddfSDavid du Colombier static char *
headText(void)16487dd7cddfSDavid du Colombier headText(void)
16497dd7cddfSDavid du Colombier {
16507dd7cddfSDavid du Colombier uchar *v;
16517dd7cddfSDavid du Colombier char *s;
16527dd7cddfSDavid du Colombier
16537dd7cddfSDavid du Colombier v = headStr;
16547dd7cddfSDavid du Colombier headToEnd();
16557dd7cddfSDavid du Colombier s = emalloc(headStr - v + 1);
16567dd7cddfSDavid du Colombier memmove(s, v, headStr - v);
16577dd7cddfSDavid du Colombier s[headStr - v] = '\0';
16587dd7cddfSDavid du Colombier return s;
16597dd7cddfSDavid du Colombier }
16607dd7cddfSDavid du Colombier
16617dd7cddfSDavid du Colombier /*
16627dd7cddfSDavid du Colombier * white space is ' ' '\t' or nested comments.
16637dd7cddfSDavid du Colombier * skip white space.
16647dd7cddfSDavid du Colombier * if com and a comment is seen,
16657dd7cddfSDavid du Colombier * return it's contents and stop processing white space.
16667dd7cddfSDavid du Colombier */
16677dd7cddfSDavid du Colombier static char*
headSkipWhite(int com)16687dd7cddfSDavid du Colombier headSkipWhite(int com)
16697dd7cddfSDavid du Colombier {
16707dd7cddfSDavid du Colombier char *s;
16717dd7cddfSDavid du Colombier int c, incom, as, ns;
16727dd7cddfSDavid du Colombier
16737dd7cddfSDavid du Colombier s = nil;
16747dd7cddfSDavid du Colombier as = StrAlloc;
16757dd7cddfSDavid du Colombier ns = 0;
16767dd7cddfSDavid du Colombier if(com)
16777dd7cddfSDavid du Colombier s = emalloc(StrAlloc);
16787dd7cddfSDavid du Colombier incom = 0;
16797dd7cddfSDavid du Colombier for(; c = *headStr; headStr++){
16807dd7cddfSDavid du Colombier switch(c){
16817dd7cddfSDavid du Colombier case ' ':
16827dd7cddfSDavid du Colombier case '\t':
16837dd7cddfSDavid du Colombier case '\r':
16847dd7cddfSDavid du Colombier c = ' ';
16857dd7cddfSDavid du Colombier break;
16867dd7cddfSDavid du Colombier case '\n':
16877dd7cddfSDavid du Colombier c = headStr[1];
16887dd7cddfSDavid du Colombier if(c != ' ' && c != '\t')
16897dd7cddfSDavid du Colombier goto breakout;
16907dd7cddfSDavid du Colombier c = ' ';
16917dd7cddfSDavid du Colombier break;
16927dd7cddfSDavid du Colombier case '\\':
16937dd7cddfSDavid du Colombier if(com && incom)
16947dd7cddfSDavid du Colombier s[ns++] = c;
16957dd7cddfSDavid du Colombier c = headStr[1];
16967dd7cddfSDavid du Colombier if(c == '\0')
16977dd7cddfSDavid du Colombier goto breakout;
16987dd7cddfSDavid du Colombier headStr++;
16997dd7cddfSDavid du Colombier break;
17007dd7cddfSDavid du Colombier case '(':
17017dd7cddfSDavid du Colombier incom++;
17027dd7cddfSDavid du Colombier if(incom == 1)
17037dd7cddfSDavid du Colombier continue;
17047dd7cddfSDavid du Colombier break;
17057dd7cddfSDavid du Colombier case ')':
17067dd7cddfSDavid du Colombier incom--;
17077dd7cddfSDavid du Colombier if(com && !incom){
17087dd7cddfSDavid du Colombier s[ns] = '\0';
17097dd7cddfSDavid du Colombier return s;
17107dd7cddfSDavid du Colombier }
17117dd7cddfSDavid du Colombier break;
17127dd7cddfSDavid du Colombier default:
17137dd7cddfSDavid du Colombier if(!incom)
17147dd7cddfSDavid du Colombier goto breakout;
17157dd7cddfSDavid du Colombier break;
17167dd7cddfSDavid du Colombier }
17177dd7cddfSDavid du Colombier if(com && incom && (c != ' ' || ns > 0 && s[ns-1] != ' ')){
17187dd7cddfSDavid du Colombier s[ns++] = c;
17197dd7cddfSDavid du Colombier if(ns + 1 >= as){ /* leave room for \c or 0 */
17207dd7cddfSDavid du Colombier as += StrAlloc;
17217dd7cddfSDavid du Colombier s = erealloc(s, as);
17227dd7cddfSDavid du Colombier }
17237dd7cddfSDavid du Colombier }
17247dd7cddfSDavid du Colombier }
17257dd7cddfSDavid du Colombier breakout:;
17267dd7cddfSDavid du Colombier free(s);
17277dd7cddfSDavid du Colombier return nil;
17287dd7cddfSDavid du Colombier }
17297dd7cddfSDavid du Colombier
17307dd7cddfSDavid du Colombier /*
17317dd7cddfSDavid du Colombier * return the next non-white character
17327dd7cddfSDavid du Colombier */
17337dd7cddfSDavid du Colombier static int
headChar(int eat)17347dd7cddfSDavid du Colombier headChar(int eat)
17357dd7cddfSDavid du Colombier {
17367dd7cddfSDavid du Colombier int c;
17377dd7cddfSDavid du Colombier
17387dd7cddfSDavid du Colombier headSkipWhite(0);
17397dd7cddfSDavid du Colombier c = *headStr;
17407dd7cddfSDavid du Colombier if(eat && c != '\0' && c != '\n')
17417dd7cddfSDavid du Colombier headStr++;
17427dd7cddfSDavid du Colombier return c;
17437dd7cddfSDavid du Colombier }
17447dd7cddfSDavid du Colombier
17457dd7cddfSDavid du Colombier static void
headToEnd(void)17467dd7cddfSDavid du Colombier headToEnd(void)
17477dd7cddfSDavid du Colombier {
17487dd7cddfSDavid du Colombier uchar *s;
17497dd7cddfSDavid du Colombier int c;
17507dd7cddfSDavid du Colombier
17517dd7cddfSDavid du Colombier for(;;){
17527dd7cddfSDavid du Colombier s = headStr;
17537dd7cddfSDavid du Colombier c = *s++;
17547dd7cddfSDavid du Colombier while(c == '\r')
17557dd7cddfSDavid du Colombier c = *s++;
17567dd7cddfSDavid du Colombier if(c == '\n'){
17577dd7cddfSDavid du Colombier c = *s++;
17587dd7cddfSDavid du Colombier if(c != ' ' && c != '\t')
17597dd7cddfSDavid du Colombier return;
17607dd7cddfSDavid du Colombier }
17617dd7cddfSDavid du Colombier if(c == '\0')
17627dd7cddfSDavid du Colombier return;
17637dd7cddfSDavid du Colombier headStr = s;
17647dd7cddfSDavid du Colombier }
17657dd7cddfSDavid du Colombier }
17667dd7cddfSDavid du Colombier
17677dd7cddfSDavid du Colombier static void
headSkip(void)17687dd7cddfSDavid du Colombier headSkip(void)
17697dd7cddfSDavid du Colombier {
17707dd7cddfSDavid du Colombier int c;
17717dd7cddfSDavid du Colombier
17727dd7cddfSDavid du Colombier while(c = *headStr){
17737dd7cddfSDavid du Colombier headStr++;
17747dd7cddfSDavid du Colombier if(c == '\n'){
17757dd7cddfSDavid du Colombier c = *headStr;
17767dd7cddfSDavid du Colombier if(c == ' ' || c == '\t')
17777dd7cddfSDavid du Colombier continue;
17787dd7cddfSDavid du Colombier return;
17797dd7cddfSDavid du Colombier }
17807dd7cddfSDavid du Colombier }
17817dd7cddfSDavid du Colombier }
1782