SRI-NOSC/ncpp/mail/msg.c

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

#/*
Module Name:
	msg.c

Installation:
	if $1e = finale goto finale
	cc msg.c
	exit
: finale
	cc -O -s -n msg.c
	su cp a.out /bin/msg
	rm a.out

*/
#define MSGSEP "\001\001\001\001\n"
#define MSGSEPL 5
#define NMSGS 120
#define SIZEDATE 12    /* also have to change the printf */
#define SIZEFROM 21
#define SIZESUBJ 41
#define DELETED 0000001
#define LINESIZE 180
#define PLEN 23	/* page length for display commands */

char *newmsgfn "/.mail";
char *savmsgfn "/mbox";
char *helpfile "/etc/help/msg.help";
struct {long int start;
	int len;
	char flags;
	char date[SIZEDATE];
	char from[SIZEFROM];
	char subject[SIZESUBJ];
	} msg[NMSGS], *p;

struct
{	int hiword;
	int loword;
};

struct
{	char minor;
	char major;
	int inumber;
	int sflags;
	char nlinks;
	char uid;
	char gid;
	char size0;
	char size1;
	int addr[8];
	long int actime;
	long int modtime;
}	statb1, statb2; /* used for comparing times */

int pwr10[] {1,10,100,1000};
int ttyraw[3],ttynorm[3];
extern int errno;
int nottty;
long int curpos;
long int newpos;
int nmsgs;
int ndeleted;
int msgno;
char line[LINESIZE], templine[LINESIZE], *tlp;
char filename[60], tempname[60], outfile[60], mbox[60];
char maininbox[60];
char defoutfile[60];
char userid[20];
char flag1,flag2;
int doflg;
int msgbeg, msgend;
char nxtchar;
int needhead;
int gotnl;
int verbose;
int orig;
int curmsg;
int inmsg;
int wfile;
int lcount;
struct getcbuf
	{int fildes;
	int nleft;
	char *nextp;
	char buff[512];
	} filebuf;
/**/
onint() {
	signal(2, &onint);
	error("\n...interrupted\n");
}
/**/
error(s) char *s; {
	if (wfile > 0) close(wfile);
	if (verbose) stty(0,ttyraw);
	printf("%s", s);
	if (!(verbose || gotnl || nxtchar == '\n')) suckup();
	reset();
}
/**/
gline(file)
	struct getcbuf *file;
{	register char *cp;
	char *linend;
	linend = line + LINESIZE - 1;
	for(cp = line; cp < linend; cp++)
	{	if((*cp = getc(file)) == -1) return(-1);
		if(*cp == '\n') break;
	}
	if (*cp != '\n') *++cp = '\n';
	return(++cp-line);
}
/**/
prefix(s1, s2)
	char *s1, *s2;
{	while(*s2) if(*s1++ != *s2++) return(0);
	return(1);
}
/**/
copy(s1, s2) char *s1, *s2; {
	while(*s2++ = *s1++);
}
/**/
setup()
{	int count;
	int total;

	nmsgs = ndeleted = needhead = curmsg = inmsg = 0;
	curpos = 0;
	newpos = 0;
	if (filebuf.fildes > 0) close(filebuf.fildes);
	if(fopen(filename, &filebuf) < 0)
	{	printf("cannot open %s\n", filename);
		error("");
	}
	fstat(filebuf.fildes,&statb1);
	total = 0;
	while ((count=gline(&filebuf)) != -1)
	{	curpos = newpos;
		newpos =+ count;
		if (line[0] == MSGSEP[0])
			inmsg = 0;
		else   {if (!inmsg) begmsg();
			p->len =+ count;
			total =+ count;
			if (needhead) gethead();
			}
	}

	printf("%d message%c\n",nmsgs, nmsgs == 1 ? ' ' : 's');
}
/**/

nxtfld(s)
	char *s;
{
	while (*s && (*s++ != ' '));
	while(*s == ' ') s++;
	return(s);
}
/**/
nxtfld1()
{	char c;
	if (!verbose)
		while((c = getcc()) != '\n' && c != ' ');
	else    c=getcc();
	if (c == ' ')
		while((c = getcc()) == ' ');
	return(c);
}
/**/

prhdr()
{	if (verbose) stty(0,ttynorm);
	printf("%3d%c %-11s %-20s %-40s\n", msgno,
		p->flags&DELETED ? '*' : ' ',
		p-> date, p->from, p->subject);
	if (verbose) stty(0,ttyraw);
}
/**/
main(argc, argv)
	int argc;
	char *argv[];
{
	int restrt;
	extern prmsg(), delmsg(), undelmsg(), prhdr(), movmsg(),
	  putmsg(), lstmsg();
	orig = signal(2, &onint);
	if (gtty(0,ttynorm) < 0)
		nottty++;
	ttyraw[0] = ttynorm[0];
	ttyraw[2] = ttynorm[2] | 040;
	printf("MSG Version 3.3.NOSC\n");
	printf("	    Use DEL to abort output.\n");
	printf("	    For help type ?\n");
	printf("reading mailbox ...\n");
	getuser();
	restrt = 0;
	if (argc > 1)
	  copy(argv[1],filename);
	setexit();
	if (!(restrt++))
	   setup();
	if (argc != 0 && argv[0][0] != 'r' && !nottty)
	{	verbose++;
		stty(0,ttyraw);
	}
	setexit();
/**/
	for(;;) {
		printf("<- ");
		flag1 = flag2 = gotnl = 0;
		nxtchar = getcc();
	/*      if (nmsgs == 0 && !(nxtchar == '?' || nxtchar == 'q' ||
		   nxtchar == 'j' || nxtchar == 'v'|| nxtchar == 'r'))
			error("\nNo file\n");   */
		switch(nxtchar)
		{
		case '\n':
			break;
		case 'h':
			if (verbose) printf("eaders ");
			rditer(&prhdr);
			break;
		case 'j':
			if (verbose) printf("ump ");
			getfn("to program: ",templine,0);
			xeq();
			break;
		case '?':
			if (verbose) printf("\n");
			help();
			break;
		case 'c':
			if (verbose) printf("urrent ");
			printf("message is %d of %d messages in file %s\n",
			   curmsg,nmsgs,filename);
			break;
		case 'd':
			if (verbose) printf("elete ");
			rditer(&delmsg);
			break;
		case 'u':
			if (verbose) printf("ndelete ");
			rditer(&undelmsg);
			break;
		case 't':
			if (verbose) printf("ype ");
			lcount=0;
			rditer(&prmsg);
			break;
		case 'n':
			if (verbose) printf("ext message is:\n");
			else suckup();
			if (curmsg == nmsgs)
				error("There is no next message\n");
			p = &msg[curmsg];
			msgno = ++curmsg;
			lcount=0;
			prmsg();
			break;
		case 'b':
			if (verbose) printf("acking up to:\n");
			else suckup();
			if (curmsg <= 1)
				error("There is no previous message\n");
			msgno = --curmsg;
			p = &msg[curmsg - 1];
			lcount=0;
			prmsg();
			break;
		case 'm':
			if (verbose) printf("ove ");
			rditer1();
			getfn("to file: ",outfile,defoutfile);
			cpymsg(&movmsg);
			break;
		case 'p':
			if (verbose) printf("ut ");
			rditer1();
			getfn("to file: ",outfile,defoutfile);
			cpymsg(&putmsg);
			break;
		case 'l':
			if (verbose) printf("ist ");
			rditer1();
			getfn("to file: ",outfile,defoutfile);
			cpymsg(&lstmsg);
			break;
		case 'w':
			if (verbose) printf("rite defaults ");
			getfn("to file: ",defoutfile,mbox);
			break;
		case 's':
			if (verbose) printf("ave ");
			confirm();
			if (str_cmp(filename,mbox))
			   error("Same file - ignored\n");
			save();
			overwrit();
			copy(outfile,filename);
			setup();
			break;
		case 'o':
			if (verbose) printf("verwrite ");
			confirm();
			overwrit();
			setup();
			break;
		case 'r':
			if (verbose) printf("ead ");
			getfn("from file: ",filename,maininbox);
			setup();
			break;
		case 'e':
			if (verbose) printf("xit and update file ");
			confirm();
			if (mainbox())
			   save();
			overwrit();
			stty(0,ttynorm);
			exit();
		case '\177':  /* DEL */
			onint();
		case 'q':
			if (verbose) printf("uit\n");
			stty(0,ttynorm);
			exit();
		case 'v':
			if (verbose)
			{	printf("erbose off\n");
				stty(0,ttynorm);
				verbose = 0;
				gotnl++;
			}
			else
			{	suckup();
				if (nottty) error("Input not tty\n");
				printf("verbose on\n");
				verbose++;
				stty(0,ttyraw);
			}
			break;
		case 'f':
			if (verbose) printf("orward -- ");
			printf("Sorry, command not yet implemented\n");
			break;
		case 'a':
			if (verbose) printf("nswer -- ");
			printf("Sorry, command not yet implemented\n");
			break;
		case '':
			nxtchar = -1;
		default:
			if (nxtchar >= 0)
			printf("\nUnrecognized command.  For help type ?\n");
			else printf("Type quit to exit\n");
		}
		if (!(verbose || gotnl || nxtchar == '\n')) suckup();
	}
}
/**/
delmsg()
{	p->flags =| DELETED ;
	ndeleted++;
	return;
}
/**/
undelmsg()
{	p->flags =& ~DELETED;
	--ndeleted;
	return;
}
/**/

save()  /* move undeleted messages in file filename to mbox file */
{	extern movmsg();
	flag1 = 'u';
	copy(mbox,outfile);
	if ((wfile=open(outfile,1)) < 0)
	{	if (errno != 2)
		{	printf("Can't open %s",outfile);
			error("\n");
		}
		if ((wfile=creat(outfile,0600)) < 0)
		{	printf("Can't create %s",outfile);
			error("\n");
		}
	}
	else (seek(wfile,0,2));
	doiter(&movmsg,1,nmsgs);
	close(wfile);
	wfile = 0;
}
/**/

getfn(s,f,def)
	char *s,*f,*def;
{	char tmpbuf[100];
	char *cp;
	if (verbose) stty(0,ttynorm);
	printf("%s",s);
	read(0,tmpbuf,100);
	for (cp = tmpbuf; *cp != '\n'; cp++);
	*cp = 0;
	if (cp == tmpbuf)
	{	if (def == 0) error("Invalid name\n");
		else  { copy(def,f); printf("%s\n",f); }
	}
	else copy(tmpbuf,f);
	if (verbose) stty(0,ttyraw);
}
/**/
cpymsg(fn)
	int (*fn)();
{	if ((wfile=open(outfile,1)) < 0)
	{	if (errno != 2)
			error("can't open file\n");
		if ((wfile=creat(outfile,0644)) < 0)
			error("can't create file\n");
	}
	else seek(wfile,0,2);
	rditer2(fn);
	close(wfile);
	wfile = 0;
}
/**/
movmsg()
{	putmsg();
	delmsg();
}
/**/
putmsg()
{	write(wfile,MSGSEP,MSGSEPL);
	lstmsg();
	write(wfile,MSGSEP,MSGSEPL);
}
/**/
lstmsg()
{	int size;
	int count;
	int temp;
	char tmpbuf[512];

	temp = p->start >> 9;
	seek(filebuf.fildes,temp,3);
	seek(filebuf.fildes,(p->start).loword&0777,1);
	for (size = p->len; size; size =- count)
	{	count = size<512? size : 512;
		if (read(filebuf.fildes,tmpbuf,count) < 0)
			error("read error\n");
		if (write(wfile,tmpbuf,count) < 0)
			error("write error\n");
	}
}
/**/

prmsg()
{	int size;
	int llen;
	int count;
	printf("\n(Message %d%s, %d bytes)\n",msgno,
		p->flags&DELETED ? "*" : "",p->len);
	write(1,"**Hit DEL to abort output\n",26);
	lcount =+ 3;
	fseek(&filebuf,p->start);
	size = p->len;
	if (verbose) stty(0,ttynorm);
	for (count = 0; count < size; )
	{	while (lcount++ < PLEN)
		{	write(1,line,(llen=gline(&filebuf)));
			if ((count =+ llen) >= size) break;
		}
		if (count < size)
		{	printf("\007");
			if (verbose)
				write(1,"**Hit RETURN to continue: ",27);
			getcc();
			lcount=0;
		}
	}
	if (verbose) stty(0,ttyraw);
	curmsg = msgno;
}
/**/
overwrit()  /* remove deleted messages from file filename */
{	char tmpbuf[512];
	int size;
	int count;
	int j;

	if (ndeleted == 0)
	{	printf("File unchanged, so not updated\n");
		return;
	}

	if (stat(filename,&statb2) >= 0 && statb1.modtime != statb2.modtime)
		error("File has been updated since last read\n");

	if (ndeleted == nmsgs)
	{	if (mainbox())
			creat(filename,0600); /* truncate if mail file */
		else
		{	printf("Deleting file!\n");
			unlink(filename);	/* otherwise delete */
		}

		return;
	}



	if ((wfile=creat(tempname,0600)) < 0)
		error("can't create temporary file\n");
	flag1 = 'u';
	doiter(&putmsg,1,nmsgs);
	close(wfile);
	if (unlink(filename) < 0)
		error("can't delete old file\n");
	if (link(tempname,filename) < 0)
		error("can't rename temp file\n");
	unlink(tempname);
}
/**/

xeq()
{	int process, status;
	int old1, old2, old3;
	if (verbose)
		stty(0,ttynorm);
	old1 = signal(1, 1);
	old2 = signal(2, 1);
	old3 = signal(3, 1);

	process = fork();
	if(!process)
	{	signal(1, old1);
		signal(2, orig);
		signal(3, old3);
		execl("/bin/sh", "-", "-c", templine, 0);
		printf("cannot execute %s\n", templine);
	}
	else
	{	wait(&status);
		signal(1, old1);
		signal(2, old2);
		signal(3, old3);
	}
	if (verbose) stty(0,ttyraw);
}
/**/

help()
{	int helpfd;
	int i;
	char helpbuf[512];
	if ((helpfd=open(helpfile,0)) < 0)
		error("Can't open help file\n");
	if (verbose) stty(0,ttynorm);
	while ((i=read(helpfd,helpbuf,512)) > 0)
		write(1,helpbuf,i);
	close(helpfd);
	if (verbose) stty(0,ttyraw);
}
/**/

rditer(fn)
int (*fn)();
{	rditer1();
	if (nmsgs==0)  {
		printf("Mailbox is empty\n");
		return;
	}
	rditer2(fn);
}
/**/

rditer1()
{	int n1, n2;
	int begin, end;

	switch (nxtchar = nxtfld1())
	{
	case '\n':
	/*      if (curmsg == 0 || curmsg > nmsgs)
			error("No current message\n");  */
		msgbeg = msgend = curmsg;
		break;
	case 'a':
		if (verbose) printf("ll messages\n");
		msgbeg = 1;
		msgend = nmsgs;
		break;
	case 'i':
		if (verbose) printf("nverse all messages\n");
		msgbeg = nmsgs;
		msgend = 1;
		break;
	case 'd':
	case 'u':
		flag1 = nxtchar;	 /* save 'u' or 'd' */
		if (verbose) printf(nxtchar == 'd' ?
			     "eleted%s" : "ndeleted%s"," messages\n");
		msgbeg = 1;
		msgend = nmsgs;
		break;
	default:
		flag2++;
		rditer2(0); /* indicate only checking */
	}
}
/**/
rditer2(fn)
int (*fn)();

{	int n1, n2, t;
	int begin, end;

	doflg = fn;
	tlp = templine;
	if (doflg) nxtchar = *tlp++;
	else *tlp++ = nxtchar;
	if (flag2)	    /* only do this if a msg-sequence is present */
	while (nxtchar != '\n')
	{	while (nxtchar == ' ' || nxtchar == ',')
			if (doflg) nxtchar = *tlp++;
			else *tlp++ = nxtchar = getcc();
		if (nxtchar == '\n') break;
		n1 = getnum(&begin);
		end = begin;
		switch(nxtchar)
		{
		case '-':
			if (n1 == 0)
			   error("'-' must be preceeded by number\n");
			if (begin == 0 || begin > nmsgs)
			   error(" Invalid starting number\n");
			if (doflg) nxtchar = *tlp++;
			else *tlp++ = nxtchar = getcc();
			n2 = getnum(&end);
			if (n2 == 0)
			   error("'-' must be followed by number\n");
			if (end > nmsgs)
			   error(" Invalid ending number\n");
			if (n1 > n2) /* here comes the class! */
			{	t = pwr10[n2];
				end =+ begin / t * t;
			}
			if (begin > end)
			   error("Invalid order for '-'\n");
			break;
		case '\n':
		case ' ':
		case ',':
			if (begin == 0 || begin > nmsgs)
			   error("Invalid number\n");
			break;
		case ':':
		case '>':
			if (n1 == 0) begin = 1;
			if (begin == 0 || begin > nmsgs)
			   error(" Invalid starting number\n");
			if (doflg) nxtchar = *tlp++;
			else *tlp++ = nxtchar = getcc();
			n2 = getnum(&end);
			if (n2 == 0) end = nmsgs;
			if (end == 0 || end > nmsgs)
			   error(" Invalid ending number\n");
			break;
		default:
			error(" Invalid number\n");
		}

		if (doflg) doiter(fn,begin,end);
	}
	else if (doflg)	                    /* no msg-sequence */
		doiter(fn,msgbeg,msgend);

}
/**/

getnum(result)
int *result;
{	register int i;
	register int n;

	i = n = 0;
	while (nxtchar >= '0' && nxtchar <= '9')
	{	n = n*10 + nxtchar - '0';
		i++;
		if (doflg) nxtchar = *tlp++;
		else *tlp++ = nxtchar = getcc();
	}
	*result = n;
	return(i);
}
/**/

doiter(fn,begin,end)
  int begin,end;
  int (*fn)();

{	if (nmsgs==0) return;
	if (begin <= end)
		for(msgno = begin; msgno <= end; msgno++)
		{	p = &msg[msgno-1];
			if (flag1 == 0 || (flag1 == 'd' && (p->flags&DELETED))
				|| (flag1 == 'u' && !(p->flags&DELETED)) )
			   (*fn)();
		}
	else
		for(msgno = begin; msgno >= end; --msgno)
		{	p = &msg[msgno-1];
			if (flag1 == 0 || (flag1 == 'd' && (p->flags&DELETED))
				|| (flag1 == 'u' && !(p->flags&DELETED)) )
			   (*fn)();
		}
}
/**/
str_cpy(s1,s2)
char *s1, *s2;
{	register char *p1, *p2;

	p1 = s1;
	p2 = s2;
	while(*p2++ = *p1++);
	return(p2-s2-1);
}
/**/
str_cmp(s1,s2)
char *s1, *s2;
{	while (*s1++ == *s2++)
		if (!(*s1 | *s2)) return(1);
	return(0);
}
/**/

begmsg()
{	if (nmsgs == NMSGS)
	{	printf("Too many messages!\n");
		 reset();
	}
	p = &msg[nmsgs++];
	p->from[0] = p->date[0] = p->subject[0] = p->flags = 0;
	p->start = curpos;
	p->len = 0;
	needhead = 1;
	inmsg++;
}
/**/

copy1(src,dst,maxlen)
char *src, *dst;
int maxlen;
{	register char *s, *d;
	register int count;
	s = src;
	d = dst;
	for (count = 0; count < maxlen; count++)
		if ( (*d++ = *s++) == '\n') break;
	*--d = 0;
}
/**/
gethead()
{	char line1[LINESIZE];
	if (line[0] == '\n' || line[0] == ' ') 
	{
		needhead = 0;
		return;
	}

	copy1(line,line1,LINESIZE);
	cnvlc(line1);

	if (prefix(line1,"date:"))
	{	copy1(line+6,p->date,SIZEDATE);
		return;
	}

	if (prefix(line1,"sender:"))
	{	copy1(line+8,p->from,SIZEFROM);
		return;
	}

	if (prefix(line1,"from:"))
	{	copy1(line+6,p->from,SIZEFROM);
		return;
	}

	if (prefix(line1,"subject:"))
	{	copy1(line+9,p->subject,SIZESUBJ);
		return;
	}

	if (prefix(line1,"to:"))
		if (prefix(p->from,userid))
			copy1(line,p->from,SIZEFROM);

}
/**/
cnvlc(linep)
	char *linep;
{	register char *s;
	for (s = linep; *s; s++)
		if (*s >= 'A' && *s <= 'Z') *s =| ' ';
}
/**/
fseek(bufptr,loc)
struct getcbuf *bufptr;
long int loc;
{	int temp;
	temp = loc >> 9;
	seek(bufptr->fildes,temp,3);
	seek(bufptr->fildes,loc.loword&0777,1);
	bufptr->nleft = 0;
	bufptr->nextp = 0;
}
/**/
getuser()
{	register char *s, *d;
	int i;
	char pwbuf[120];

	if (getpw(getuid(),pwbuf))
	{	printf("Can't locate user name\n");
		exit();
	}

	s = pwbuf;
	d = userid;
	while ((*d = *s++) != ':') d++; /* get user name */
	*d++ = ' ';	              /* pad with blank */
	*d = 0;

	for (i=4; i; --i)
		while(*s++ != ':');
	d = filename;
	while((*d = *s++) != ':')d++;
	*d = 0;
	copy(filename,tempname);
	copy(filename,mbox);
	copy(newmsgfn,d);
	copy(filename,maininbox);
	copy(savmsgfn,mbox+d-filename);
	copy(mbox,defoutfile);
	copy("/tmpmail",tempname+d-filename);
}
/**/
confirm()
{	char c;
	printf("[confirm] ");
	if ((c = getcc()) == 'y' && verbose) printf("es\n");
	if (!verbose) suckup();	           /* suck up rest of line */
	if (c != 'y' && c != '\n')
		error("command ignored\n");
}
/**/
suckup()
{
	while((nxtchar=getcc()) != '\n');
}
/**/
mainbox()	        /* return non-0 if last part of filename indicates */
{	char *cp;       /* it is the main mailbox                          */

	cp = filename;
	while(*cp++);   /* get to end of name */
	while(--cp != filename && *cp != '/'); /* find last part */
	if (*cp == '/') cp++;
	return (str_cmp(cp,newmsgfn+1));
}
/**/

getcc()
{
	static c;

	read(0, &c, 1);
	return(c);
}