Thanks to John Cummings.
This commit is contained in:
parent
cd37451963
commit
5cdb17983a
94 changed files with 26853 additions and 0 deletions
573
src/cmd/upas/send/message.c
Normal file
573
src/cmd/upas/send/message.c
Normal file
|
|
@ -0,0 +1,573 @@
|
|||
#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));
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
#if 0 /* jpc */
|
||||
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",
|
||||
};
|
||||
#endif /* jpc */
|
||||
|
||||
/* 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].s.sp!=subexp[REMSYSMATCH].e.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);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue