/*
 * Citadel/UX message base support routines
 * see copyright.doc for copyright information
 */

#include <fcntl.h>
#include <stdio.h>
#include <ctype.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <pwd.h>
#include <setjmp.h>
#include <termio.h>
#include "citadel.h"
#include "color.h"
#include "qform.h"

#define IFEXPERT if (usersupp.flags&US_EXPERT)
#define IFNEXPERT if ((usersupp.flags&US_EXPERT)==0)
#define IFUPASS if (upass!=0)
#define IFNUPASS if (upass==0)
#define IFAIDE if (usersupp.axlevel>=6)
#define IFNAIDE if (usersupp.axlevel<6)
#define MAXWORDBUF 256

struct cittext {
	struct cittext *next;
	char text[MAXWORDBUF];
	};

/* long atol(); */
long lseek();
long finduser();
char *getenv();

int oldstdout;
char reply_to[512];
char reply_subj[256];

extern int curr_rm,hold_rm,twitroom;
extern struct smreturn smreturn;
extern struct usersupp usersupp;
extern struct quickroom quickroom;
extern struct fullroom fullroom;
extern struct config config;
extern jmp_buf nextbuf;
extern void backnext();
extern void backstop();
extern char temp[];
extern long highest_msg_read;
extern int editor_pid;

extern char editorfile[16];

/*
 * add a newline to the buffer...
 */
void add_newline(textlist)
struct cittext *textlist; {
	struct cittext *ptr;

	ptr=textlist;
	while (ptr->next != NULL) ptr = ptr->next;

	while (ptr->text[strlen(ptr->text)-1]==32)
		ptr->text[strlen(ptr->text)-1] = 0;
	/* strcat(ptr->text,"\n"); */

	ptr->next = (struct cittext *)
		malloc(sizeof(struct cittext));
	ptr = ptr->next;
	ptr->next = NULL;
	strcpy(ptr->text,"");
	}


/*
 * add a word to the buffer...
 */
void add_word(textlist,wordbuf)
struct cittext *textlist;
char wordbuf[]; {
	struct cittext *ptr;


	ptr=textlist;
	while (ptr->next != NULL) ptr = ptr->next;
	
	if (3+strlen(ptr->text)+strlen(wordbuf) > usersupp.USscreenwidth) {
		ptr->next = (struct cittext *)
			malloc(sizeof(struct cittext));
		ptr = ptr->next;
		ptr->next = NULL;
		strcpy(ptr->text,"");
		}
	
	strcat(ptr->text,wordbuf);
	strcat(ptr->text," ");
	}


/*
 * begin editing of an opened file pointed to by fp, beginning at position pos.
 */
void citedit(fp,base_pos)
FILE *fp;
long base_pos; {
	int a,prev,finished,b,last_space;
	int appending = 0;
	struct cittext *textlist = NULL;
	struct cittext *ptr;
	char wordbuf[MAXWORDBUF];

	/* first, load the text into the buffer */
	fseek(fp,base_pos,0);
	textlist = (struct cittext *)malloc(sizeof(struct cittext));
	textlist->next = NULL;
	strcpy(textlist->text,"");

	strcpy(wordbuf,"");
	prev = (-1);
	while (a=getc(fp), a>=0) {
		appending = 1;
		if ((a==32)||(a==9)||(a==13)||(a==10)) {
			add_word(textlist,wordbuf);
			strcpy(wordbuf,"");
			if ((prev==13)||(prev==10)) {
				add_word(textlist,"\n");
				add_newline(textlist);
				add_word(textlist,"");
				}
			}
		else {
			wordbuf[strlen(wordbuf)+1] = 0;
			wordbuf[strlen(wordbuf)] = a;
			}
		if (strlen(wordbuf)+3 > usersupp.USscreenwidth) {
			add_word(textlist,wordbuf);
			strcpy(wordbuf,"");
			}
		prev = a;
		}

	/* get text */
	finished = 0;
	prev = (appending ? 13 : (-1));
	strcpy(wordbuf,"");
	do {
		a=getc(stdin);
		if (a==10) a=13;
		if (a==9) a=32;
		if (a==127) a=8;
		if ((a==32)&&(prev==13)) {
			add_word(textlist,"\n");
			add_newline(textlist);
			}
		if (a==8) {
			if (strlen(wordbuf)>0) {
				wordbuf[strlen(wordbuf)-1] = 0;
				putc(8,stdout);
				putc(32,stdout);
				putc(8,stdout);
				}
			}
		else if (a==13) {
			printf("\n");
			if (strlen(wordbuf)==0) finished = 1;
			else {
				for (b=0; b<strlen(wordbuf); ++b)
				   if (wordbuf[b]==32) {
					wordbuf[b]=0;
					add_word(textlist,wordbuf);
					strcpy(wordbuf,&wordbuf[b+1]);
					b=0;
					}
				add_word(textlist,wordbuf);
				strcpy(wordbuf,"");
				}
			}
		else {
			putc(a,stdout);
			wordbuf[strlen(wordbuf)+1] = 0;
			wordbuf[strlen(wordbuf)] = a;
			}
		if ((strlen(wordbuf)+3) > usersupp.USscreenwidth) {
			last_space = (-1);
			for (b=0; b<strlen(wordbuf); ++b)
				if (wordbuf[b]==32) last_space = b;
			if (last_space>=0) {
				for (b=0; b<strlen(wordbuf); ++b)
				   if (wordbuf[b]==32) {
					wordbuf[b]=0;
					add_word(textlist,wordbuf);
					strcpy(wordbuf,&wordbuf[b+1]);
					b=0;
					}
				for (b=0; b<strlen(wordbuf); ++b) {
					putc(8,stdout);
					putc(32,stdout);
					putc(8,stdout);
					}
				printf("\n%s",wordbuf);
				}
			else {
				add_word(textlist,wordbuf);
				strcpy(wordbuf,"");
				printf("\n");
				}
			}
		prev = a;
		} while (finished==0);

	/* write the buffer back to disk */
	fseek(fp,base_pos,0);
	for (ptr=textlist; ptr!=NULL; ptr=ptr->next) {
		fprintf(fp,"%s",ptr->text);
		}
	putc(10,fp);
	putc(0,fp);

	/* and deallocate the memory we used */
	while (textlist!=NULL) {
		ptr=textlist->next;
		free(textlist);
		textlist=ptr;
		}
	}


read_message(pos,pagin)	/* Read a message from the master file */
long pos;	/* Position in master file */
char pagin;	/* 0 = normal read, 1 = read with pagination, 2 = header */
{
	int a;
	a=setjmp(nextbuf);
	sttybbs(0);
	if ((a==1)||(a==2)) {
		printf("\n\n");
		return(a);
		}
	signal(SIGINT,backnext);
	signal(SIGQUIT,backstop);
	sttybbs(1);
	clearcon();
	setcolor(RED,B_BLACK);
	printf("---------------------------------------------------------------------------");
	
	msgform(usersupp.USscreenwidth,pos,"msgmain",pagin);
	sttybbs(0);
	return(0);
}

send_message(filename,retbuf)	/* send a message to the master file */
char filename[];		/* tempfilename of proper message */
struct smreturn *retbuf;	/* return information */
{

int file,a,c,d;
long bb,cc,templen,hibytes,origpos,bytes_written;
char sbuf[BUFSIZ];
char mid[30];
FILE *fp,*fp2;
struct msgmain msgmain;

	/* lock_msgmain(); */
	file=eopen("MMstructure",O_RDWR);
	lseek(file,0L,0);
	a=read(file,&msgmain,sizeof(struct msgmain));
	if (a<1) interr(14);
	lseek(file,0L,0);
	close(file);

	origpos=msgmain.MMcurpos;
	++msgmain.MMhighest;
	sprintf(mid,"I%ld",msgmain.MMhighest);

	/* measure the message */
	fp=fopen(filename,"r");
	fseek(fp,0L,2);
	templen=ftell(fp);
	fclose(fp);
	templen=templen+((long)strlen(mid))+2L;

	/* check for FF bytes, to determine how many msgs we're overwriting */
	hibytes=0L;
	fp=fopen("msgmain","rb");
	if (fp==NULL) interr(18);
	fseek(fp,msgmain.MMcurpos,0);
	cc=ftell(fp);
	for (bb=0L; bb<templen; ++bb) {
		if (cc>=MM_FILELEN) {
			fseek(fp,0L,0);
			cc=0L;
			}
		c=getc(fp); ++cc;
		if (c>127) ++hibytes;	/* bump count if hi bit set */
		}
	fclose(fp);
	msgmain.MMlowest=msgmain.MMlowest+hibytes;

	fp=fopen("msgmain","r+");
	fseek(fp,msgmain.MMcurpos,0);
	cc=ftell(fp);
	fp2=fopen(filename,"r");
	fread((char *)sbuf,3,1,fp2);
	fwrite((char *)sbuf,3,1,fp);
	fprintf(fp,"%s",mid);
	putc(0,fp);

	/* 3 header + mid (I field) + 1 zero-byte */
	bytes_written = 4L + ((long)strlen(mid));

	while (bytes_written < templen) {
		d=getc(fp2);
		if (d<0) d=0;
		putc(d,fp);
		++cc;
		if (cc>=MM_FILELEN) {
			fseek(fp,0L,0);
			cc = 0L;
			}
		++bytes_written;
		}

	msgmain.MMcurpos=ftell(fp);
	fclose(fp2);	/* done with temp file */
	fclose(fp);	/* done with master file */

	/* now update the message structure */
	file=eopen("MMstructure",O_RDWR);
	a=write(file,&msgmain,sizeof(struct msgmain));
	if (a<1) interr(21);
	close(file);

	/* unlock_msgmain(); */

	retbuf->smnumber=msgmain.MMhighest;
	retbuf->smpos=origpos;

	return(0);
	}

/*
 * hold_message()  -  put a message into the hold buffer (temp file)
 */
void hold_message(source,spos,dest)
char *source;
long spos;
char *dest; {
	FILE *sfp,*dfp;
	int a;
	
	sfp=fopen(source,"r");
	dfp=fopen(dest,"w");
	fseek(sfp,spos,0);
	do {
		a=getc(sfp);
		if (a>=0) putc(a,dfp);
		} while (a>0);
	fclose(sfp);
	fclose(dfp);
	}

/*
 * replace string function for the built-in editor
 */
void replace_string(filename,startpos)
char *filename;
long startpos; {
	char buf[512];
	char srch_str[128];
	char rplc_str[128];
	FILE *fp;
	int a,b;
	long rpos,wpos;
	char *ptr;
	int substitutions = 0;
	long msglen = 0L;

	printf("Enter text to be replaced:\n: ");
	getline(srch_str,128);
	if (strlen(srch_str)==0) return;
	
	printf("Enter text to replace it with:\n: ");
	getline(rplc_str,128);

	fp=fopen(filename,"r+");
	if (fp==NULL) return;

	wpos=startpos;
	fseek(fp,startpos,0);
	strcpy(buf,"");
	while (a=getc(fp), a>0) {
		++msglen;
		buf[strlen(buf)+1] = 0;
		buf[strlen(buf)] = a;
		ptr=&buf[strlen(buf)-strlen(srch_str)];
		if (!struncmp(ptr,srch_str,strlen(srch_str))) {
			strcpy(ptr,rplc_str);
			++substitutions;
			}
		if (strlen(buf)>384) {
			rpos=ftell(fp);
			fseek(fp,wpos,0);
			fwrite((char *)buf,128,1,fp);
			strcpy(buf,&buf[128]);
			wpos = ftell(fp);
			fseek(fp,rpos,0);
			}
		}
	fseek(fp,wpos,0);
	if (strlen(buf)>0) fwrite((char *)buf,strlen(buf),1,fp);
	putc(0,fp);
	fclose(fp);
	printf("<R>eplace made %d substitution(s).\n\n",substitutions);
	}


make_message(filename,author,recipient,room,type,mode,subject)
char filename[];	/* temporary file name */
struct usersupp *author;  /* author's usersupp structure */
char recipient[];	/* NULL if it's not mail */
char room[];		/* room where it's going */
int type;		/* see MES_ types in header file */
int mode;		/* 0 for normal, 1 for ASCII, 2 for editor */
char subject[];
{ 
	FILE *fp,*fp2;
	int a,b,old,editor_exit;
	long aa,beg,now;
	char *eex_string;

	if (mode==2) if (getenv("EDITOR")==NULL) {
		printf("*** No editor available, using built-in editor\n");
		mode=0;
		}
	eex_string = getenv("EDITOR_EXIT");
	if (eex_string==NULL) eex_string = "";

	time(&now);
	fp=fopen(filename,"wb"); if (fp==NULL) interr(22);
	fclose(fp); fp=fopen(filename,"r+");
	putc(255,fp);
	putc(type,fp);	/* Normal or anonymous, see MES_ flags */
	putc(((mode!=0)?1:0),fp);	/* Formatted or unformatted */
	fprintf(fp,"Pcit%ld",author->eternal); putc(0,fp); /* path */
	fprintf(fp,"T%ld",now); putc(0,fp);		/* date/time */
	fprintf(fp,"A%s",author->fullname); putc(0,fp);	/* author */
	fprintf(fp,"O%s",quickroom.QRname); putc(0,fp);	/* room */
	fprintf(fp,"N%s",NODENAME); putc(0,fp);		/* nodename */
	fprintf(fp,"H%s",HUMANNODE); putc(0,fp);	/* human nodename */
	fprintf(fp,"U%s",subject); putc(0,fp);	/* subject for this msg */

	if (recipient[0]!=0) { fprintf(fp,"R%s",recipient); putc(0,fp); }
	fflush(fp);
	msgform(usersupp.USscreenwidth,0L,filename,0);
	putc('M',fp);
	if (mode==1) printf("(Press ctrl-d when finished)\n");
	printf("--------------- vv Enter Message Below vv --------------------------------\n\n");
	setcolor(WHITE,B_BLACK);
	beg=ftell(fp); old=1;
	if (mode==0) {
		fp2=fopen(editorfile,"r");
		if (fp2!=NULL) {
			while (a=getc(fp2), a>0) {
				putc(a,fp);
				putc(a,stdout);
				}
			fclose(fp2);
			putc(0,fp);
			fseek(fp,beg,0);
			unlink(editorfile);
			}
		}

ME1:	switch(mode) {

	   case 0:
		citedit(fp,beg);
		goto MECR;
		break;

	   case 1:
		do {
			a=inkey(); if (a==255) a=32;
			if (a==13) a=10;
			if (a!=4) {
				putc(a,fp);
				putc(a,stdout);
				}
			if (a==10) putc(13,stdout);
			} while(a!=4);
		break;

	   case 2:
		editor_pid=fork();
		if (editor_pid==0) {
			setuid(getuid()); /* use real uid & gid */
			setgid(getgid());
			sttybbs(SB_RESTORE);
		     execlp(getenv("EDITOR"),getenv("EDITOR"),editorfile,NULL);
			exit(1);
			}
		if (editor_pid>0) do {
			editor_exit = 0;
			b=wait(&editor_exit);
			} while((b!=editor_pid)&&(b>=0));
		editor_pid = (-1);
		sttybbs(0);
		break;
		}

MECR:	if (mode==2) {
		fseek(fp,beg,0);
		fp2=fopen(editorfile,"r");
		if (fp2!=NULL) {
			while(b=getc(fp2),b>0) {
				/* only save printable characters and lf's */
				if ((b==10)||(((b>=32)&&(b<=126)))) putc(b,fp);
				}
			fclose(fp2);
			}
		}
	putc(0,fp); fseek(fp,-1L,1); fflush(fp);
	if ((mode==2)&&(strucmp(eex_string,""))) {
		if (editor_exit==0) goto MEFIN;
		goto MEABT2;
		}
MECR1:	printf("Entry cmd (? for options) -> ");
MECR2:	b=inkey(); b=(b&127); b=tolower(b);
	if (b=='?') { printf("Help\n");
			if(isansi())
				formout("messages/saveopt.ansi");
			else
				formout("messages/saveopt");
			goto MECR1;
			}
	if (b=='a') { printf("Abort\n");	goto MEABT;	}
	if (b=='c') { printf("Continue\n");	goto ME1;	}
	if (b=='s') { printf("Save message\n");	goto MEFIN;	} 
	if (b=='p') {
		printf("Print formatted\n");
		msgform(usersupp.USscreenwidth,0L,filename,0);
		goto MECR;
		}
	if (b=='r') {
		printf("Replace string\n");
		fclose(fp); 
		replace_string(filename,beg);
		fp=fopen(filename,"r+");
		fseek(fp,0L,2);
		goto MECR;
		}
	if (b=='h') {
		printf("Hold message\n");
		putc(0,fp);
		fclose(fp);
		hold_message(filename,beg,editorfile);
		return(2);
		}
	goto MECR2;

MEFIN:	putc(0,fp);
	fclose(fp);
	if (mode==2) unlink(editorfile);
	return(0);

MEABT:	printf("Are you sure? ");
	if (yesno()==0) goto ME1;
MEABT2:	fseek(fp,0L,0);
	putc(0,fp);
	putc(0,fp);
	fclose(fp);
	return(2);
	}

/*
 * msgform()  -  print a message to the screen
 */
msgform(width,spos,msgfile,pagin)
int width;	/* screen width */
long spos;	/* starting position in message file */
char *msgfile;	/* name of message file */
char pagin;	/* 0 = normal read, 1 = read with pagination,
		   2 = header only, 3 = message body only */
	{
	struct tm *tm;
	int a,b,e,mtype,aflag;
	int lines_printed = 8;
	char bbb[1024];
	char m_author[128];
	char m_node[128];
	char m_subject[256];
	FILE *fp;
	long now;

	strcpy(m_author,"");
	strcpy(m_node,NODENAME);
	strcpy(m_subject,"");
	
/* 	clearcon(); */

	fp=fopen(msgfile,"rb");
	if (fp==NULL) return(1);
	fseek(fp,spos,0);
	e=getc(fp);
	if (e!=255) {
		printf("*** CANNOT LOCATE MESSAGE / pos=%ld\n",spos);
		return(1);
		}
	mtype=getc(fp); aflag=getc(fp);
 	printf("\n");
	if (mtype==MES_ANON){
		setcolor(WHITE,B_BLUE);
		printf("From     :");
		setcolor(CYAN,B_BLACK);
		printf(" -----\n");
		}
	if (mtype==MES_AN2) {
		setcolor(WHITE,B_BLUE);
		printf("From     :");
		setcolor(CYAN,B_BLACK);
		printf(" <anonymous>\n");
		}

   do {
	b=getc(fp);
	if ((pagin==READ_MSGBODY)&&(b!='M')) b = 1;
	if (b=='M') {
		if (strlen(m_subject)!=0) {
			setcolor(WHITE,B_BLUE);
			printf("Subject  :");
			setcolor(CYAN,B_BLACK);
			printf(" %s\n",m_subject);
			}
		setcolor(RED,B_BLACK);
		printf("\n=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=\n\n");
		setcolor(WHITE,B_BLACK);
		if (pagin==READ_HEADER) while(getc(fp)>0) ;
		else if (aflag!=1) fmout(width,fp,pagin,
			usersupp.USscreenheight);
		   else while(a=getc(fp), a>0) {
			if (a==13) a=10;
			putc(a,stdout);
			if (a==10) {
				++lines_printed;
				if ( ((lines_printed %
				   (usersupp.USscreenheight-8))==0)
				   && (pagin==1)) {
					hit_any_key();
					}
				}
			if (ftell(fp)>=MM_FILELEN) fseek(fp,0L,0);
			}
		}
	if ((b!='M')&&(b>0)) fpgetfield(fp,bbb);

           if ( (mtype!=MES_ANON && mtype!=MES_AN2)
             || (usersupp.axlevel >= 6)
	     || (usersupp.eternal == quickroom.QRroomaide) ) {
	if (b=='A') {
		setcolor(WHITE,B_BLUE);
		printf("From     :");
		setcolor(CYAN,B_BLACK);
		printf(" %s\n",bbb);
		strcpy(m_author,bbb);
		}
	if (b=='P') strcpy(reply_to,bbb);
	if (b=='U') {
		 strcpy(m_subject,bbb);
		 strcpy(reply_subj,bbb);
		 }
	if ((pagin==READ_HEADER)&&(b=='P')) printf("\nPath      : %s\n",bbb);
	if ((pagin==READ_HEADER)&&(b=='I')) printf("\nMessage ID: %s\n",bbb);
	if ((b=='H')&&(strucmp(bbb,HUMANNODE))) printf("(%s) ",bbb);
	if (b=='O'){
		setcolor(WHITE,B_BLUE);
		printf("Room     :");
		setcolor(CYAN,B_BLACK);
		printf(" %s\n",bbb);
		}
	if ((b=='N')&&((quickroom.QRflags&QR_NETWORK)||((strucmp(bbb,NODENAME)
	   &&(strucmp(bbb,FQDN))))))
		printf("@%s ",bbb);
	if (b=='N') strcpy(m_node,bbb);
	if (b=='R') {
		setcolor(WHITE,B_BLUE);
		printf("To       :");
		setcolor(CYAN,B_BLACK);
		printf(" %s\n",bbb);
		}
	if (b=='T') {
		now=atol(bbb);
		tm=(struct tm *)localtime(&now);
		strcpy(bbb,asctime(tm)); bbb[strlen(bbb)-1]=0;
		strcpy(&bbb[16],&bbb[19]);
		setcolor(WHITE,B_BLUE);
		printf("Posted On:");
		setcolor(CYAN,B_BLACK);
		printf(" %s\n",&bbb[4]);
		}
              }
	   } while ((b!='M')&&(b>0));
	printf("\n"); fclose(fp);
	e=0;
	for (a=0; a<strlen(m_node); ++a) if (m_node[a]=='.') ++e;
	if (e==0) {
		if (!strucmp(m_node,NODENAME)) strcpy(reply_to,m_author);
		else sprintf(reply_to,"%s @ %s",m_author,m_node);
		}
	return(0);
}

/*
 * entmsg()  -  edit and create a message
 *              returns 0 if message was saved
 */
int entmsg(is_reply,c)
int is_reply;		/* nonzero if this was a <R>eply command */
int c; {		/* */
	char buf[300];
	int file,a,b,e;
	char mtsflag;
	struct usersupp tempUS;
	long aa;
	char subj[255];
	
	if ((usersupp.axlevel<2)&&(curr_rm!=1)) {
		printf("Need to be validated to enter\n");
		printf("(except in Mail> to Sysop)\n");
		return(1);
		}
	if ((usersupp.axlevel<4)&&(quickroom.QRflags&QR_NETWORK)) {
		printf("Need net privileges to enter here.\n");
		return(1);
		}
	if ((usersupp.axlevel<6)&&(quickroom.QRflags&QR_READONLY)) {
		printf("Sorry, this is a read-only room.\n");
		return(1);
		}
	mtsflag=0;
	hold_rm=curr_rm;
	IFNEXPERT {
		if(isansi())
			formout("messages/entermsg.ansi");
		else
			formout("messages/entermsg");
		}
	buf[0]=0; 
	
	if (curr_rm==1) {
		if (usersupp.axlevel>=2) {
			if (is_reply) {
				strcpy(buf,reply_to);
				}
			else {
				printf("Enter recipient: ");
				getline(buf,299);
				}
			}
		else strcpy(buf,"sysop");
		e=alias(buf);			/* alias and mail type */
		if ((buf[0]==0)&&(curr_rm==1)) {
			return(1);
			}
		if (e==M_ERROR) {
			printf("Unknown address - cannot send message.\n");
			return(1);
			}
		if ((e!=M_LOCAL)&&(usersupp.axlevel<4)) {
			printf("Net privileges required for network mail.\n");
			return(1);
			}
		if ((RESTRICT_INTERNET==1)&&(e==M_UUCP)
		   &&((usersupp.flags&US_INTERNET)==0)) {
			printf("You don't have access to Internet mail.\n");
			return(1);
			}
	if (!strucmp(buf,"sysop")) {
		mtsflag=1;
		goto SKFALL;
		}
	if (e!=M_LOCAL) goto SKFALL;	/* don't search local file if remote */
	if (!strucmp(buf,usersupp.fullname)) {
		printf("Can't send mail to yourself!\n");
		return(1);
		}

	file=eopen("usersupp",O_RDONLY);	/* check to make sure the */
	aa=finduser(file,buf);			/* user exists; also get  */
	if (aa==(-1)) {				/* the right upper/lower  */
		printf("No such user.\n");	/* casing of the name     */
		close(file);
		return(1);
		}
	read(file,&tempUS,sizeof(struct usersupp));
	strcpy(buf,tempUS.fullname);
	close(file);
	}
	else {
	if (usersupp.axlevel>=2) {
		if (is_reply) {
			strcpy(buf,reply_to);
		}
		else {
			printf("Enter recipient (Enter = ALL): ");
			getline(buf,299);
		}
	}
	}
	
	
SKFALL: b=MES_NORMAL;
	if (quickroom.QRflags&QR_ANONONLY) b=MES_ANON;
	if (quickroom.QRflags&QR_ANON2) {
		printf("Anonymous (Y/N)? ");
		if (yesno()==1) b=MES_AN2;
		}
/*	if (curr_rm!=1) buf[0]=0; */
	if(is_reply)
	{
		strcpy(subj,reply_subj);
	}
	else
	{
		printf("Subject: ");
		getline(subj,255);
	}
	
	a=make_message(temp,&usersupp,buf,quickroom.QRname,b,c,subj);
	if (a!=0) return(2);
	save_message(temp,buf,mtsflag,e);
	return(0);
	}

process_quote() {	/* do editing on quoted file */
FILE *qfile,*tfile;
char buf[128];
int line,qstart,qend;

	qfile = fopen(editorfile,"r");
	line = 0;
	fgets(buf,128,qfile);
	while (fgets(buf,128,qfile)!=NULL) {
		printf("%2d %s",++line,buf);
		}
	printf("Begin quoting at [ 1] : ");
	getline(buf,3);
	qstart = (buf[0]==0) ? (1) : atoi(buf);
	printf("  End quoting at [%d] : ",line);
	getline(buf,3);
	qend = (buf[0]==0) ? (line) : atoi(buf);
	rewind(qfile);
	line=0;
	fgets(buf,128,qfile);
	tfile=fopen(temp,"w");
	while(fgets(buf,128,qfile)!=NULL) {
		if ((++line>=qstart)&&(line<=qend)) fprintf(tfile," >%s",buf);
		}
	fprintf(tfile," \n");
	fclose(qfile);
	fclose(tfile);
	unlink(editorfile);
	link(temp,editorfile);
	unlink(temp);
	chmod(editorfile,0666);
	return(0);
	}


readmsgs(b,c,rdir)	/* read contents of a room */
int b;		/* starting point in room to read */
int c;		/* 0=Read all  1=Read new  2=Read old */
int rdir;	/* 1=Forward (-1)=Reverse */
	{
	int a,d,e,file,f,g,hold_sw;
	char arcflag = 0;
	char quotflag = 0;
	long cc;
	struct msgmain msgmain;
	char prtfile[16];
	char pagin;

	signal(SIGINT,SIG_IGN);
	signal(SIGQUIT,SIG_IGN);
	sprintf(prtfile,"/tmp/CPrt%d",getpid());
	cc=usersupp.lastseen[curr_rm]+1L;
	if (usersupp.flags & US_LASTOLD) --cc;
	file=eopen("./MMstructure",O_RDONLY);
	a=read(file,&msgmain,sizeof(struct msgmain)); if (a<1) interr(45);
	close(file);
	for (a=b; ((a<MSGSPERRM)&&(a>=0)); a=a+rdir) {
		while ( (fullroom.FRnum[a]==0L)
		||  (fullroom.FRnum[a]<msgmain.MMlowest)
		|| ((c==1)&&(fullroom.FRnum[a]<cc))
		|| ((c==2)&&(fullroom.FRnum[a]>=cc))
			) {
			a=a+rdir; if ((a==MSGSPERRM)||(a==(-1))) return(0);
			}
RAGAIN:		pagin=((arcflag==0)&&(quotflag==0)&&
			(usersupp.flags & US_PAGINATOR)) ? 1 : 0;

	/* if we're doing a quote, set the screenwidth to 72 temporarily */
		if (quotflag) {
			hold_sw = usersupp.USscreenwidth;
			usersupp.USscreenwidth = 72;
			}

	/* now read the message... */
		if(quotflag)
			e=readq(fullroom.FRpos[a],pagin);
		else
			e=read_message(fullroom.FRpos[a],pagin);

	/* ...and set the screenwidth back if we have to */
		if (quotflag) {
			usersupp.USscreenwidth = hold_sw;
			}
RMSGREAD:	fflush(stdout);
		highest_msg_read = fullroom.FRnum[a];
		if (quotflag) {
/*			dup2(oldstdout,stdout);
			freopen("/dev/console","r+",stdout); */
			quotflag=0;
			process_quote();

                        if (entmsg(1,(DEFAULT_ENTRY==46 ? 2 : 0))==0)
			a=a-rdir;
			goto RMSGREAD;
			}
		if (arcflag) {
			freopen("/dev/tty","r+",stdout);
			arcflag=0;
			f=fork();
			if (f==0) {
				freopen(prtfile,"r",stdin);
				setuid(getuid()); /* use real uid & gid */
				setgid(getgid());
				sttybbs(SB_RESTORE);
				system(getenv("PRINTCMD"));
				sttybbs(0);
				unlink(prtfile);
				exit(0);
				}
			if (f>0) do {
				g=wait(NULL);
				} while((g!=f)&&(g>=0));
			printf("Message printed.\n");
			}
		if (e==2) return(0);
		if ((usersupp.flags&US_NOPROMPT)||(e==1)) e='n';
		else {
			if (rdir==1) printf("(%d) ",MSGSPERRM-a-1);
			printf("<R>eply ");
			if (getenv("PRINTCMD")!=NULL) printf("<P>rint ");
/*		printf("\\_________________________________________________________________________/\n\n"); */
		printf("<B>ack <A>gain <Q>uote <H>eader <N>ext <S>top <E>nter -> ");
			do {
				e=(inkey()&127); e=tolower(e);
/* return key same as <N> */ 	if (e==13) e='n';
	if((usersupp.axlevel<6)&&(usersupp.eternal!=quickroom.QRroomaide))
/* del/move for aides only */	if ((e=='d')||(e=='m')) e=0;
/* print only if available */	if ((e=='p')&&(getenv("PRINTCMD")==NULL)) e=0;
/* can't move from Mail> */	if ((e=='m')&&(curr_rm==1)) e=0;
/* can't reply in public rms */	/* if ((e=='r')&&(curr_rm!=1)) e=0; */
				} while((e!='a')&&(e!='n')&&(e!='s')
					&&(e!='d')&&(e!='m')&&(e!='p')
					&&(e!='q')&&(e!='b')&&(e!='h')
					&&(e!='r')&&(e!='e'));
			switch(e) {
				case 's':	printf("Stop\r");	break;
				case 'a':	printf("Again\r");	break;
				case 'd':	printf("Delete\r");	break;
				case 'm':	printf("Move\r");	break;
				case 'n':	printf("Next\r");	break;
				case 'p':	printf("Print\r");	break;
				case 'q':	printf("Quote\r");	break;
				case 'b':	printf("Back\r");	break;
				case 'h':	printf("Header\r");	break;
				case 'r':	printf("Reply\r");	break;
				case 'e':	printf("Enter Msg\r");	break;
				}
			if (usersupp.flags & US_DISAPPEAR)
				printf("%75s\r","");
			else
				printf("\n");
			}
		switch(e) {
		   case 'p':	fflush(stdout);
				freopen(prtfile,"w",stdout);
				arcflag = 1;
				goto RAGAIN;
		   case 'q':	fflush(stdout);
				quotflag = 1;
				goto RAGAIN;
		   case 's':	return(0);
		   case 'a':	goto RAGAIN;
		   case 'b':	a=a-(rdir*2);
				break;
		   case 'd':	printf("---> Delete this message? ");
				if (yesno()==1)
					delete_message(fullroom.FRnum[a]);
				break;
		   case 'm':	if (move_message(fullroom.FRpos[a],
					fullroom.FRnum[a])==0)
					delete_message(fullroom.FRnum[a]);
				break;
		   case 'h':	read_message(fullroom.FRpos[a],READ_HEADER);
				goto RMSGREAD;
		   case 'r':	if (entmsg(1,(DEFAULT_ENTRY==46 ? 2 : 0))==0)
					a=a-rdir;
				goto RMSGREAD;
		   case 'e':	entmsg(0,0);
		   		goto RMSGREAD;
			}
		} /* end for loop */
	} /* end read routine */

save_message(mtmp,rec,mtsflag,mailtype)
char mtmp[];			/* file containing proper message */
char rec[];			/* Recipient (if mail) */
char mtsflag;			/* 0 for normal, 1 to force Aide> room */
int mailtype; {			/* local or remote type, see citadel.h */
	int a,d,e,file;
	long aa,ee;
	struct usersupp tempUS;
	char aaa[100];

	lock_msgmain();
	send_message(mtmp,&smreturn);
	hold_rm=(-1);
	if (TWITDETECT) if (usersupp.axlevel==2) {
		if (twitroom<0) loadtroom();
		hold_rm=curr_rm;
		curr_rm=twitroom;
		gotocurr();
		}
	if (mtsflag) {
		hold_rm=curr_rm;
		curr_rm=2;
		gotocurr();
		}
	sprintf(aaa,"./rooms/fullrm%d",curr_rm);
	file=eopen(aaa,O_RDWR);
	a=read(file,&fullroom,sizeof(struct fullroom)); if (a<1) interr(49);
	if (curr_rm==1) readmail();
	for (a=0; a<(MSGSPERRM-1); ++a) {
		fullroom.FRnum[a]=fullroom.FRnum[a+1];
		fullroom.FRpos[a]=fullroom.FRpos[a+1];
		}
	fullroom.FRnum[MSGSPERRM-1]=smreturn.smnumber;
	fullroom.FRpos[MSGSPERRM-1]=smreturn.smpos;
	lseek(file,0L,0);
	a=write(file,&fullroom,sizeof(struct fullroom)); if (a<1) interr(50);
	close(file);

	file=eopen("quickroom",O_RDWR);
	aa=(long)(curr_rm * sizeof(struct quickroom));
	lseek(file,aa,0);
	a=read(file,&quickroom,sizeof(struct quickroom)); if (a<1) interr(52);
	quickroom.QRhighest=fullroom.FRnum[MSGSPERRM-1];
	lseek(file,aa,0);
	a=write(file,&quickroom,sizeof(struct quickroom)); if (a<1) interr(53);
	close(file);
	readyerself();
	++usersupp.posted;
	if (curr_rm==twitroom) usersupp.generation[twitroom]=quickroom.QRgen;
	writeyerself();
	if (curr_rm!=1) goto ENTFIN;	/* if mail, there's still more to do */
	writemail();			/* keep a copy for yourself */
	if (mtsflag) goto ENTFIN;
	if (mailtype!=M_LOCAL) {
		printf("Filing network mail...\n");
		if ((a=fork())==0) {
			chdir(BBSDIR);
			execlp("netmailer","netmailer",mtmp,&mailtype,NULL);
			printf("*** Netmailer not installed.\n");
			exit(0);
			}
		do {
			d=wait(NULL);
			} while((d!=a)&&(d!=(-1)));
		}
	if (mailtype==M_LOCAL) {
		file=eopen("usersupp",O_RDWR);
		ee=finduser(file,rec);
		if (ee!=(-1L)) {
			read(file,&tempUS,sizeof(struct usersupp));
			for (e=0; e<(MAILSLOTS-1); ++e) {
				tempUS.mailnum[e]=tempUS.mailnum[e+1];
				tempUS.mailpos[e]=tempUS.mailpos[e+1];
				}
			tempUS.mailnum[MAILSLOTS-1]=smreturn.smnumber;
			tempUS.mailpos[MAILSLOTS-1]=smreturn.smpos;
			lseek(file,ee,0);
			write(file,&tempUS,sizeof(struct usersupp)); 
			}
		close(file);
		}

ENTFIN:	if (TWITDETECT) if (hold_rm!=(-1)) {
		curr_rm=hold_rm;
		gotocurr();
		}
	if (mtsflag) { 
		curr_rm=hold_rm;
		gotocurr();
		}
	unlink(mtmp);
	unlock_msgmain();
	return(0);
	}

/*
 * qform()  -  print a message to a stream
 */
qform(width,spos,msgfile,pagin)
int width;	/* screen width */
long spos;	/* starting position in message file */
char *msgfile;	/* name of message file */
char pagin;	/* 0 = normal read, 1 = read with pagination,
		   2 = header only, 3 = message body only */
	{
	struct tm *tm;
	int a,b,e,mtype,aflag;
	int lines_printed = 2;
	char bbb[1024];
	char m_author[128];
	char m_node[128];
	char m_subject[256];
	FILE *fp,*myfp;
	long now;

	strcpy(m_author,"");
	strcpy(m_node,NODENAME);
	strcpy(m_subject,"");
	
/* 	clearcon(); */

	fp=fopen(msgfile,"rb");
	myfp=fopen(editorfile,"w");
	if (fp==NULL) return(1);
	fseek(fp,spos,0);
	e=getc(fp);
	if (e!=255) {
		printf("*** CANNOT LOCATE MESSAGE / pos=%ld\n",spos);
		return(1);
		}
	mtype=getc(fp); aflag=getc(fp);
 	fprintf(myfp,"\n");
	if (mtype==MES_ANON){
		setcolor(WHITE,B_BLUE);
		fprintf(myfp,"From     :");
		setcolor(CYAN,B_BLACK);
		fprintf(myfp," -----\n");
		}
	if (mtype==MES_AN2) {
		setcolor(WHITE,B_BLUE);
		fprintf(myfp,"From     :");
		setcolor(CYAN,B_BLACK);
		fprintf(myfp," <anonymous>\n");
		}

   do {
	b=getc(fp);
	if ((pagin==READ_MSGBODY)&&(b!='M')) b = 1;
	if (b=='M') {
		if (strlen(m_subject)!=0) {
			setcolor(WHITE,B_BLUE);
			fprintf(myfp,"Subject  :");
			setcolor(CYAN,B_BLACK);
			fprintf(myfp," %s\n",m_subject);
			}
		setcolor(RED,B_BLACK);
		fprintf(myfp,"\n=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=(=\n\n");
		setcolor(WHITE,B_BLACK);
		if (pagin==READ_HEADER) while(getc(fp)>0) ;
		else if (aflag!=1) qout(width,fp,pagin,usersupp.USscreenheight,myfp);
		   else while(a=getc(fp), a>0) {
			if (a==13) a=10;
			putc(a,myfp);
			if (a==10) {
				++lines_printed;
				if ( ((lines_printed %
				   (usersupp.USscreenheight-8))==0)
				   && (pagin==1)) {
					hit_any_key();
					}
				}
			if (ftell(fp)>=MM_FILELEN) fseek(fp,0L,0);
			}
		}
	if ((b!='M')&&(b>0)) fpgetfield(fp,bbb);

           if ( (mtype!=MES_ANON && mtype!=MES_AN2)
             || (usersupp.axlevel >= 6)
	     || (usersupp.eternal == quickroom.QRroomaide) ) {
	if (b=='A') {
		setcolor(WHITE,B_BLUE);
		fprintf(myfp,"From     :");
		setcolor(CYAN,B_BLACK);
		fprintf(myfp," %s\n",bbb);
		strcpy(m_author,bbb);
		}
	if (b=='P') strcpy(reply_to,bbb);
	if (b=='U') {
		 strcpy(m_subject,bbb);
		 strcpy(reply_subj,bbb);
		 }
	if ((pagin==READ_HEADER)&&(b=='P')) fprintf(myfp,"\nPath      : %s\n",bbb);
	if ((pagin==READ_HEADER)&&(b=='I')) fprintf(myfp,"\nMessage ID: %s\n",bbb);
	if ((b=='H')&&(strucmp(bbb,HUMANNODE))) fprintf(myfp,"(%s) ",bbb);
	if (b=='O'){
		setcolor(WHITE,B_BLUE);
		fprintf(myfp,"Room     :");
		setcolor(CYAN,B_BLACK);
		fprintf(myfp," %s\n",bbb);
		}
	if ((b=='N')&&((quickroom.QRflags&QR_NETWORK)||((strucmp(bbb,NODENAME)
	   &&(strucmp(bbb,FQDN))))))
		fprintf(myfp,"@%s ",bbb);
	if (b=='N') strcpy(m_node,bbb);
	if (b=='R') {
		setcolor(WHITE,B_BLUE);
		fprintf(myfp,"To       :");
		setcolor(CYAN,B_BLACK);
		fprintf(myfp," %s\n",bbb);
		}
	if (b=='T') {
		now=atol(bbb);
		tm=(struct tm *)localtime(&now);
		strcpy(bbb,asctime(tm)); bbb[strlen(bbb)-1]=0;
		strcpy(&bbb[16],&bbb[19]);
		setcolor(WHITE,B_BLUE);
		fprintf(myfp,"Posted On:");
		setcolor(CYAN,B_BLACK);
		fprintf(myfp," %s\n",&bbb[4]);
		}
              }
	   } while ((b!='M')&&(b>0));
	fprintf(myfp,"\n"); fclose(fp);
	e=0;
	for (a=0; a<strlen(m_node); ++a) if (m_node[a]=='.') ++e;
	if (e==0) {
		if (!strucmp(m_node,NODENAME)) strcpy(reply_to,m_author);
		else sprintf(reply_to,"%s @ %s",m_author,m_node);
		}
	fclose(myfp);
	return(0);
}

readq(pos,pagin)	/* Read a message from the master file */
long pos;	/* Position in master file */
char pagin;	/* 0 = normal read, 1 = read with pagination, 2 = header */
{
	int a;
	FILE *myfp;
	a=setjmp(nextbuf);
	sttybbs(0);
	if ((a==1)||(a==2)) {
		printf("\n\n");
		return(a);
		}
	signal(SIGINT,backnext);
	signal(SIGQUIT,backstop);
	sttybbs(1);
/*	clearcon();
	setcolor(RED,B_BLACK);
	printf("---------------------------------------------------------------------------");
	myfp=fopen(editorfile,"w"); */
	qform(usersupp.USscreenwidth,pos,"msgmain",pagin);
	sttybbs(0);
	return(0);
}
