V10/cmd/nupas/send/message.c

Compare this file to the similar file:
Show the results in this format:

#include <stdio.h>
#include <regexp.h>
#include <signal.h>
#include <pwd.h>
#include "mail.h"
#include "string.h"
#include "message.h"
#include "aux.h"

/* imported */
extern char *malloc();
extern long time();
extern char *ctime();
extern char *getlog();
extern void exit();
extern char *thedate();

/* global to this file */
static regexp *rfprog;
static regexp *fprog;
static pipe_err=0;

#define VMLIMIT (64*1024)
#define MSGLIMIT (5*1024*1024)

extern void
default_from(mp)
	message *mp;
{
	char *logname;
	struct passwd *pw;
	extern char *getenv();

	/* add in date and sender */
	if ((logname=getenv("upasname")) == NULL) {
		if ((logname=getlog()) == NULL)
			logname = "Liz.Bimmler";
	}
	s_append(mp->sender, logname);
	s_append(mp->date, thedate());
}

extern message *
m_new()
{
	message *mp;

	mp = (message *)malloc(sizeof(message));
	if (mp == NULL) {
		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 int
m_free(mp)
	message *mp;
{
	if(mp->fd >= 0)
		close(mp->fd);
	s_free(mp->sender);
	s_free(mp->date);
	s_free(mp->body);
	free((char *)mp);
}

/* read a message into a temp file , return an open fd to it */
static int
m_read_to_file(fp, mp)
	FILE *fp;
	message *mp;
{
	int cfd, fd;
	int n;
	char buf[4*1024];

	/*
	 *  create and unlink temp file
	 */
	strcpy(buf, MAILROOT);
	strcat(buf, "mtXXXXXX");
	mktemp(buf);
	if((cfd = creat(buf, 0600))<0)
		return -1;
	if((fd = open(buf, 2))<0){
		unlink(buf);
		close(cfd);
		return -1;
	}
	close(cfd);
	unlink(buf);

	/*
	 *  read the rest into the temp file
	 */
	while((n = fread(buf, 1, sizeof buf, fp)) > 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;
}

/* read in a message, interpret the 'From' header */
extern message *
m_read(fp, rmail, onatty)
	FILE *fp;
	int rmail;	/* true if invoked as /bin/rmail */
	int onatty;	/* true if input from a terminal */
{
	message *mp;
	regsubexp subexp[10];
	int first;

	mp = m_new();

	/* parse From lines */
	if (rmail) {
		/* get remote address */
		string *sender=s_new();

		if (rfprog == NULL)
			rfprog = regcomp(REMFROMRE);
		first = 1;
		while(s_read_line(fp, s_restart(mp->body)) != NULL) {
			if (regexec(rfprog, s_to_c(mp->body), subexp, 10) == 0){
				if(first == 0)
					break;
				if (fprog == NULL)
					fprog = regcomp(FROMRE);
				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);

	/* get body */
	if(onatty){
		/* user typing on terminal: terminator == '.' or EOF */
		for(;;) {
			char *line;

			if ((line=s_read_line(fp, mp->body))==NULL)
				break;
			if (strcmp(".\n", line)==0) {
				*line = '\0';
				mp->body->ptr = line;
				break;
			}
		}
		mp->size = mp->body->ptr - mp->body->base;
	} else {
		/*
		 *  read up to VMLIMIT bytes (more or less).
		 *  if message is longer use temp file
		 */
		mp->size = s_read_to_lim(fp, mp->body, VMLIMIT);
		if(mp->size < 0){
			mp->size = -mp->size;
			if(m_read_to_file(fp, mp) < 0){
				perror("m_read");
				exit(1);
			}
		}
	}

	/*
	 *  ignore 0 length messages from a terminal
	 */
	if (!rmail && *s_to_c(mp->body) == '\0')
		return NULL;

	return mp;
}

SIGRETURN
sigpipe(s)
	int s;
{
	signal(SIGPIPE, sigpipe);
	pipe_err = -1;
}

/* return a piece of message starting at `offset' */
extern int
m_get(mp, offset, pp)
	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 < mp->body->ptr - mp->body->base){
		*pp = mp->body->base + offset;
		return mp->body->ptr - mp->body->base - offset;
	}

	/*
	 *  read it from the temp file
	 */
	offset -= mp->body->ptr - mp->body->base;
	if(mp->fd < 0)
		return -1;
	if(lseek(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(mp, fp)
	message *mp;	/* the message */
	FILE *fp;	/* where to print it */
{
	long offset;
	int n;
	char *p;

	for(offset = 0; offset < mp->size; offset += n){
		n = m_get(mp, offset, &p);
		if(n < 0){
			fflush(fp);
			return -1;
		}
		fwrite(p, n, 1, fp);
	}
	fflush(fp);
	return 0;
}

/*
 *  output the message body with ^From escapes.  The state machine
 *  ensures that any line starting with a 'From ' gets a '>' stuck
 *  in front of it.
 */
static int
m_escape(mp, fp)
	message *mp;	/* the message */
	FILE *fp;	/* where to print it */
{
	register char *p;
	register char *end;
	register int state;
	long offset;
	int n;
	char *start;

	state = 1;
	for(offset = 0; offset < mp->size; offset += n){
		n = m_get(mp, offset, &start);
		if(n < 0){
			fflush(fp);
			return -1;
		}

		p = start;
		for(end = p+n; p < end; p++){
			switch(state){
			case 1:
				if(*p == 'F'){
					state = 2;
					continue;
				}
				state = 0;
				break;
			case 2:
				if(*p == 'r'){
					state = 3;
					continue;
				}
				state = 0;
				fputc('F', fp);
				break;
			case 3:
				if(*p == 'o'){
					state = 4;
					continue;
				}
				state = 0;
				fputc('F', fp);
				fputc('r', fp);
				break;
			case 4:
				if(*p == 'm'){
					state = 5;
					continue;
				}
				state = 0;
				fputc('F', fp);
				fputc('r', fp);
				fputc('o', fp);
				break;
			case 5:
				if(*p == ' ')
					fputc('>', fp);
				state = 0;
				fputc('F', fp);
				fputc('r', fp);
				fputc('o', fp);
				fputc('m', fp);
				break;
			}
			fputc(*p, fp);
			if(*p == '\n')
				state = 1;
		}
	}
	fflush(fp);
	return 0;
}

/* output a message */
extern int
m_print(mp, fp, remote, mbox)
	message *mp;	/* the message */
	FILE *fp;	/* where to print it */
	char *remote;	/* 'remote from' string */
{
	SIG_TYP oldsig;
	int err;

	pipe_err = 0;
	oldsig = signal(SIGPIPE, sigpipe);
	if (remote != NULL)
		print_remote_header(fp,s_to_c(mp->sender),s_to_c(mp->date),remote);
	else
		print_header(fp, s_to_c(mp->sender), s_to_c(mp->date));

	if (!mbox)
		err = m_noescape(mp, fp);
	else
		err = m_escape(mp, fp);
	signal(SIGPIPE, oldsig);
	if(ferror(fp))
		err = -1;
	return pipe_err|err;
}

/* print just the message body */
extern int
m_bprint(mp, fp)
	message *mp;	/* the message */
	FILE *fp;	/* where to print it */
{
	SIG_TYP oldsig;
	int err;

	pipe_err = 0;
	oldsig = signal(SIGPIPE, sigpipe);
	err = m_noescape(mp, fp);
	signal(SIGPIPE, oldsig);
	if(ferror(fp))
		err = -1;
	return pipe_err|err;
}