📄 message.c
字号:
#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 intdefault_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 voidm_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 intm_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 voidrfc822cruft(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 intm_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 intm_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 intm_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 intprintfrom(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;}intisutf8(String *s){ char *p; for(p = s_to_c(s); *p; p++) if(*p&0x80) return 1; return 0;}voidprintutf8mime(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 intm_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 intm_bprint(message *mp, Biobuf *fp){ return m_noescape(mp, fp);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -