123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572 |
- #include "common.h"
- #include "send.h"
- #include "../smtp/smtp.h"
- #include "../smtp/y.tab.h"
- /* global to this file */
- static Reprog *rfprog;
- static Reprog *fprog;
- #define VMLIMIT (64*1024)
- #define MSGLIMIT (128*1024*1024)
- int received; /* from rfc822.y */
- static String* getstring(Node *p);
- static String* getaddr(Node *p);
- extern int
- default_from(message *mp)
- {
- char *cp, *lp;
- cp = getenv("upasname");
- lp = getlog();
- if(lp == nil)
- return -1;
- if(cp && *cp)
- s_append(mp->sender, cp);
- else
- s_append(mp->sender, lp);
- s_append(mp->date, thedate());
- return 0;
- }
- extern message *
- m_new(void)
- {
- message *mp;
- mp = (message *)mallocz(sizeof(message), 1);
- if (mp == 0) {
- perror("message:");
- exit(1);
- }
- mp->sender = s_new();
- mp->replyaddr = s_new();
- mp->date = s_new();
- mp->body = s_new();
- mp->size = 0;
- mp->fd = -1;
- return mp;
- }
- extern void
- m_free(message *mp)
- {
- if(mp->fd >= 0){
- close(mp->fd);
- sysremove(s_to_c(mp->tmp));
- s_free(mp->tmp);
- }
- s_free(mp->sender);
- s_free(mp->date);
- s_free(mp->body);
- s_free(mp->havefrom);
- s_free(mp->havesender);
- s_free(mp->havereplyto);
- s_free(mp->havesubject);
- free((char *)mp);
- }
- /* read a message into a temp file , return an open fd to it */
- static int
- m_read_to_file(Biobuf *fp, message *mp)
- {
- int fd;
- int n;
- String *file;
- char buf[4*1024];
- file = s_new();
- /*
- * create temp file to be remove on close
- */
- abspath("mtXXXXXX", UPASTMP, file);
- mktemp(s_to_c(file));
- if((fd = syscreate(s_to_c(file), ORDWR|ORCLOSE, 0600))<0){
- s_free(file);
- return -1;
- }
- mp->tmp = file;
- /*
- * read the rest into the temp file
- */
- while((n = Bread(fp, buf, sizeof(buf))) > 0){
- if(write(fd, buf, n) != n){
- close(fd);
- return -1;
- }
- mp->size += n;
- if(mp->size > MSGLIMIT){
- mp->size = -1;
- break;
- }
- }
- mp->fd = fd;
- return 0;
- }
- /* get the first address from a node */
- static String*
- getaddr(Node *p)
- {
- for(; p; p = p->next)
- if(p->s && p->addr)
- return s_copy(s_to_c(p->s));
- return nil;
- }
- /* get the text of a header line minus the field name */
- static String*
- getstring(Node *p)
- {
- String *s;
- s = s_new();
- if(p == nil)
- return s;
- for(p = p->next; p; p = p->next){
- if(p->s){
- s_append(s, s_to_c(p->s));
- }else{
- s_putc(s, p->c);
- s_terminate(s);
- }
- if(p->white)
- s_append(s, s_to_c(p->white));
- }
- return s;
- }
- static char *fieldname[] =
- {
- [WORD-WORD] "WORD",
- [DATE-WORD] "DATE",
- [RESENT_DATE-WORD] "RESENT_DATE",
- [RETURN_PATH-WORD] "RETURN_PATH",
- [FROM-WORD] "FROM",
- [SENDER-WORD] "SENDER",
- [REPLY_TO-WORD] "REPLY_TO",
- [RESENT_FROM-WORD] "RESENT_FROM",
- [RESENT_SENDER-WORD] "RESENT_SENDER",
- [RESENT_REPLY_TO-WORD] "RESENT_REPLY_TO",
- [SUBJECT-WORD] "SUBJECT",
- [TO-WORD] "TO",
- [CC-WORD] "CC",
- [BCC-WORD] "BCC",
- [RESENT_TO-WORD] "RESENT_TO",
- [RESENT_CC-WORD] "RESENT_CC",
- [RESENT_BCC-WORD] "RESENT_BCC",
- [REMOTE-WORD] "REMOTE",
- [PRECEDENCE-WORD] "PRECEDENCE",
- [MIMEVERSION-WORD] "MIMEVERSION",
- [CONTENTTYPE-WORD] "CONTENTTYPE",
- [MESSAGEID-WORD] "MESSAGEID",
- [RECEIVED-WORD] "RECEIVED",
- [MAILER-WORD] "MAILER",
- [BADTOKEN-WORD] "BADTOKEN",
- };
- /* fix 822 addresses */
- static void
- rfc822cruft(message *mp)
- {
- Field *f;
- Node *p;
- String *body, *s;
- char *cp;
- /*
- * parse headers in in-core part
- */
- yyinit(s_to_c(mp->body), s_len(mp->body));
- mp->rfc822headers = 0;
- yyparse();
- mp->rfc822headers = 1;
- mp->received = received;
- /*
- * remove equivalent systems in all addresses
- */
- body = s_new();
- cp = s_to_c(mp->body);
- for(f = firstfield; f; f = f->next){
- if(f->node->c == MIMEVERSION)
- mp->havemime = 1;
- if(f->node->c == FROM)
- mp->havefrom = getaddr(f->node);
- if(f->node->c == SENDER)
- mp->havesender = getaddr(f->node);
- if(f->node->c == REPLY_TO)
- mp->havereplyto = getaddr(f->node);
- if(f->node->c == TO)
- mp->haveto = 1;
- if(f->node->c == DATE)
- mp->havedate = 1;
- if(f->node->c == SUBJECT)
- mp->havesubject = getstring(f->node);
- if(f->node->c == PRECEDENCE && f->node->next && f->node->next->next){
- s = f->node->next->next->s;
- if(s && (strcmp(s_to_c(s), "bulk") == 0
- || strcmp(s_to_c(s), "Bulk") == 0))
- mp->bulk = 1;
- }
- for(p = f->node; p; p = p->next){
- if(p->s){
- if(p->addr){
- cp = skipequiv(s_to_c(p->s));
- s_append(body, cp);
- } else
- s_append(body, s_to_c(p->s));
- }else{
- s_putc(body, p->c);
- s_terminate(body);
- }
- if(p->white)
- s_append(body, s_to_c(p->white));
- cp = p->end+1;
- }
- s_append(body, "\n");
- }
- if(*s_to_c(body) == 0){
- s_free(body);
- return;
- }
- if(*cp != '\n')
- s_append(body, "\n");
- s_memappend(body, cp, s_len(mp->body) - (cp - s_to_c(mp->body)));
- s_terminate(body);
- firstfield = 0;
- mp->size += s_len(body) - s_len(mp->body);
- s_free(mp->body);
- mp->body = body;
- }
- /* read in a message, interpret the 'From' header */
- extern message *
- m_read(Biobuf *fp, int rmail, int interactive)
- {
- message *mp;
- Resub subexp[10];
- char *line;
- int first;
- int n;
- mp = m_new();
- /* parse From lines if remote */
- if (rmail) {
- /* get remote address */
- String *sender=s_new();
- if (rfprog == 0)
- rfprog = regcomp(REMFROMRE);
- first = 1;
- while(s_read_line(fp, s_restart(mp->body)) != 0) {
- memset(subexp, 0, sizeof(subexp));
- if (regexec(rfprog, s_to_c(mp->body), subexp, 10) == 0){
- if(first == 0)
- break;
- if (fprog == 0)
- fprog = regcomp(FROMRE);
- memset(subexp, 0, sizeof(subexp));
- if(regexec(fprog, s_to_c(mp->body), subexp,10) == 0)
- break;
- s_restart(mp->body);
- append_match(subexp, s_restart(sender), SENDERMATCH);
- append_match(subexp, s_restart(mp->date), DATEMATCH);
- break;
- }
- append_match(subexp, s_restart(sender), REMSENDERMATCH);
- append_match(subexp, s_restart(mp->date), REMDATEMATCH);
- if(subexp[REMSYSMATCH].sp!=subexp[REMSYSMATCH].ep){
- append_match(subexp, mp->sender, REMSYSMATCH);
- s_append(mp->sender, "!");
- }
- first = 0;
- }
- s_append(mp->sender, s_to_c(sender));
- s_free(sender);
- }
- if(*s_to_c(mp->sender)=='\0')
- default_from(mp);
- /* if sender address is unreturnable, treat message as bulk mail */
- if(!returnable(s_to_c(mp->sender)))
- mp->bulk = 1;
- /* get body */
- if(interactive && !rmail){
- /* user typing on terminal: terminator == '.' or EOF */
- for(;;) {
- line = s_read_line(fp, mp->body);
- if (line == 0)
- break;
- if (strcmp(".\n", line)==0) {
- mp->body->ptr -= 2;
- *mp->body->ptr = '\0';
- break;
- }
- }
- mp->size = mp->body->ptr - mp->body->base;
- } else {
- /*
- * read up to VMLIMIT bytes (more or less) into main memory.
- * if message is longer put the rest in a tmp file.
- */
- mp->size = mp->body->ptr - mp->body->base;
- n = s_read(fp, mp->body, VMLIMIT);
- if(n < 0){
- perror("m_read");
- exit(1);
- }
- mp->size += n;
- if(n == VMLIMIT){
- if(m_read_to_file(fp, mp) < 0){
- perror("m_read");
- exit(1);
- }
- }
- }
- /*
- * ignore 0 length messages from a terminal
- */
- if (!rmail && mp->size == 0)
- return 0;
- rfc822cruft(mp);
- return mp;
- }
- /* return a piece of message starting at `offset' */
- extern int
- m_get(message *mp, long offset, char **pp)
- {
- static char buf[4*1024];
- /*
- * are we past eof?
- */
- if(offset >= mp->size)
- return 0;
- /*
- * are we in the virtual memory portion?
- */
- if(offset < s_len(mp->body)){
- *pp = mp->body->base + offset;
- return mp->body->ptr - mp->body->base - offset;
- }
- /*
- * read it from the temp file
- */
- offset -= s_len(mp->body);
- if(mp->fd < 0)
- return -1;
- if(seek(mp->fd, offset, 0)<0)
- return -1;
- *pp = buf;
- return read(mp->fd, buf, sizeof buf);
- }
- /* output the message body without ^From escapes */
- static int
- m_noescape(message *mp, Biobuf *fp)
- {
- long offset;
- int n;
- char *p;
- for(offset = 0; offset < mp->size; offset += n){
- n = m_get(mp, offset, &p);
- if(n <= 0){
- Bflush(fp);
- return -1;
- }
- if(Bwrite(fp, p, n) < 0)
- return -1;
- }
- return Bflush(fp);
- }
- /*
- * Output the message body with '^From ' escapes.
- * Ensures that any line starting with a 'From ' gets a ' ' stuck
- * in front of it.
- */
- static int
- m_escape(message *mp, Biobuf *fp)
- {
- char *p, *np;
- char *end;
- long offset;
- int m, n;
- char *start;
- for(offset = 0; offset < mp->size; offset += n){
- n = m_get(mp, offset, &start);
- if(n < 0){
- Bflush(fp);
- return -1;
- }
- p = start;
- for(end = p+n; p < end; p += m){
- np = memchr(p, '\n', end-p);
- if(np == 0){
- Bwrite(fp, p, end-p);
- break;
- }
- m = np - p + 1;
- if(m > 5 && strncmp(p, "From ", 5) == 0)
- Bputc(fp, ' ');
- Bwrite(fp, p, m);
- }
- }
- Bflush(fp);
- return 0;
- }
- static int
- printfrom(message *mp, Biobuf *fp)
- {
- String *s;
- int rv;
- if(!returnable(s_to_c(mp->sender)))
- return Bprint(fp, "From: Postmaster\n");
- s = username(mp->sender);
- if(s) {
- s_append(s, " <");
- s_append(s, s_to_c(mp->sender));
- s_append(s, ">");
- } else {
- s = s_copy(s_to_c(mp->sender));
- }
- s = unescapespecial(s);
- rv = Bprint(fp, "From: %s\n", s_to_c(s));
- s_free(s);
- return rv;
- }
- static char *
- rewritezone(char *z)
- {
- int mindiff;
- char s;
- Tm *tm;
- static char x[7];
- tm = localtime(time(0));
- mindiff = tm->tzoff/60;
- /* if not in my timezone, don't change anything */
- if(strcmp(tm->zone, z) != 0)
- return z;
- if(mindiff < 0){
- s = '-';
- mindiff = -mindiff;
- } else
- s = '+';
- sprint(x, "%c%.2d%.2d", s, mindiff/60, mindiff%60);
- return x;
- }
- int
- isutf8(String *s)
- {
- char *p;
-
- for(p = s_to_c(s); *p; p++)
- if(*p&0x80)
- return 1;
- return 0;
- }
- void
- printutf8mime(Biobuf *b)
- {
- Bprint(b, "MIME-Version: 1.0\n");
- Bprint(b, "Content-Type: text/plain; charset=\"UTF-8\"\n");
- Bprint(b, "Content-Transfer-Encoding: 8bit\n");
- }
- /* output a message */
- extern int
- m_print(message *mp, Biobuf *fp, char *remote, int mbox)
- {
- String *date, *sender;
- char *f[6];
- int n;
- sender = unescapespecial(s_clone(mp->sender));
- if (remote != 0){
- if(print_remote_header(fp,s_to_c(sender),s_to_c(mp->date),remote) < 0){
- s_free(sender);
- return -1;
- }
- } else {
- if(print_header(fp, s_to_c(sender), s_to_c(mp->date)) < 0){
- s_free(sender);
- return -1;
- }
- }
- s_free(sender);
- if(!rmail && !mp->havedate){
- /* add a date: line Date: Sun, 19 Apr 1998 12:27:52 -0400 */
- date = s_copy(s_to_c(mp->date));
- n = getfields(s_to_c(date), f, 6, 1, " \t");
- if(n == 6)
- Bprint(fp, "Date: %s, %s %s %s %s %s\n", f[0], f[2], f[1],
- f[5], f[3], rewritezone(f[4]));
- }
- if(!rmail && !mp->havemime && isutf8(mp->body))
- printutf8mime(fp);
- if(mp->to){
- /* add the to: line */
- if (Bprint(fp, "%s\n", s_to_c(mp->to)) < 0)
- return -1;
- /* add the from: line */
- if (!mp->havefrom && printfrom(mp, fp) < 0)
- return -1;
- if(!mp->rfc822headers && *s_to_c(mp->body) != '\n')
- if (Bprint(fp, "\n") < 0)
- return -1;
- } else if(!rmail){
- /* add the from: line */
- if (!mp->havefrom && printfrom(mp, fp) < 0)
- return -1;
- if(!mp->rfc822headers && *s_to_c(mp->body) != '\n')
- if (Bprint(fp, "\n") < 0)
- return -1;
- }
- if (!mbox)
- return m_noescape(mp, fp);
- return m_escape(mp, fp);
- }
- /* print just the message body */
- extern int
- m_bprint(message *mp, Biobuf *fp)
- {
- return m_noescape(mp, fp);
- }
|