13e12c5d1SDavid du Colombier #include "common.h"
23e12c5d1SDavid du Colombier #include "send.h"
33e12c5d1SDavid du Colombier
47dd7cddfSDavid du Colombier #include "../smtp/smtp.h"
57dd7cddfSDavid du Colombier #include "../smtp/y.tab.h"
67dd7cddfSDavid du Colombier
73e12c5d1SDavid du Colombier /* global to this file */
83e12c5d1SDavid du Colombier static Reprog *rfprog;
93e12c5d1SDavid du Colombier static Reprog *fprog;
103e12c5d1SDavid du Colombier
113e12c5d1SDavid du Colombier #define VMLIMIT (64*1024)
12219b2ee8SDavid du Colombier #define MSGLIMIT (128*1024*1024)
133e12c5d1SDavid du Colombier
147dd7cddfSDavid du Colombier int received; /* from rfc822.y */
157dd7cddfSDavid du Colombier
169a747e4fSDavid du Colombier static String* getstring(Node *p);
179a747e4fSDavid du Colombier static String* getaddr(Node *p);
189a747e4fSDavid du Colombier
197dd7cddfSDavid du Colombier extern int
default_from(message * mp)203e12c5d1SDavid du Colombier default_from(message *mp)
213e12c5d1SDavid du Colombier {
227dd7cddfSDavid du Colombier char *cp, *lp;
233e12c5d1SDavid du Colombier
243e12c5d1SDavid du Colombier cp = getenv("upasname");
257dd7cddfSDavid du Colombier lp = getlog();
267dd7cddfSDavid du Colombier if(lp == nil)
277dd7cddfSDavid du Colombier return -1;
287dd7cddfSDavid du Colombier
297dd7cddfSDavid du Colombier if(cp && *cp)
303e12c5d1SDavid du Colombier s_append(mp->sender, cp);
313e12c5d1SDavid du Colombier else
327dd7cddfSDavid du Colombier s_append(mp->sender, lp);
333e12c5d1SDavid du Colombier s_append(mp->date, thedate());
347dd7cddfSDavid du Colombier return 0;
353e12c5d1SDavid du Colombier }
363e12c5d1SDavid du Colombier
373e12c5d1SDavid du Colombier extern message *
m_new(void)383e12c5d1SDavid du Colombier m_new(void)
393e12c5d1SDavid du Colombier {
403e12c5d1SDavid du Colombier message *mp;
413e12c5d1SDavid du Colombier
4268060204SDavid du Colombier mp = (message *)mallocz(sizeof(message), 1);
433e12c5d1SDavid du Colombier if (mp == 0) {
443e12c5d1SDavid du Colombier perror("message:");
453e12c5d1SDavid du Colombier exit(1);
463e12c5d1SDavid du Colombier }
473e12c5d1SDavid du Colombier mp->sender = s_new();
483e12c5d1SDavid du Colombier mp->replyaddr = s_new();
493e12c5d1SDavid du Colombier mp->date = s_new();
503e12c5d1SDavid du Colombier mp->body = s_new();
513e12c5d1SDavid du Colombier mp->size = 0;
523e12c5d1SDavid du Colombier mp->fd = -1;
533e12c5d1SDavid du Colombier return mp;
543e12c5d1SDavid du Colombier }
553e12c5d1SDavid du Colombier
563e12c5d1SDavid du Colombier extern void
m_free(message * mp)573e12c5d1SDavid du Colombier m_free(message *mp)
583e12c5d1SDavid du Colombier {
593e12c5d1SDavid du Colombier if(mp->fd >= 0){
603e12c5d1SDavid du Colombier close(mp->fd);
617dd7cddfSDavid du Colombier sysremove(s_to_c(mp->tmp));
623e12c5d1SDavid du Colombier s_free(mp->tmp);
633e12c5d1SDavid du Colombier }
643e12c5d1SDavid du Colombier s_free(mp->sender);
653e12c5d1SDavid du Colombier s_free(mp->date);
663e12c5d1SDavid du Colombier s_free(mp->body);
679a747e4fSDavid du Colombier s_free(mp->havefrom);
689a747e4fSDavid du Colombier s_free(mp->havesender);
699a747e4fSDavid du Colombier s_free(mp->havereplyto);
709a747e4fSDavid du Colombier s_free(mp->havesubject);
713e12c5d1SDavid du Colombier free((char *)mp);
723e12c5d1SDavid du Colombier }
733e12c5d1SDavid du Colombier
74*c6569576SDavid du Colombier /* read a message into a temp file, return an open fd to it in mp->fd */
753e12c5d1SDavid du Colombier static int
m_read_to_file(Biobuf * fp,message * mp)763e12c5d1SDavid du Colombier m_read_to_file(Biobuf *fp, message *mp)
773e12c5d1SDavid du Colombier {
783e12c5d1SDavid du Colombier int fd;
793e12c5d1SDavid du Colombier int n;
803e12c5d1SDavid du Colombier String *file;
813e12c5d1SDavid du Colombier char buf[4*1024];
823e12c5d1SDavid du Colombier
833e12c5d1SDavid du Colombier file = s_new();
843e12c5d1SDavid du Colombier /*
85*c6569576SDavid du Colombier * create temp file to be removed on close
863e12c5d1SDavid du Colombier */
877dd7cddfSDavid du Colombier abspath("mtXXXXXX", UPASTMP, file);
883e12c5d1SDavid du Colombier mktemp(s_to_c(file));
897dd7cddfSDavid du Colombier if((fd = syscreate(s_to_c(file), ORDWR|ORCLOSE, 0600))<0){
907dd7cddfSDavid du Colombier s_free(file);
913e12c5d1SDavid du Colombier return -1;
923e12c5d1SDavid du Colombier }
933e12c5d1SDavid du Colombier mp->tmp = file;
943e12c5d1SDavid du Colombier
953e12c5d1SDavid du Colombier /*
963e12c5d1SDavid du Colombier * read the rest into the temp file
973e12c5d1SDavid du Colombier */
983e12c5d1SDavid du Colombier while((n = Bread(fp, buf, sizeof(buf))) > 0){
993e12c5d1SDavid du Colombier if(write(fd, buf, n) != n){
1003e12c5d1SDavid du Colombier close(fd);
1013e12c5d1SDavid du Colombier return -1;
1023e12c5d1SDavid du Colombier }
1033e12c5d1SDavid du Colombier mp->size += n;
1043e12c5d1SDavid du Colombier if(mp->size > MSGLIMIT){
1053e12c5d1SDavid du Colombier mp->size = -1;
1063e12c5d1SDavid du Colombier break;
1073e12c5d1SDavid du Colombier }
1083e12c5d1SDavid du Colombier }
1093e12c5d1SDavid du Colombier
1103e12c5d1SDavid du Colombier mp->fd = fd;
1113e12c5d1SDavid du Colombier return 0;
1123e12c5d1SDavid du Colombier }
1133e12c5d1SDavid du Colombier
1149a747e4fSDavid du Colombier /* get the first address from a node */
1159a747e4fSDavid du Colombier static String*
getaddr(Node * p)1169a747e4fSDavid du Colombier getaddr(Node *p)
1179a747e4fSDavid du Colombier {
1189a747e4fSDavid du Colombier for(; p; p = p->next)
1199a747e4fSDavid du Colombier if(p->s && p->addr)
1209a747e4fSDavid du Colombier return s_copy(s_to_c(p->s));
121ec46fab0SDavid du Colombier return nil;
1229a747e4fSDavid du Colombier }
1239a747e4fSDavid du Colombier
1249a747e4fSDavid du Colombier /* get the text of a header line minus the field name */
1259a747e4fSDavid du Colombier static String*
getstring(Node * p)1269a747e4fSDavid du Colombier getstring(Node *p)
1279a747e4fSDavid du Colombier {
1289a747e4fSDavid du Colombier String *s;
1299a747e4fSDavid du Colombier
1309a747e4fSDavid du Colombier s = s_new();
1319a747e4fSDavid du Colombier if(p == nil)
1329a747e4fSDavid du Colombier return s;
1339a747e4fSDavid du Colombier
1349a747e4fSDavid du Colombier for(p = p->next; p; p = p->next){
1359a747e4fSDavid du Colombier if(p->s){
1369a747e4fSDavid du Colombier s_append(s, s_to_c(p->s));
1379a747e4fSDavid du Colombier }else{
1389a747e4fSDavid du Colombier s_putc(s, p->c);
1399a747e4fSDavid du Colombier s_terminate(s);
1409a747e4fSDavid du Colombier }
1419a747e4fSDavid du Colombier if(p->white)
1429a747e4fSDavid du Colombier s_append(s, s_to_c(p->white));
1439a747e4fSDavid du Colombier }
1449a747e4fSDavid du Colombier return s;
1459a747e4fSDavid du Colombier }
1469a747e4fSDavid du Colombier
1479a747e4fSDavid du Colombier static char *fieldname[] =
1489a747e4fSDavid du Colombier {
1499a747e4fSDavid du Colombier [WORD-WORD] "WORD",
1509a747e4fSDavid du Colombier [DATE-WORD] "DATE",
1519a747e4fSDavid du Colombier [RESENT_DATE-WORD] "RESENT_DATE",
1529a747e4fSDavid du Colombier [RETURN_PATH-WORD] "RETURN_PATH",
1539a747e4fSDavid du Colombier [FROM-WORD] "FROM",
1549a747e4fSDavid du Colombier [SENDER-WORD] "SENDER",
1559a747e4fSDavid du Colombier [REPLY_TO-WORD] "REPLY_TO",
1569a747e4fSDavid du Colombier [RESENT_FROM-WORD] "RESENT_FROM",
1579a747e4fSDavid du Colombier [RESENT_SENDER-WORD] "RESENT_SENDER",
1589a747e4fSDavid du Colombier [RESENT_REPLY_TO-WORD] "RESENT_REPLY_TO",
1599a747e4fSDavid du Colombier [SUBJECT-WORD] "SUBJECT",
1609a747e4fSDavid du Colombier [TO-WORD] "TO",
1619a747e4fSDavid du Colombier [CC-WORD] "CC",
1629a747e4fSDavid du Colombier [BCC-WORD] "BCC",
1639a747e4fSDavid du Colombier [RESENT_TO-WORD] "RESENT_TO",
1649a747e4fSDavid du Colombier [RESENT_CC-WORD] "RESENT_CC",
1659a747e4fSDavid du Colombier [RESENT_BCC-WORD] "RESENT_BCC",
1669a747e4fSDavid du Colombier [REMOTE-WORD] "REMOTE",
1679a747e4fSDavid du Colombier [PRECEDENCE-WORD] "PRECEDENCE",
1689a747e4fSDavid du Colombier [MIMEVERSION-WORD] "MIMEVERSION",
1699a747e4fSDavid du Colombier [CONTENTTYPE-WORD] "CONTENTTYPE",
1709a747e4fSDavid du Colombier [MESSAGEID-WORD] "MESSAGEID",
1719a747e4fSDavid du Colombier [RECEIVED-WORD] "RECEIVED",
1729a747e4fSDavid du Colombier [MAILER-WORD] "MAILER",
1739a747e4fSDavid du Colombier [BADTOKEN-WORD] "BADTOKEN",
1749a747e4fSDavid du Colombier };
1759a747e4fSDavid du Colombier
1767dd7cddfSDavid du Colombier /* fix 822 addresses */
1777dd7cddfSDavid du Colombier static void
rfc822cruft(message * mp)1787dd7cddfSDavid du Colombier rfc822cruft(message *mp)
1797dd7cddfSDavid du Colombier {
1807dd7cddfSDavid du Colombier Field *f;
1817dd7cddfSDavid du Colombier Node *p;
1827dd7cddfSDavid du Colombier String *body, *s;
1837dd7cddfSDavid du Colombier char *cp;
1847dd7cddfSDavid du Colombier
1857dd7cddfSDavid du Colombier /*
1867dd7cddfSDavid du Colombier * parse headers in in-core part
1877dd7cddfSDavid du Colombier */
1889a747e4fSDavid du Colombier yyinit(s_to_c(mp->body), s_len(mp->body));
1897dd7cddfSDavid du Colombier mp->rfc822headers = 0;
1907dd7cddfSDavid du Colombier yyparse();
1917dd7cddfSDavid du Colombier mp->rfc822headers = 1;
1927dd7cddfSDavid du Colombier mp->received = received;
1937dd7cddfSDavid du Colombier
1947dd7cddfSDavid du Colombier /*
1957dd7cddfSDavid du Colombier * remove equivalent systems in all addresses
1967dd7cddfSDavid du Colombier */
1977dd7cddfSDavid du Colombier body = s_new();
1987dd7cddfSDavid du Colombier cp = s_to_c(mp->body);
1997dd7cddfSDavid du Colombier for(f = firstfield; f; f = f->next){
2007dd7cddfSDavid du Colombier if(f->node->c == MIMEVERSION)
2017dd7cddfSDavid du Colombier mp->havemime = 1;
2027dd7cddfSDavid du Colombier if(f->node->c == FROM)
2039a747e4fSDavid du Colombier mp->havefrom = getaddr(f->node);
2049a747e4fSDavid du Colombier if(f->node->c == SENDER)
2059a747e4fSDavid du Colombier mp->havesender = getaddr(f->node);
2069a747e4fSDavid du Colombier if(f->node->c == REPLY_TO)
2079a747e4fSDavid du Colombier mp->havereplyto = getaddr(f->node);
2087dd7cddfSDavid du Colombier if(f->node->c == TO)
2097dd7cddfSDavid du Colombier mp->haveto = 1;
2107dd7cddfSDavid du Colombier if(f->node->c == DATE)
2117dd7cddfSDavid du Colombier mp->havedate = 1;
2127dd7cddfSDavid du Colombier if(f->node->c == SUBJECT)
2139a747e4fSDavid du Colombier mp->havesubject = getstring(f->node);
2147dd7cddfSDavid du Colombier if(f->node->c == PRECEDENCE && f->node->next && f->node->next->next){
2157dd7cddfSDavid du Colombier s = f->node->next->next->s;
2167dd7cddfSDavid du Colombier if(s && (strcmp(s_to_c(s), "bulk") == 0
2177dd7cddfSDavid du Colombier || strcmp(s_to_c(s), "Bulk") == 0))
2187dd7cddfSDavid du Colombier mp->bulk = 1;
2197dd7cddfSDavid du Colombier }
2207dd7cddfSDavid du Colombier for(p = f->node; p; p = p->next){
2217dd7cddfSDavid du Colombier if(p->s){
2227dd7cddfSDavid du Colombier if(p->addr){
2237dd7cddfSDavid du Colombier cp = skipequiv(s_to_c(p->s));
2247dd7cddfSDavid du Colombier s_append(body, cp);
2257dd7cddfSDavid du Colombier } else
2267dd7cddfSDavid du Colombier s_append(body, s_to_c(p->s));
2277dd7cddfSDavid du Colombier }else{
2287dd7cddfSDavid du Colombier s_putc(body, p->c);
2297dd7cddfSDavid du Colombier s_terminate(body);
2307dd7cddfSDavid du Colombier }
2317dd7cddfSDavid du Colombier if(p->white)
2327dd7cddfSDavid du Colombier s_append(body, s_to_c(p->white));
2337dd7cddfSDavid du Colombier cp = p->end+1;
2347dd7cddfSDavid du Colombier }
2357dd7cddfSDavid du Colombier s_append(body, "\n");
2367dd7cddfSDavid du Colombier }
2377dd7cddfSDavid du Colombier
2387dd7cddfSDavid du Colombier if(*s_to_c(body) == 0){
2397dd7cddfSDavid du Colombier s_free(body);
2407dd7cddfSDavid du Colombier return;
2417dd7cddfSDavid du Colombier }
2427dd7cddfSDavid du Colombier
2437dd7cddfSDavid du Colombier if(*cp != '\n')
2447dd7cddfSDavid du Colombier s_append(body, "\n");
2457dd7cddfSDavid du Colombier s_memappend(body, cp, s_len(mp->body) - (cp - s_to_c(mp->body)));
2467dd7cddfSDavid du Colombier s_terminate(body);
2477dd7cddfSDavid du Colombier
2487dd7cddfSDavid du Colombier firstfield = 0;
2497dd7cddfSDavid du Colombier mp->size += s_len(body) - s_len(mp->body);
2507dd7cddfSDavid du Colombier s_free(mp->body);
2517dd7cddfSDavid du Colombier mp->body = body;
2527dd7cddfSDavid du Colombier }
2537dd7cddfSDavid du Colombier
2543e12c5d1SDavid du Colombier /* read in a message, interpret the 'From' header */
2553e12c5d1SDavid du Colombier extern message *
m_read(Biobuf * fp,int rmail,int interactive)2567dd7cddfSDavid du Colombier m_read(Biobuf *fp, int rmail, int interactive)
2573e12c5d1SDavid du Colombier {
2583e12c5d1SDavid du Colombier message *mp;
2593e12c5d1SDavid du Colombier Resub subexp[10];
2607dd7cddfSDavid du Colombier char *line;
2613e12c5d1SDavid du Colombier int first;
2623e12c5d1SDavid du Colombier int n;
2633e12c5d1SDavid du Colombier
2643e12c5d1SDavid du Colombier mp = m_new();
2653e12c5d1SDavid du Colombier
2663e12c5d1SDavid du Colombier /* parse From lines if remote */
2673e12c5d1SDavid du Colombier if (rmail) {
2683e12c5d1SDavid du Colombier /* get remote address */
2693e12c5d1SDavid du Colombier String *sender=s_new();
2703e12c5d1SDavid du Colombier
2713e12c5d1SDavid du Colombier if (rfprog == 0)
2723e12c5d1SDavid du Colombier rfprog = regcomp(REMFROMRE);
2733e12c5d1SDavid du Colombier first = 1;
2743e12c5d1SDavid du Colombier while(s_read_line(fp, s_restart(mp->body)) != 0) {
2753e12c5d1SDavid du Colombier memset(subexp, 0, sizeof(subexp));
2763e12c5d1SDavid du Colombier if (regexec(rfprog, s_to_c(mp->body), subexp, 10) == 0){
2773e12c5d1SDavid du Colombier if(first == 0)
2783e12c5d1SDavid du Colombier break;
2793e12c5d1SDavid du Colombier if (fprog == 0)
2803e12c5d1SDavid du Colombier fprog = regcomp(FROMRE);
2813e12c5d1SDavid du Colombier memset(subexp, 0, sizeof(subexp));
2823e12c5d1SDavid du Colombier if(regexec(fprog, s_to_c(mp->body), subexp,10) == 0)
2833e12c5d1SDavid du Colombier break;
2849a747e4fSDavid du Colombier s_restart(mp->body);
2853e12c5d1SDavid du Colombier append_match(subexp, s_restart(sender), SENDERMATCH);
2863e12c5d1SDavid du Colombier append_match(subexp, s_restart(mp->date), DATEMATCH);
2873e12c5d1SDavid du Colombier break;
2883e12c5d1SDavid du Colombier }
2893e12c5d1SDavid du Colombier append_match(subexp, s_restart(sender), REMSENDERMATCH);
2903e12c5d1SDavid du Colombier append_match(subexp, s_restart(mp->date), REMDATEMATCH);
2913e12c5d1SDavid du Colombier if(subexp[REMSYSMATCH].sp!=subexp[REMSYSMATCH].ep){
2923e12c5d1SDavid du Colombier append_match(subexp, mp->sender, REMSYSMATCH);
2933e12c5d1SDavid du Colombier s_append(mp->sender, "!");
2943e12c5d1SDavid du Colombier }
2953e12c5d1SDavid du Colombier first = 0;
2963e12c5d1SDavid du Colombier }
2973e12c5d1SDavid du Colombier s_append(mp->sender, s_to_c(sender));
2987dd7cddfSDavid du Colombier
2993e12c5d1SDavid du Colombier s_free(sender);
3003e12c5d1SDavid du Colombier }
3013e12c5d1SDavid du Colombier if(*s_to_c(mp->sender)=='\0')
3023e12c5d1SDavid du Colombier default_from(mp);
3033e12c5d1SDavid du Colombier
3047dd7cddfSDavid du Colombier /* if sender address is unreturnable, treat message as bulk mail */
3057dd7cddfSDavid du Colombier if(!returnable(s_to_c(mp->sender)))
3067dd7cddfSDavid du Colombier mp->bulk = 1;
3077dd7cddfSDavid du Colombier
3087dd7cddfSDavid du Colombier /* get body */
3097dd7cddfSDavid du Colombier if(interactive && !rmail){
3107dd7cddfSDavid du Colombier /* user typing on terminal: terminator == '.' or EOF */
3117dd7cddfSDavid du Colombier for(;;) {
3127dd7cddfSDavid du Colombier line = s_read_line(fp, mp->body);
3137dd7cddfSDavid du Colombier if (line == 0)
3147dd7cddfSDavid du Colombier break;
3157dd7cddfSDavid du Colombier if (strcmp(".\n", line)==0) {
3167dd7cddfSDavid du Colombier mp->body->ptr -= 2;
3177dd7cddfSDavid du Colombier *mp->body->ptr = '\0';
3187dd7cddfSDavid du Colombier break;
3197dd7cddfSDavid du Colombier }
3207dd7cddfSDavid du Colombier }
3217dd7cddfSDavid du Colombier mp->size = mp->body->ptr - mp->body->base;
3227dd7cddfSDavid du Colombier } else {
3233e12c5d1SDavid du Colombier /*
3243e12c5d1SDavid du Colombier * read up to VMLIMIT bytes (more or less) into main memory.
3253e12c5d1SDavid du Colombier * if message is longer put the rest in a tmp file.
3263e12c5d1SDavid du Colombier */
3273e12c5d1SDavid du Colombier mp->size = mp->body->ptr - mp->body->base;
3283e12c5d1SDavid du Colombier n = s_read(fp, mp->body, VMLIMIT);
3293e12c5d1SDavid du Colombier if(n < 0){
3303e12c5d1SDavid du Colombier perror("m_read");
3313e12c5d1SDavid du Colombier exit(1);
3323e12c5d1SDavid du Colombier }
3333e12c5d1SDavid du Colombier mp->size += n;
3343e12c5d1SDavid du Colombier if(n == VMLIMIT){
3353e12c5d1SDavid du Colombier if(m_read_to_file(fp, mp) < 0){
3363e12c5d1SDavid du Colombier perror("m_read");
3373e12c5d1SDavid du Colombier exit(1);
3383e12c5d1SDavid du Colombier }
3393e12c5d1SDavid du Colombier }
3403e12c5d1SDavid du Colombier
3417dd7cddfSDavid du Colombier }
3427dd7cddfSDavid du Colombier
3433e12c5d1SDavid du Colombier /*
3443e12c5d1SDavid du Colombier * ignore 0 length messages from a terminal
3453e12c5d1SDavid du Colombier */
346219b2ee8SDavid du Colombier if (!rmail && mp->size == 0)
3473e12c5d1SDavid du Colombier return 0;
3483e12c5d1SDavid du Colombier
3497dd7cddfSDavid du Colombier rfc822cruft(mp);
3507dd7cddfSDavid du Colombier
3513e12c5d1SDavid du Colombier return mp;
3523e12c5d1SDavid du Colombier }
3533e12c5d1SDavid du Colombier
3543e12c5d1SDavid du Colombier /* return a piece of message starting at `offset' */
3553e12c5d1SDavid du Colombier extern int
m_get(message * mp,long offset,char ** pp)3563e12c5d1SDavid du Colombier m_get(message *mp, long offset, char **pp)
3573e12c5d1SDavid du Colombier {
3583e12c5d1SDavid du Colombier static char buf[4*1024];
3593e12c5d1SDavid du Colombier
3603e12c5d1SDavid du Colombier /*
3613e12c5d1SDavid du Colombier * are we past eof?
3623e12c5d1SDavid du Colombier */
3633e12c5d1SDavid du Colombier if(offset >= mp->size)
3643e12c5d1SDavid du Colombier return 0;
3653e12c5d1SDavid du Colombier
3663e12c5d1SDavid du Colombier /*
3673e12c5d1SDavid du Colombier * are we in the virtual memory portion?
3683e12c5d1SDavid du Colombier */
3697dd7cddfSDavid du Colombier if(offset < s_len(mp->body)){
3703e12c5d1SDavid du Colombier *pp = mp->body->base + offset;
3713e12c5d1SDavid du Colombier return mp->body->ptr - mp->body->base - offset;
3723e12c5d1SDavid du Colombier }
3733e12c5d1SDavid du Colombier
3743e12c5d1SDavid du Colombier /*
3753e12c5d1SDavid du Colombier * read it from the temp file
3763e12c5d1SDavid du Colombier */
3777dd7cddfSDavid du Colombier offset -= s_len(mp->body);
3783e12c5d1SDavid du Colombier if(mp->fd < 0)
3793e12c5d1SDavid du Colombier return -1;
3803e12c5d1SDavid du Colombier if(seek(mp->fd, offset, 0)<0)
3813e12c5d1SDavid du Colombier return -1;
3823e12c5d1SDavid du Colombier *pp = buf;
3833e12c5d1SDavid du Colombier return read(mp->fd, buf, sizeof buf);
3843e12c5d1SDavid du Colombier }
3853e12c5d1SDavid du Colombier
3863e12c5d1SDavid du Colombier /* output the message body without ^From escapes */
3873e12c5d1SDavid du Colombier static int
m_noescape(message * mp,Biobuf * fp)3883e12c5d1SDavid du Colombier m_noescape(message *mp, Biobuf *fp)
3893e12c5d1SDavid du Colombier {
3903e12c5d1SDavid du Colombier long offset;
3913e12c5d1SDavid du Colombier int n;
3923e12c5d1SDavid du Colombier char *p;
3933e12c5d1SDavid du Colombier
3943e12c5d1SDavid du Colombier for(offset = 0; offset < mp->size; offset += n){
3953e12c5d1SDavid du Colombier n = m_get(mp, offset, &p);
3963e12c5d1SDavid du Colombier if(n <= 0){
3973e12c5d1SDavid du Colombier Bflush(fp);
3983e12c5d1SDavid du Colombier return -1;
3993e12c5d1SDavid du Colombier }
4003e12c5d1SDavid du Colombier if(Bwrite(fp, p, n) < 0)
4013e12c5d1SDavid du Colombier return -1;
4023e12c5d1SDavid du Colombier }
4033e12c5d1SDavid du Colombier return Bflush(fp);
4043e12c5d1SDavid du Colombier }
4053e12c5d1SDavid du Colombier
4063e12c5d1SDavid du Colombier /*
407219b2ee8SDavid du Colombier * Output the message body with '^From ' escapes.
408219b2ee8SDavid du Colombier * Ensures that any line starting with a 'From ' gets a ' ' stuck
4093e12c5d1SDavid du Colombier * in front of it.
4103e12c5d1SDavid du Colombier */
4113e12c5d1SDavid du Colombier static int
m_escape(message * mp,Biobuf * fp)4123e12c5d1SDavid du Colombier m_escape(message *mp, Biobuf *fp)
4133e12c5d1SDavid du Colombier {
414219b2ee8SDavid du Colombier char *p, *np;
415219b2ee8SDavid du Colombier char *end;
4163e12c5d1SDavid du Colombier long offset;
417219b2ee8SDavid du Colombier int m, n;
4183e12c5d1SDavid du Colombier char *start;
4193e12c5d1SDavid du Colombier
4203e12c5d1SDavid du Colombier for(offset = 0; offset < mp->size; offset += n){
4213e12c5d1SDavid du Colombier n = m_get(mp, offset, &start);
4223e12c5d1SDavid du Colombier if(n < 0){
4233e12c5d1SDavid du Colombier Bflush(fp);
4243e12c5d1SDavid du Colombier return -1;
4253e12c5d1SDavid du Colombier }
4263e12c5d1SDavid du Colombier
4273e12c5d1SDavid du Colombier p = start;
428219b2ee8SDavid du Colombier for(end = p+n; p < end; p += m){
429219b2ee8SDavid du Colombier np = memchr(p, '\n', end-p);
430219b2ee8SDavid du Colombier if(np == 0){
431219b2ee8SDavid du Colombier Bwrite(fp, p, end-p);
4323e12c5d1SDavid du Colombier break;
4333e12c5d1SDavid du Colombier }
434219b2ee8SDavid du Colombier m = np - p + 1;
435219b2ee8SDavid du Colombier if(m > 5 && strncmp(p, "From ", 5) == 0)
436219b2ee8SDavid du Colombier Bputc(fp, ' ');
437219b2ee8SDavid du Colombier Bwrite(fp, p, m);
4383e12c5d1SDavid du Colombier }
4393e12c5d1SDavid du Colombier }
4403e12c5d1SDavid du Colombier Bflush(fp);
4413e12c5d1SDavid du Colombier return 0;
4423e12c5d1SDavid du Colombier }
4433e12c5d1SDavid du Colombier
4447dd7cddfSDavid du Colombier static int
printfrom(message * mp,Biobuf * fp)4457dd7cddfSDavid du Colombier printfrom(message *mp, Biobuf *fp)
4467dd7cddfSDavid du Colombier {
4477dd7cddfSDavid du Colombier String *s;
4487dd7cddfSDavid du Colombier int rv;
4497dd7cddfSDavid du Colombier
4507dd7cddfSDavid du Colombier if(!returnable(s_to_c(mp->sender)))
4517dd7cddfSDavid du Colombier return Bprint(fp, "From: Postmaster\n");
4527dd7cddfSDavid du Colombier
4537dd7cddfSDavid du Colombier s = username(mp->sender);
4547dd7cddfSDavid du Colombier if(s) {
4557dd7cddfSDavid du Colombier s_append(s, " <");
4567dd7cddfSDavid du Colombier s_append(s, s_to_c(mp->sender));
4577dd7cddfSDavid du Colombier s_append(s, ">");
4587dd7cddfSDavid du Colombier } else {
4597dd7cddfSDavid du Colombier s = s_copy(s_to_c(mp->sender));
4607dd7cddfSDavid du Colombier }
4617dd7cddfSDavid du Colombier s = unescapespecial(s);
4627dd7cddfSDavid du Colombier rv = Bprint(fp, "From: %s\n", s_to_c(s));
4637dd7cddfSDavid du Colombier s_free(s);
4647dd7cddfSDavid du Colombier return rv;
4657dd7cddfSDavid du Colombier }
4667dd7cddfSDavid du Colombier
4677dd7cddfSDavid du Colombier static char *
rewritezone(char * z)4687dd7cddfSDavid du Colombier rewritezone(char *z)
4697dd7cddfSDavid du Colombier {
4707dd7cddfSDavid du Colombier int mindiff;
4717dd7cddfSDavid du Colombier char s;
4727dd7cddfSDavid du Colombier Tm *tm;
4737dd7cddfSDavid du Colombier static char x[7];
4747dd7cddfSDavid du Colombier
4757dd7cddfSDavid du Colombier tm = localtime(time(0));
4767dd7cddfSDavid du Colombier mindiff = tm->tzoff/60;
4777dd7cddfSDavid du Colombier
4787dd7cddfSDavid du Colombier /* if not in my timezone, don't change anything */
4797dd7cddfSDavid du Colombier if(strcmp(tm->zone, z) != 0)
4807dd7cddfSDavid du Colombier return z;
4817dd7cddfSDavid du Colombier
4827dd7cddfSDavid du Colombier if(mindiff < 0){
4837dd7cddfSDavid du Colombier s = '-';
4847dd7cddfSDavid du Colombier mindiff = -mindiff;
4857dd7cddfSDavid du Colombier } else
4867dd7cddfSDavid du Colombier s = '+';
4877dd7cddfSDavid du Colombier
4887dd7cddfSDavid du Colombier sprint(x, "%c%.2d%.2d", s, mindiff/60, mindiff%60);
4897dd7cddfSDavid du Colombier return x;
4907dd7cddfSDavid du Colombier }
4917dd7cddfSDavid du Colombier
4927dd7cddfSDavid du Colombier int
isutf8(String * s)4937dd7cddfSDavid du Colombier isutf8(String *s)
4947dd7cddfSDavid du Colombier {
4957dd7cddfSDavid du Colombier char *p;
4967dd7cddfSDavid du Colombier
4977dd7cddfSDavid du Colombier for(p = s_to_c(s); *p; p++)
4987dd7cddfSDavid du Colombier if(*p&0x80)
4997dd7cddfSDavid du Colombier return 1;
5007dd7cddfSDavid du Colombier return 0;
5017dd7cddfSDavid du Colombier }
5027dd7cddfSDavid du Colombier
5037dd7cddfSDavid du Colombier void
printutf8mime(Biobuf * b)5047dd7cddfSDavid du Colombier printutf8mime(Biobuf *b)
5057dd7cddfSDavid du Colombier {
5067dd7cddfSDavid du Colombier Bprint(b, "MIME-Version: 1.0\n");
5077dd7cddfSDavid du Colombier Bprint(b, "Content-Type: text/plain; charset=\"UTF-8\"\n");
5087dd7cddfSDavid du Colombier Bprint(b, "Content-Transfer-Encoding: 8bit\n");
5097dd7cddfSDavid du Colombier }
5107dd7cddfSDavid du Colombier
5113e12c5d1SDavid du Colombier /* output a message */
5123e12c5d1SDavid du Colombier extern int
m_print(message * mp,Biobuf * fp,char * remote,int mbox)5133e12c5d1SDavid du Colombier m_print(message *mp, Biobuf *fp, char *remote, int mbox)
5143e12c5d1SDavid du Colombier {
5157dd7cddfSDavid du Colombier String *date, *sender;
5167dd7cddfSDavid du Colombier char *f[6];
5177dd7cddfSDavid du Colombier int n;
5187dd7cddfSDavid du Colombier
5197dd7cddfSDavid du Colombier sender = unescapespecial(s_clone(mp->sender));
5207dd7cddfSDavid du Colombier
5213e12c5d1SDavid du Colombier if (remote != 0){
5227dd7cddfSDavid du Colombier if(print_remote_header(fp,s_to_c(sender),s_to_c(mp->date),remote) < 0){
5237dd7cddfSDavid du Colombier s_free(sender);
5243e12c5d1SDavid du Colombier return -1;
5257dd7cddfSDavid du Colombier }
5263e12c5d1SDavid du Colombier } else {
5277dd7cddfSDavid du Colombier if(print_header(fp, s_to_c(sender), s_to_c(mp->date)) < 0){
5287dd7cddfSDavid du Colombier s_free(sender);
5297dd7cddfSDavid du Colombier return -1;
5307dd7cddfSDavid du Colombier }
5317dd7cddfSDavid du Colombier }
5327dd7cddfSDavid du Colombier s_free(sender);
5337dd7cddfSDavid du Colombier if(!rmail && !mp->havedate){
5347dd7cddfSDavid du Colombier /* add a date: line Date: Sun, 19 Apr 1998 12:27:52 -0400 */
5357dd7cddfSDavid du Colombier date = s_copy(s_to_c(mp->date));
5367dd7cddfSDavid du Colombier n = getfields(s_to_c(date), f, 6, 1, " \t");
5377dd7cddfSDavid du Colombier if(n == 6)
5387dd7cddfSDavid du Colombier Bprint(fp, "Date: %s, %s %s %s %s %s\n", f[0], f[2], f[1],
5397dd7cddfSDavid du Colombier f[5], f[3], rewritezone(f[4]));
5407dd7cddfSDavid du Colombier }
5417dd7cddfSDavid du Colombier if(!rmail && !mp->havemime && isutf8(mp->body))
5427dd7cddfSDavid du Colombier printutf8mime(fp);
5437dd7cddfSDavid du Colombier if(mp->to){
5447dd7cddfSDavid du Colombier /* add the to: line */
5457dd7cddfSDavid du Colombier if (Bprint(fp, "%s\n", s_to_c(mp->to)) < 0)
5467dd7cddfSDavid du Colombier return -1;
5477dd7cddfSDavid du Colombier /* add the from: line */
5487dd7cddfSDavid du Colombier if (!mp->havefrom && printfrom(mp, fp) < 0)
5497dd7cddfSDavid du Colombier return -1;
5507dd7cddfSDavid du Colombier if(!mp->rfc822headers && *s_to_c(mp->body) != '\n')
5517dd7cddfSDavid du Colombier if (Bprint(fp, "\n") < 0)
5527dd7cddfSDavid du Colombier return -1;
5537dd7cddfSDavid du Colombier } else if(!rmail){
5547dd7cddfSDavid du Colombier /* add the from: line */
5557dd7cddfSDavid du Colombier if (!mp->havefrom && printfrom(mp, fp) < 0)
5567dd7cddfSDavid du Colombier return -1;
5577dd7cddfSDavid du Colombier if(!mp->rfc822headers && *s_to_c(mp->body) != '\n')
5587dd7cddfSDavid du Colombier if (Bprint(fp, "\n") < 0)
5593e12c5d1SDavid du Colombier return -1;
5603e12c5d1SDavid du Colombier }
5613e12c5d1SDavid du Colombier
5623e12c5d1SDavid du Colombier if (!mbox)
5633e12c5d1SDavid du Colombier return m_noescape(mp, fp);
5643e12c5d1SDavid du Colombier return m_escape(mp, fp);
5653e12c5d1SDavid du Colombier }
5663e12c5d1SDavid du Colombier
5673e12c5d1SDavid du Colombier /* print just the message body */
5683e12c5d1SDavid du Colombier extern int
m_bprint(message * mp,Biobuf * fp)5693e12c5d1SDavid du Colombier m_bprint(message *mp, Biobuf *fp)
5703e12c5d1SDavid du Colombier {
5713e12c5d1SDavid du Colombier return m_noescape(mp, fp);
5723e12c5d1SDavid du Colombier }
573