xref: /plan9-contrib/sys/src/cmd/upas/send/message.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
13e12c5d1SDavid du Colombier #include "common.h"
23e12c5d1SDavid du Colombier #include "send.h"
33e12c5d1SDavid du Colombier 
43e12c5d1SDavid du Colombier /* global to this file */
53e12c5d1SDavid du Colombier static Reprog *rfprog;
63e12c5d1SDavid du Colombier static Reprog *fprog;
73e12c5d1SDavid du Colombier 
83e12c5d1SDavid du Colombier #define VMLIMIT (64*1024)
9*219b2ee8SDavid du Colombier #define MSGLIMIT (128*1024*1024)
103e12c5d1SDavid du Colombier 
113e12c5d1SDavid du Colombier extern void
123e12c5d1SDavid du Colombier default_from(message *mp)
133e12c5d1SDavid du Colombier {
143e12c5d1SDavid du Colombier 	char *cp;
153e12c5d1SDavid du Colombier 
163e12c5d1SDavid du Colombier 	cp = getenv("upasname");
173e12c5d1SDavid du Colombier 	if(cp)
183e12c5d1SDavid du Colombier 		s_append(mp->sender, cp);
193e12c5d1SDavid du Colombier 	else
203e12c5d1SDavid du Colombier 		s_append(mp->sender, getlog());
213e12c5d1SDavid du Colombier 	s_append(mp->date, thedate());
223e12c5d1SDavid du Colombier }
233e12c5d1SDavid du Colombier 
243e12c5d1SDavid du Colombier extern message *
253e12c5d1SDavid du Colombier m_new(void)
263e12c5d1SDavid du Colombier {
273e12c5d1SDavid du Colombier 	message *mp;
283e12c5d1SDavid du Colombier 
293e12c5d1SDavid du Colombier 	mp = (message *)malloc(sizeof(message));
303e12c5d1SDavid du Colombier 	if (mp == 0) {
313e12c5d1SDavid du Colombier 		perror("message:");
323e12c5d1SDavid du Colombier 		exit(1);
333e12c5d1SDavid du Colombier 	}
343e12c5d1SDavid du Colombier 	mp->sender = s_new();
353e12c5d1SDavid du Colombier 	mp->replyaddr = s_new();
363e12c5d1SDavid du Colombier 	mp->date = s_new();
373e12c5d1SDavid du Colombier 	mp->body = s_new();
383e12c5d1SDavid du Colombier 	mp->size = 0;
393e12c5d1SDavid du Colombier 	mp->fd = -1;
403e12c5d1SDavid du Colombier 	return mp;
413e12c5d1SDavid du Colombier }
423e12c5d1SDavid du Colombier 
433e12c5d1SDavid du Colombier extern void
443e12c5d1SDavid du Colombier m_free(message *mp)
453e12c5d1SDavid du Colombier {
463e12c5d1SDavid du Colombier 	if(mp->fd >= 0){
473e12c5d1SDavid du Colombier 		close(mp->fd);
483e12c5d1SDavid du Colombier 		remove(s_to_c(mp->tmp));
493e12c5d1SDavid du Colombier 		s_free(mp->tmp);
503e12c5d1SDavid du Colombier 	}
513e12c5d1SDavid du Colombier 	s_free(mp->sender);
523e12c5d1SDavid du Colombier 	s_free(mp->date);
533e12c5d1SDavid du Colombier 	s_free(mp->body);
543e12c5d1SDavid du Colombier 	free((char *)mp);
553e12c5d1SDavid du Colombier }
563e12c5d1SDavid du Colombier 
573e12c5d1SDavid du Colombier /* read a message into a temp file , return an open fd to it */
583e12c5d1SDavid du Colombier static int
593e12c5d1SDavid du Colombier m_read_to_file(Biobuf *fp, message *mp)
603e12c5d1SDavid du Colombier {
613e12c5d1SDavid du Colombier 	int fd;
623e12c5d1SDavid du Colombier 	int n;
633e12c5d1SDavid du Colombier 	String *file;
643e12c5d1SDavid du Colombier 	char buf[4*1024];
653e12c5d1SDavid du Colombier 
663e12c5d1SDavid du Colombier 	file = s_new();
673e12c5d1SDavid du Colombier 	/*
683e12c5d1SDavid du Colombier 	 *  create and unlink temp file
693e12c5d1SDavid du Colombier 	 */
703e12c5d1SDavid du Colombier 	abspath("tmp/mtXXXXXX", MAILROOT, file);
713e12c5d1SDavid du Colombier 	mktemp(s_to_c(file));
723e12c5d1SDavid du Colombier 	if((fd = syscreate(s_to_c(file), 0600))<0){
733e12c5d1SDavid du Colombier 		s_free(mp->tmp);
743e12c5d1SDavid du Colombier 		return -1;
753e12c5d1SDavid du Colombier 	}
763e12c5d1SDavid du Colombier 	mp->tmp = file;
773e12c5d1SDavid du Colombier 
783e12c5d1SDavid du Colombier 	/*
793e12c5d1SDavid du Colombier 	 *  read the rest into the temp file
803e12c5d1SDavid du Colombier 	 */
813e12c5d1SDavid du Colombier 	while((n = Bread(fp, buf, sizeof(buf))) > 0){
823e12c5d1SDavid du Colombier 		if(write(fd, buf, n) != n){
833e12c5d1SDavid du Colombier 			close(fd);
843e12c5d1SDavid du Colombier 			return -1;
853e12c5d1SDavid du Colombier 		}
863e12c5d1SDavid du Colombier 		mp->size += n;
873e12c5d1SDavid du Colombier 		if(mp->size > MSGLIMIT){
883e12c5d1SDavid du Colombier 			mp->size = -1;
893e12c5d1SDavid du Colombier 			break;
903e12c5d1SDavid du Colombier 		}
913e12c5d1SDavid du Colombier 	}
923e12c5d1SDavid du Colombier 
933e12c5d1SDavid du Colombier 	mp->fd = fd;
943e12c5d1SDavid du Colombier 	return 0;
953e12c5d1SDavid du Colombier }
963e12c5d1SDavid du Colombier 
973e12c5d1SDavid du Colombier /* read in a message, interpret the 'From' header */
983e12c5d1SDavid du Colombier extern message *
993e12c5d1SDavid du Colombier m_read(Biobuf *fp, int rmail)
1003e12c5d1SDavid du Colombier {
1013e12c5d1SDavid du Colombier 	message *mp;
1023e12c5d1SDavid du Colombier 	Resub subexp[10];
1033e12c5d1SDavid du Colombier 	int first;
1043e12c5d1SDavid du Colombier 	int n;
1053e12c5d1SDavid du Colombier 
106*219b2ee8SDavid du Colombier 
1073e12c5d1SDavid du Colombier 	mp = m_new();
1083e12c5d1SDavid du Colombier 
1093e12c5d1SDavid du Colombier 	/* parse From lines if remote */
1103e12c5d1SDavid du Colombier 	if (rmail) {
1113e12c5d1SDavid du Colombier 		/* get remote address */
1123e12c5d1SDavid du Colombier 		String *sender=s_new();
1133e12c5d1SDavid du Colombier 
1143e12c5d1SDavid du Colombier 		if (rfprog == 0)
1153e12c5d1SDavid du Colombier 			rfprog = regcomp(REMFROMRE);
1163e12c5d1SDavid du Colombier 		first = 1;
1173e12c5d1SDavid du Colombier 		while(s_read_line(fp, s_restart(mp->body)) != 0) {
1183e12c5d1SDavid du Colombier 			memset(subexp, 0, sizeof(subexp));
1193e12c5d1SDavid du Colombier 			if (regexec(rfprog, s_to_c(mp->body), subexp, 10) == 0){
1203e12c5d1SDavid du Colombier 				if(first == 0)
1213e12c5d1SDavid du Colombier 					break;
1223e12c5d1SDavid du Colombier 				if (fprog == 0)
1233e12c5d1SDavid du Colombier 					fprog = regcomp(FROMRE);
1243e12c5d1SDavid du Colombier 				memset(subexp, 0, sizeof(subexp));
1253e12c5d1SDavid du Colombier 				if(regexec(fprog, s_to_c(mp->body), subexp,10) == 0)
1263e12c5d1SDavid du Colombier 					break;
1273e12c5d1SDavid du Colombier 				USE(s_restart(mp->body));
1283e12c5d1SDavid du Colombier 				append_match(subexp, s_restart(sender), SENDERMATCH);
1293e12c5d1SDavid du Colombier 				append_match(subexp, s_restart(mp->date), DATEMATCH);
1303e12c5d1SDavid du Colombier 				break;
1313e12c5d1SDavid du Colombier 			}
1323e12c5d1SDavid du Colombier 			append_match(subexp, s_restart(sender), REMSENDERMATCH);
1333e12c5d1SDavid du Colombier 			append_match(subexp, s_restart(mp->date), REMDATEMATCH);
1343e12c5d1SDavid du Colombier 			if(subexp[REMSYSMATCH].sp!=subexp[REMSYSMATCH].ep){
1353e12c5d1SDavid du Colombier 				append_match(subexp, mp->sender, REMSYSMATCH);
1363e12c5d1SDavid du Colombier 				s_append(mp->sender, "!");
1373e12c5d1SDavid du Colombier 			}
1383e12c5d1SDavid du Colombier 			first = 0;
1393e12c5d1SDavid du Colombier 		}
1403e12c5d1SDavid du Colombier 		s_append(mp->sender, s_to_c(sender));
1413e12c5d1SDavid du Colombier 		s_free(sender);
1423e12c5d1SDavid du Colombier 	}
1433e12c5d1SDavid du Colombier 	if (*s_to_c(mp->sender)=='\0')
1443e12c5d1SDavid du Colombier 		default_from(mp);
1453e12c5d1SDavid du Colombier 
1463e12c5d1SDavid du Colombier 	/*
1473e12c5d1SDavid du Colombier 	 *  read up to VMLIMIT bytes (more or less) into main memory.
1483e12c5d1SDavid du Colombier 	 *  if message is longer put the rest in a tmp file.
1493e12c5d1SDavid du Colombier 	 */
1503e12c5d1SDavid du Colombier 	mp->size = mp->body->ptr - mp->body->base;
1513e12c5d1SDavid du Colombier 	n = s_read(fp, mp->body, VMLIMIT);
1523e12c5d1SDavid du Colombier 	if(n < 0){
1533e12c5d1SDavid du Colombier 		perror("m_read");
1543e12c5d1SDavid du Colombier 		exit(1);
1553e12c5d1SDavid du Colombier 	}
1563e12c5d1SDavid du Colombier 	mp->size += n;
1573e12c5d1SDavid du Colombier 	if(n == VMLIMIT){
1583e12c5d1SDavid du Colombier 		if(m_read_to_file(fp, mp) < 0){
1593e12c5d1SDavid du Colombier 			perror("m_read");
1603e12c5d1SDavid du Colombier 			exit(1);
1613e12c5d1SDavid du Colombier 		}
1623e12c5d1SDavid du Colombier 	}
1633e12c5d1SDavid du Colombier 
1643e12c5d1SDavid du Colombier 	/*
1653e12c5d1SDavid du Colombier 	 *  ignore 0 length messages from a terminal
1663e12c5d1SDavid du Colombier 	 */
167*219b2ee8SDavid du Colombier 	if (!rmail && mp->size == 0)
1683e12c5d1SDavid du Colombier 		return 0;
1693e12c5d1SDavid du Colombier 
1703e12c5d1SDavid du Colombier 	return mp;
1713e12c5d1SDavid du Colombier }
1723e12c5d1SDavid du Colombier 
1733e12c5d1SDavid du Colombier /* return a piece of message starting at `offset' */
1743e12c5d1SDavid du Colombier extern int
1753e12c5d1SDavid du Colombier m_get(message *mp, long offset, char **pp)
1763e12c5d1SDavid du Colombier {
1773e12c5d1SDavid du Colombier 	static char buf[4*1024];
1783e12c5d1SDavid du Colombier 
1793e12c5d1SDavid du Colombier 	/*
1803e12c5d1SDavid du Colombier 	 *  are we past eof?
1813e12c5d1SDavid du Colombier 	 */
1823e12c5d1SDavid du Colombier 	if(offset >= mp->size)
1833e12c5d1SDavid du Colombier 		return 0;
1843e12c5d1SDavid du Colombier 
1853e12c5d1SDavid du Colombier 	/*
1863e12c5d1SDavid du Colombier 	 *  are we in the virtual memory portion?
1873e12c5d1SDavid du Colombier 	 */
1883e12c5d1SDavid du Colombier 	if(offset < mp->body->ptr - mp->body->base){
1893e12c5d1SDavid du Colombier 		*pp = mp->body->base + offset;
1903e12c5d1SDavid du Colombier 		return mp->body->ptr - mp->body->base - offset;
1913e12c5d1SDavid du Colombier 	}
1923e12c5d1SDavid du Colombier 
1933e12c5d1SDavid du Colombier 	/*
1943e12c5d1SDavid du Colombier 	 *  read it from the temp file
1953e12c5d1SDavid du Colombier 	 */
1963e12c5d1SDavid du Colombier 	offset -= mp->body->ptr - mp->body->base;
1973e12c5d1SDavid du Colombier 	if(mp->fd < 0)
1983e12c5d1SDavid du Colombier 		return -1;
1993e12c5d1SDavid du Colombier 	if(seek(mp->fd, offset, 0)<0)
2003e12c5d1SDavid du Colombier 		return -1;
2013e12c5d1SDavid du Colombier 	*pp = buf;
2023e12c5d1SDavid du Colombier 	return read(mp->fd, buf, sizeof buf);
2033e12c5d1SDavid du Colombier }
2043e12c5d1SDavid du Colombier 
2053e12c5d1SDavid du Colombier /* output the message body without ^From escapes */
2063e12c5d1SDavid du Colombier static int
2073e12c5d1SDavid du Colombier m_noescape(message *mp, Biobuf *fp)
2083e12c5d1SDavid du Colombier {
2093e12c5d1SDavid du Colombier 	long offset;
2103e12c5d1SDavid du Colombier 	int n;
2113e12c5d1SDavid du Colombier 	char *p;
2123e12c5d1SDavid du Colombier 
2133e12c5d1SDavid du Colombier 	for(offset = 0; offset < mp->size; offset += n){
2143e12c5d1SDavid du Colombier 		n = m_get(mp, offset, &p);
2153e12c5d1SDavid du Colombier 		if(n <= 0){
2163e12c5d1SDavid du Colombier 			Bflush(fp);
2173e12c5d1SDavid du Colombier 			return -1;
2183e12c5d1SDavid du Colombier 		}
2193e12c5d1SDavid du Colombier 		if(Bwrite(fp, p, n) < 0)
2203e12c5d1SDavid du Colombier 			return -1;
2213e12c5d1SDavid du Colombier 	}
2223e12c5d1SDavid du Colombier 	return Bflush(fp);
2233e12c5d1SDavid du Colombier }
2243e12c5d1SDavid du Colombier 
2253e12c5d1SDavid du Colombier /*
226*219b2ee8SDavid du Colombier  *  Output the message body with '^From ' escapes.
227*219b2ee8SDavid du Colombier  *  Ensures that any line starting with a 'From ' gets a ' ' stuck
2283e12c5d1SDavid du Colombier  *  in front of it.
2293e12c5d1SDavid du Colombier  */
2303e12c5d1SDavid du Colombier static int
2313e12c5d1SDavid du Colombier m_escape(message *mp, Biobuf *fp)
2323e12c5d1SDavid du Colombier {
233*219b2ee8SDavid du Colombier 	char *p, *np;
234*219b2ee8SDavid du Colombier 	char *end;
2353e12c5d1SDavid du Colombier 	long offset;
236*219b2ee8SDavid du Colombier 	int m, n;
2373e12c5d1SDavid du Colombier 	char *start;
2383e12c5d1SDavid du Colombier 
2393e12c5d1SDavid du Colombier 	for(offset = 0; offset < mp->size; offset += n){
2403e12c5d1SDavid du Colombier 		n = m_get(mp, offset, &start);
2413e12c5d1SDavid du Colombier 		if(n < 0){
2423e12c5d1SDavid du Colombier 			Bflush(fp);
2433e12c5d1SDavid du Colombier 			return -1;
2443e12c5d1SDavid du Colombier 		}
2453e12c5d1SDavid du Colombier 
2463e12c5d1SDavid du Colombier 		p = start;
247*219b2ee8SDavid du Colombier 		for(end = p+n; p < end; p += m){
248*219b2ee8SDavid du Colombier 			np = memchr(p, '\n', end-p);
249*219b2ee8SDavid du Colombier 			if(np == 0){
250*219b2ee8SDavid du Colombier 				Bwrite(fp, p, end-p);
2513e12c5d1SDavid du Colombier 				break;
2523e12c5d1SDavid du Colombier 			}
253*219b2ee8SDavid du Colombier 			m = np - p + 1;
254*219b2ee8SDavid du Colombier 			if(m > 5 && strncmp(p, "From ", 5) == 0)
255*219b2ee8SDavid du Colombier 				Bputc(fp, ' ');
256*219b2ee8SDavid du Colombier 			Bwrite(fp, p, m);
2573e12c5d1SDavid du Colombier 		}
2583e12c5d1SDavid du Colombier 	}
2593e12c5d1SDavid du Colombier 	Bflush(fp);
2603e12c5d1SDavid du Colombier 	return 0;
2613e12c5d1SDavid du Colombier }
2623e12c5d1SDavid du Colombier 
2633e12c5d1SDavid du Colombier /* output a message */
2643e12c5d1SDavid du Colombier extern int
2653e12c5d1SDavid du Colombier m_print(message *mp, Biobuf *fp, char *remote, int mbox)
2663e12c5d1SDavid du Colombier {
2673e12c5d1SDavid du Colombier 	if (remote != 0){
2683e12c5d1SDavid du Colombier 		if(print_remote_header(fp,s_to_c(mp->sender),s_to_c(mp->date),remote) < 0)
2693e12c5d1SDavid du Colombier 			return -1;
2703e12c5d1SDavid du Colombier 	} else {
2713e12c5d1SDavid du Colombier 		if(print_header(fp, s_to_c(mp->sender), s_to_c(mp->date)) < 0)
2723e12c5d1SDavid du Colombier 			return -1;
2733e12c5d1SDavid du Colombier 	}
2743e12c5d1SDavid du Colombier 
2753e12c5d1SDavid du Colombier 	if (!mbox)
2763e12c5d1SDavid du Colombier 		return m_noescape(mp, fp);
2773e12c5d1SDavid du Colombier 	return m_escape(mp, fp);
2783e12c5d1SDavid du Colombier }
2793e12c5d1SDavid du Colombier 
2803e12c5d1SDavid du Colombier /* print just the message body */
2813e12c5d1SDavid du Colombier extern int
2823e12c5d1SDavid du Colombier m_bprint(message *mp, Biobuf *fp)
2833e12c5d1SDavid du Colombier {
2843e12c5d1SDavid du Colombier 	return m_noescape(mp, fp);
2853e12c5d1SDavid du Colombier }
286