📄 smtp.c
字号:
return Giveup; default: return Retry; } return 0;}static char hex[] = "0123456789abcdef";/* * send the damn thing */char *data(String *from, Biobuf *b){ char *buf, *cp; int i, n, nbytes, bufsize, eof, r; String *fromline; char errmsg[Errlen]; char id[40]; /* * input the header. */ buf = malloc(1); if(buf == 0){ s_append(s_restart(reply), "out of memory"); return Retry; } n = 0; eof = 0; for(;;){ cp = Brdline(b, '\n'); if(cp == nil){ eof = 1; break; } nbytes = Blinelen(b); buf = realloc(buf, n+nbytes+1); if(buf == 0){ s_append(s_restart(reply), "out of memory"); return Retry; } strncpy(buf+n, cp, nbytes); n += nbytes; if(nbytes == 1) /* end of header */ break; } buf[n] = 0; bufsize = n; /* * parse the header, turn all addresses into @ format */ yyinit(buf, n); yyparse(); /* * print message observing '.' escapes and using \r\n for \n */ alarm(20*alarmscale); if(!filter){ dBprint("DATA\r\n"); switch(getreply()){ case 3: break; case 5: free(buf); return Giveup; default: free(buf); return Retry; } } /* * send header. add a message-id, a sender, and a date if there * isn't one */ nbytes = 0; fromline = convertheader(from); uneaten = buf; srand(truerand()); if(messageid == 0){ for(i=0; i<16; i++){ r = rand()&0xFF; id[2*i] = hex[r&0xF]; id[2*i+1] = hex[(r>>4)&0xF]; } id[2*i] = '\0'; nbytes += Bprint(&bout, "Message-ID: <%s@%s>\r\n", id, hostdomain); if(debug) Bprint(&berr, "Message-ID: <%s@%s>\r\n", id, hostdomain); } if(originator==0){ nbytes += Bprint(&bout, "From: %s\r\n", s_to_c(fromline)); if(debug) Bprint(&berr, "From: %s\r\n", s_to_c(fromline)); } s_free(fromline); if(destination == 0 && toline) if(*s_to_c(toline) == '@'){ /* route addr */ nbytes += Bprint(&bout, "To: <%s>\r\n", s_to_c(toline)); if(debug) Bprint(&berr, "To: <%s>\r\n", s_to_c(toline)); } else { nbytes += Bprint(&bout, "To: %s\r\n", s_to_c(toline)); if(debug) Bprint(&berr, "To: %s\r\n", s_to_c(toline)); } if(date==0 && udate) nbytes += printdate(udate); if (usys) uneaten = usys->end + 1; nbytes += printheader(); if (*uneaten != '\n') putcrnl("\n", 1); /* * send body */ putcrnl(uneaten, buf+n - uneaten); nbytes += buf+n - uneaten; if(eof == 0){ for(;;){ n = Bread(b, buf, bufsize); if(n < 0){ rerrstr(errmsg, sizeof(errmsg)); s_append(s_restart(reply), errmsg); free(buf); return Retry; } if(n == 0) break; alarm(10*alarmscale); putcrnl(buf, n); nbytes += n; } } free(buf); if(!filter){ if(last != '\n') dBprint("\r\n.\r\n"); else dBprint(".\r\n"); alarm(10*alarmscale); switch(getreply()){ case 2: break; case 5: return Giveup; default: return Retry; } syslog(0, "smtp", "%s sent %d bytes to %s", s_to_c(from), nbytes, s_to_c(toline));/**/ } return 0;}/* * we're leaving */voidquit(char *rv){ /* 60 minutes to quit */ quitting = 1; quitrv = rv; alarm(60*alarmscale); dBprint("QUIT\r\n"); getreply(); Bterm(&bout); Bterm(&bfile);}/* * read a reply into a string, return the reply code */intgetreply(void){ char *line; int rv; reply = s_reset(reply); for(;;){ line = getcrnl(reply); if(debug) Bflush(&berr); if(line == 0) return -1; if(!isdigit(line[0]) || !isdigit(line[1]) || !isdigit(line[2])) return -1; if(line[3] != '-') break; } if(debug) Bflush(&berr); rv = atoi(line)/100; return rv;}voidaddhostdom(String *buf, char *host){ s_append(buf, "@"); s_append(buf, host);}/* * Convert from `bang' to `source routing' format. * * a.x.y!b.p.o!c!d -> @a.x.y:c!d@b.p.o */String *bangtoat(char *addr){ String *buf; register int i; int j, d; char *field[128]; /* parse the '!' format address */ buf = s_new(); for(i = 0; addr; i++){ field[i] = addr; addr = strchr(addr, '!'); if(addr) *addr++ = 0; } if (i==1) { s_append(buf, field[0]); return buf; } /* * count leading domain fields (non-domains don't count) */ for(d = 0; d<i-1; d++) if(strchr(field[d], '.')==0) break; /* * if there are more than 1 leading domain elements, * put them in as source routing */ if(d > 1){ addhostdom(buf, field[0]); for(j=1; j<d-1; j++){ s_append(buf, ","); s_append(buf, "@"); s_append(buf, field[j]); } s_append(buf, ":"); } /* * throw in the non-domain elements separated by '!'s */ s_append(buf, field[d]); for(j=d+1; j<=i-1; j++) { s_append(buf, "!"); s_append(buf, field[j]); } if(d) addhostdom(buf, field[d-1]); return buf;}/* * convert header addresses to @ format. * if the address is a source address, and a domain is specified, * make sure it falls in the domain. */String*convertheader(String *from){ Field *f; Node *p, *lastp; String *a; if(!returnable(s_to_c(from))){ from = s_new(); s_append(from, "Postmaster"); addhostdom(from, hostdomain); } else if(strchr(s_to_c(from), '@') == 0){ a = username(from); if(a) { s_append(a, " <"); s_append(a, s_to_c(from)); addhostdom(a, hostdomain); s_append(a, ">"); from = a; } else { from = s_copy(s_to_c(from)); addhostdom(from, hostdomain); } } else from = s_copy(s_to_c(from)); for(f = firstfield; f; f = f->next){ lastp = 0; for(p = f->node; p; lastp = p, p = p->next){ if(!p->addr) continue; a = bangtoat(s_to_c(p->s)); s_free(p->s); if(strchr(s_to_c(a), '@') == 0) addhostdom(a, hostdomain); else if(*s_to_c(a) == '@') a = fixrouteaddr(a, p->next, lastp); p->s = a; } } return from;}/* * ensure route addr has brackets around it */String*fixrouteaddr(String *raddr, Node *next, Node *last){ String *a; if(last && last->c == '<' && next && next->c == '>') return raddr; /* properly formed already */ a = s_new(); s_append(a, "<"); s_append(a, s_to_c(raddr)); s_append(a, ">"); s_free(raddr); return a;}/* * print out the parsed header */intprintheader(void){ int n, len; Field *f; Node *p; char *cp; char c[1]; n = 0; for(f = firstfield; f; f = f->next){ for(p = f->node; p; p = p->next){ if(p->s) n += dBprint("%s", s_to_c(p->s)); else { c[0] = p->c; putcrnl(c, 1); n++; } if(p->white){ cp = s_to_c(p->white); len = strlen(cp); putcrnl(cp, len); n += len; } uneaten = p->end; } putcrnl("\n", 1); n++; uneaten++; /* skip newline */ } return n;}/* * add a domain onto an name, return the new name */char *domainify(char *name, char *domain){ static String *s; char *p; if(domain==0 || strchr(name, '.')!=0) return name; s = s_reset(s); s_append(s, name); p = strchr(domain, '.'); if(p == 0){ s_append(s, "."); p = domain; } s_append(s, p); return s_to_c(s);}/* * print message observing '.' escapes and using \r\n for \n */voidputcrnl(char *cp, int n){ int c; for(; n; n--, cp++){ c = *cp; if(c == '\n') dBputc('\r'); else if(c == '.' && last=='\n') dBputc('.'); dBputc(c); last = c; }}/* * Get a line including a crnl into a string. Convert crnl into nl. */char *getcrnl(String *s){ int c; int count; count = 0; for(;;){ c = Bgetc(&bin); if(debug) Bputc(&berr, c); switch(c){ case -1: s_append(s, "connection closed unexpectedly by remote system"); s_terminate(s); return 0; case '\r': c = Bgetc(&bin); if(c == '\n'){ case '\n': s_putc(s, c); if(debug) Bputc(&berr, c); count++; s_terminate(s); return s->ptr - count; } Bungetc(&bin); s_putc(s, '\r'); if(debug) Bputc(&berr, '\r'); count++; break; default: s_putc(s, c); count++; break; } }}/* * print out a parsed date */intprintdate(Node *p){ int n, sep = 0; n = dBprint("Date: %s,", s_to_c(p->s)); for(p = p->next; p; p = p->next){ if(p->s){ if(sep == 0) { dBputc(' '); n++; } if (p->next) n += dBprint("%s", s_to_c(p->s)); else n += dBprint("%s", rewritezone(s_to_c(p->s))); sep = 0; } else { dBputc(p->c); n++; sep = 1; } } n += dBprint("\r\n"); return n;}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;}/* * stolen from libc/port/print.c */#define SIZE 4096intdBprint(char *fmt, ...){ char buf[SIZE], *out; va_list arg; int n; va_start(arg, fmt); out = vseprint(buf, buf+SIZE, fmt, arg); va_end(arg); if(debug){ Bwrite(&berr, buf, (long)(out-buf)); Bflush(&berr); } n = Bwrite(&bout, buf, (long)(out-buf)); Bflush(&bout); return n;}intdBputc(int x){ if(debug) Bputc(&berr, x); return Bputc(&bout, x);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -