/****************************************************************
 *   Metal Message System read message functions
 *
 *	File:  MEREAD.C
 *
 *	Metal Message System and Z-Msg are Trademarked and
 *	       Copyright (c) 1984,1985,1986 Tim Gary
 *			All Rights Reserved.
 *
 ****************************************************************
 *
 * 1.50xx 03/05/86  Allow read options in any order (MNQK...)
 * 1.50xx 03/05/86  Record time message was read if its to this user..
 * 1.50xx 03/01/86  New routines for read. Tagged message and Mail  support..
 * 1.40xx 02/28/86  Modified references to msg[].reply to call msg_reply()
 * 1.40xx 02/10/86  Help stuff moved to METHELP library
 * 1.40xx 01/26/86  New format stuff.
 * 1.31a  10/13/85  Release version.  New overlay method allows
 *		    overlay to overlay calling, with return, so read
 *		    routines were moved here to regain needed memory space.
 *		    Modify, write, and print message functions from
 *		    selective read act on PREVIOUS message in all cases.
 * 1.31xx 08/22/85  File created, for use with new overlay to
 *		   overlay support (one level)..
 *
 ****************************************************************/

#include "xpm.h"	/* CPMIO header file for i/o operations.*/
#include "megen.h"	/* general defines		*/
#include "meglob.h"	/* global variable definitions	*/
#include "meovfn.h"	/* overlay function numbers	*/
#include "mefiles.h"	/* file names			*/

#include "ctype.h"

#define READHELP    "MSGREAD HLP"
#define	SELRDHELP   "MSGSRD  HLP"
#define	SELRDSOHELP "MSGSRDSOHLP"

static unsigned temp_lmsg=0;	/* so reply to a message entered during read is not shown */


ovmain(func,parm)
int func;		/* not used in this overlay */
unsigned parm;
{
readmsgs(parm);		/* all that's here for now */
}


/***************************
 * help for read functions *
 ***************************/

read_help(mode)
 unsigned mode;
{

if (!(mode&READ_NEW)) ltype(METHELP,READHELP);

if (mode & 0x8000) search_help();
}


selrd_help()
{
if (ltype(METHELP,SELRDHELP)!=ERROR)
	if (user.status==SYSOP) ltype(METHELP,SELRDSOHELP);
}


/******************************************
 *  Read messages routine.		  *
 *  Code is much clearer, and is not	  *
 *  dependent on message structure.	  *
 ******************************************/

readmsgs(mode)
 unsigned mode;
{
int flag;			/* flag for various things ERROR=abort	*/
int read_flag;			/* flag for something read or not	*/
unsigned *msg_tbl,*ms_t;	/* table of message numbers to read	*/

#ifdef MULTI_USER
  mu_update();
#endif

if (!msgcount)
       {
       send("\nSorry, there are currently no messages posted.\n");
       return;
       }

novhelp();

if (strloc==0 && !(user.flags&EXPERT) ) read_help(mode);

   /* allocate space for selected msgs */

msg_tbl=malloc( mindex * sizeof(unsigned) );

   /*
    *  Loop the Loop...
    */

  do	{
	if (get_range(&mode,msg_tbl)==ERROR)
		{
		mode=0;		/* clear to default mode(s) */
		break;
		}

	read_flag=FALSE;	/* nothing read yet...enable read loop */

	if ((messages=open(MESSAGES,F_RD | F_UNLOCK))==NULL)
	       {
	       send("\nUnable to open messages file.\n");
		read_flag=TRUE;		/* Don't go through loop,.. error */
	       break;
	       }

	temp_lmsg=lmsg;		/* save lmsg before read (readm uses this) */

	for (flag=FALSE, ms_t=msg_tbl;  *ms_t && flag!=ERROR; ms_t++)
		{
		flag=readm(*ms_t,mode,FALSE);
		if (flag!=0) read_flag=TRUE;
		}

if (!read_flag)
	send("\n[Nothing found.  Message(s) either private or deleted.]");

close(messages);
} while ( (flag != ERROR) && (mode & READ_ONE) );

free(msg_tbl);		/* make sure we get back memory */

putchar('\n');

} /* readmsgs */


/************************************
 * Get range function for read msgs *
 ************************************/

get_range(pmode,ms_t)
 unsigned *pmode,*ms_t;
{
register struct msg_ind *mfast;	/* pointer to main message table */
char *tp;			/* temp string pointer	*/
unsigned msgnum=0;		/* current msg num	*/
unsigned orig_mode;		/* copy of original mode*/
int sreq;			/* search request flag	*/

orig_mode=(*pmode);		/* save original mode	*/

do {   /* silly do concept */

   (*pmode)=orig_mode;	/* make sure mode is reset	*/
   setmem(buffer,MAXLINE,0);	/* make sure this is empty!!	*/

   /* see if READ_NEW or READ_MAI are set, no prompt if so */

   if ( !( (*pmode) & (READ_NEW | READ_MAI) ) )
       {
       do {
	  if (user.flags&EXPERT)
	     sprintf(buffer,"\nRead (first=%u, last=%u)? ",fmsg,lmsg);
	   else sprintf(buffer,"\nRead which message (first=%u, last=%u, '?' for help)? ",fmsg,lmsg);
	  ask(buffer,buffer,MAXLINE,UP);
	  if (*buffer=='?') read_help(*pmode | 0x8000);
	  } while (*buffer=='?');
       }


    while (*buffer && index("KQNMT",*buffer))
	{
	switch (*buffer) {
		case 'K':
			(*pmode)|=READ_KIL;	/* Read Killed msgs */
			break;
		case 'Q':
			(*pmode)|=READ_Q;	/* Read quietly */
			break;
		case 'N':
			(*pmode)|=(READ_NEW | READ_ONE);  /* Read New */
			break;
		case 'M':
			(*pmode)|=READ_MAI;	/* Read mail to you */
			break;
		case 'T':
			if (buffer[1]!=':') (*pmode)|=READ_TAG;	 /* Tagged */
			break;
		} /* switch */

	sprintf(buffer,"%s",buffer+1);	/* trash char now.. */
	} /* while */

	if (strlen(buffer)>0) sreq=msearch(buffer);
		else sreq=0;

	if ( (*pmode) & READ_NEW ) msgnum=user.lastread+1;
	   else	  {
	          if (isdigit(*buffer))
		       {
		       if ( ((msgnum=atoi(buffer))>lmsg) || (msgnum<0))
			       {
			       if (*buffer!='\0')
				       send("\n[Message out of range]\n");
			       strloc=0;    /* clear this global pointer */
			       return ERROR;
			       }
		       } else if (sreq || ((*pmode) & (READ_MAI | READ_TAG)) ) 
					{
					msgnum=1;  /* and start at msg 1 */
					*buffer='+';
					}
				 else
				   if ( !((*pmode) & (READ_MAI | READ_TAG) ) )
					return ERROR;
	       } /* READ_NEW else test */

	if (msgnum==0) ++msgnum;        /* convert a zero to a one */

	if (msgnum>lmsg)
		{
		send("\n[Message out of range]");
		strloc=0;
		return ERROR;
		}

	/* Set direction acordingly... */

	if ( ( (tp=index(buffer,'-')) < buffer+8) && tp )
		(*pmode) = READ_REV | ( (*pmode) & (0xffff ^ READ_ONE) );
	   else
	    if ( ( (tp=index(buffer,'+')) < buffer+8) && tp )
		(*pmode)&= (0xffff ^ READ_ONE);	  /* Turn off READ_ONE */


/* All options and modes are reduced by now, so start setting
 * up messages in table
 */

	/* if only one message, put it in table if found..  0 otherwise */

	if ( (*pmode) & READ_ONE )
		{
		if (getindex(msgnum)!=ERROR) *(ms_t++)=msgnum;
		   else	{
	  		printf("\n[Message %u not found]",msgnum);
			continue;
			}
		break;
		}


	/* if read reverse simple loop from end of msg[] to beginning */

	if ( (*pmode) & READ_REV )
		{
		for (mfast=msg+(mindex-1); mfast>=msg; mfast--)
		   {
		   if (mfast->number && (mfast->number)<=msgnum)
			{
			*(ms_t++)=mfast->number;
			if (
			    ( (*pmode & READ_TAG) && !((mfast->flags)&TAGGED) )
			   || ( (*pmode & READ_MAI) && !((mfast->flags)&MAIL) )
			   ) ms_t--;

			   }
			}	/* for */
		break;
		}
	

  /* It's not READ_ONE or READ_REV, has to be forward read.
   *    NOTE: this ONLY places messages without parents<msgnum in table!
   */

	for (mfast=msg; mfast<msg+mindex; mfast++)
		{
		if (mfast->number && (mfast->number)>=msgnum)
			{
			if ( (*pmode) & (READ_TAG | READ_MAI) )
			  {
			  if ( ( (*pmode&READ_TAG) && ((mfast->flags)&TAGGED) )
			    || ( (*pmode&READ_MAI) && ((mfast->flags)&MAIL) ) )
				*(ms_t++)=mfast->number;  /* place in table */
			  }
			else if ((mfast->parent)<msgnum) 
				*(ms_t++)=mfast->number;  /* place in table */
			}

		} /* for */


    break;	       /* I know.. weird */

    } while (1);

if ( !((*pmode) & READ_SEL) && !(user.flags & EXPERT) )
       send("\nControl-O skips to the next message.\n");

*ms_t=0;	/* terminate table */
return NULL;   /* done, ok */

} /* get_range */


/* This thing is recursive so the entire reply chain can be read */

readm(num,mode,flag)
 unsigned num;
 int mode,flag;
{
unsigned tnum;

if (flag==ERROR) return ERROR;

if ( (flag=rm(num,mode)) == ERROR) return flag;

tnum=num;
if ( !( mode & (READ_REV | READ_ONE | READ_TAG | READ_MAI) ) )
  while ( (tnum=msg_reply(num,tnum)) && flag!=ERROR && tnum<=temp_lmsg)
	flag=readm(tnum,mode,flag);

return flag;
}


extern char prevsender[],status;
extern unsigned prevmsg;

/* This routine displays the message, it's header, from current place in file
 *  expects message number, and read mode given to it.
 *  returns ERROR if break hit, or can't read a record
 *  returns NULL if not addressed to user and private, or not selected
 *  returns #of lines if read.....
 */

rm(msgnum,rd_mode)
 unsigned msgnum;
 int rd_mode;
{
 int lns;
 unsigned saveseek;
 char str[3],ttt[80];
 int c;
 unsigned ind;
 char tsender[NAMELEN+1];

ind=getindex(msgnum);	/* this should always be passed correct valid number */

if (breakkey()) return ERROR;

rd_mode&=(READ_KIL | READ_Q | READ_SEL);

  /* Silly loop to avoid goto..  Allows for single exit point */

do {
 setarec(messages,(saveseek=msg[ind].seek));	/* seek to message, save pos */
 lns=msgheader(messages,0,2 | rd_mode);		/* read message struct hdr   */

 status=message.status;
 if (lns==ERROR || lns==NULL) break;

 strcpy(tsender,message.sender);

 if (rd_mode & READ_SEL)			/* selective read */
	{
	if (user.status==SYSOP) send("[y/n/r/t/u/p/w/e/d/k/m/q]");
	   else if (user.flags&EXPERT) send("[Read? y/n/r/t/u/m/q/?]");
		  else send("[Read? Yes/No/Reply/Tag/Untag/Mod/Quit/Help]");
	while ((c=toupper(getd()))<' ');	/* ignore control chars */
	send(" [");
	if (c=='N') {	send("no]\n");  break;	}

	if (c=='Q') {	send("quit]");	lns=ERROR;	break;	}

	if (prevmsg!=0)
	  {

	  if (c=='M')
		{
		send("modify]\n\n");
		do_ov("[Modify PREVIOUS message header information (subject, etc..) (y/n)? ]",OVSTUFF,EDITMSG,prevmsg,0);
		continue;
		}

	  if (c=='R')
		{
		send("reply]\n\n");
		do_ov("[Reply to PREVIOUS message (y/n)? ]",OVSEND,0,prevmsg,0);
		continue;
		}

	  if (user.status==SYSOP)
	    {
	    int flag;
	    flag=TRUE;

	    switch(c)
	      {
	      case 'K':
		send("kill]\n\n");
		sprintf(ttt,"[Kill PREVIOUS message #%u (y/n)? ]",prevmsg);
		do_ov(ttt,OVKILL,KILL,prevmsg,0);
		break;

	      case 'E':
		send("edit user]\n\n");
		do_ov(0,OVUSER,EDITUSER,0,prevsender);
		break;

	      case 'D':
		send("delete user]\n\n");
		sprintf(ttt,"[Delete PREVIOUS sender (%s) from users file (y/n)? ]",prevsender);
		do_ov(ttt,OVUSER,DELETEUSER,0,prevsender);
		break;

	      case 'P':
	      case 'W':
		if (out_msg(c,prevmsg)) break;
		   else continue;
		break;

	      default:
		flag=FALSE;
		break;
	      } /* switch */
	    if (flag) continue;		/* go back and get header stuff */
	    } /* sysop test */
	  } /* previous message available */


	if (c=='H' || c=='?') {
		send(" ? ]\n\n");
		selrd_help();	/* selective read help */
		continue;
		}

	if (c=='T') {
		send("tag]\n");
		msg[ind].flags|=TAGGED;
		break;
		}

	if (c=='U') {
		send("untag]\n");
		msg[ind].flags&=(0xff ^ TAGGED);
		break;
		}

	send("yes]\n\n");
	} /* mode & READ_SEL */	/* else read the thing */

read(messages,1);		/* read next record */
if (showmsg(lns)==ERROR) {  lns=ERROR; break;	}
putchar('\n');

if (thisis(message.receiver))
	{	/* message was to this guy.. does he want to reply? */
	if (message.date_read[0]==0x00)		/* not tagged read yet */
		{
		msg_record *tmp;
		if (O.RTC) readclock();
		send("\n[Marking message read]\n");
		movmem(date,message.date_read,3);
		movmem(time,message.time_read,2);
		setarec(messages,saveseek);
		movmem(&message,bufloc(messages),128);
		write(messages,0);			/* write new header */

		summary=open(SUMMARY,F_RW | F_UNLOCK);
		setarec(summary,((msg[getindex(message.number)].flags&SUMSEEK)<<5));
		tmp=bufloc(summary);
		do read(summary,1);
		   while (tmp->number!=msgnum);
		setrrec(summary,-1);
		movmem(&message,tmp,128);
		write(summary,0);
		close(summary);
		}	/* message already tagged as read flag */

	if (!(rd_mode & READ_Q))
	   {
	   if (do_ov("\n[Reply to this msg (y/n)? ]",OVSEND,0,msgnum,0)==TRUE)
	        sprintf(ttt,"\n[Kill Message you've just replied to (y/n)? ]");
	      else sprintf(ttt,"[Delete this Message (y/n)? ]");
	   do_ov(ttt,OVKILL,KILL,msgnum,0);
	   putchar('\n');
	   }  /* quiet read mode */

	}

  break;		/* continue gets by this crock */
   } while (1);

if (lns!=NULL && ((rd_mode & READ_KIL) || status!=DEADMSG))
	{
	prevmsg=msgnum;
	strcpy(prevsender,tsender);
	}

return lns;	/* return lines.. */
}


/* do overlay from selective read... special kill msg handling */

do_ov(atext,ovname,ovfn,uparm,cparm)
 char *atext,*ovname,*cparm;
 int ovfn;
 unsigned uparm;
{
int c;
int ret_flag=YES;
char t_glbstr[MAXLINE+1];
int t_strloc;

strcpy(t_glbstr,glbstr+strloc);
t_strloc=strloc;
strloc=0;	/* clear this so READ 123;456;789;1011 things work */

/* prompt and get single letter yes=y, no=other char */
if (atext) ret_flag=yes_no(atext);	

if (ret_flag)
	{
	if (!strcmp(OVKILL,ovname)) close(messages);	/* killmsg req. */

	if (cparm) ovovload(ovname,ovfn,cparm);	/* do char overlay func */
	  else	{
		ovovload(ovname,ovfn,uparm);	/* do unn overlay func	*/
		messages=open(MESSAGES,F_RD | F_UNLOCK);
		}
	putchar('\n');
	}

strloc=t_strloc;
strcpy(glbstr+strloc,t_glbstr);		/* restore this stuff */

return ret_flag;	/* true=we did the overlay */
}


/* This routine prints the message from file ffd, for nl lines */

showmsg(nl)
 register int nl;
{
register int lc;

globalchar='\0';	/* clear this before and after showing msg! */
for (lc=0; lc<nl; lc++)
	{
	fgets(buffer,messages);			/* get a line	*/
	if (index(buffer,'<'+0x80))
		{
		putchar('\n');
		type(index(buffer,'<'+0x80)+1);
		}
	  else if (send(buffer)==ERROR) return ERROR;
	if ((globalchar & 0x1f)==0x0f) break;	/* ^O hit to skip to next */
	}
globalchar='\0';
return 0;
}


/* yes=y, any other=no */

yes_no(text)
 char *text;
{
register int ret_flag,c;
ret_flag=NO;			/* default return value */

send(text);
while ((c=toupper(getd()))<' ');	/* ignore control chars */
if (c!='Y') send(" [no]\n");
    else {
	 ret_flag=YES;
	 send(" [yes]\n");
	 }

return ret_flag;
}


/**********************************************
 * outputs message to printer 'P' or file 'W' *
 **********************************************/

out_msg(place,num)
 int place;
 register unsigned num;
{
register int line_count;
unsigned save_seek;
int ret_flag;

setarec(messages,msg[getindex(num)].seek);	/* place on message to save */

if (place=='P')		/* printer output */
	{
	printf("print msg %u]\n\n",num);  /* next line '=' is on purpose */
	if (ret_flag=yes_no("Print PREVIOUS message (y/n)?"))
		{
		msgheader(messages,0,0x82);	/* read header info.. */
		get_header(2,buffer);
		read(messages,1);	/* for fgets */
		print(buffer);
		for (line_count=0; line_count<message.lines; line_count++)
			{
			fgets(buffer,messages);
			print(buffer);
			print("\r");
			}
		print("\r\n");	/* flush */
		} /* ok.. */
	} 	/* printer output */
/* otherwise, it's to a file.. get name, etc.. */
   else
	{
	char file[MAXLINE+1];
	FILE *fd;
	printf("write msg %u]\n\n",num);	/* Next line '=' on purpose */
	if (ret_flag=yes_no("Write PREVIOUS message to disk file (y/n)?"))
		{
		send("Write message to what file (uu/d:file.nam)? ");
		getl(file,UP);
		if (*file=='\0')
			{
			strcpy(file,"14/a:message.log");
			send("[File 14/A:MESSAGE.LOG assumed]\n");
			}
		save_seek=getrec(messages);
		close(messages);
		reset_disk(0);		/* for cp/m independence later */
		messages=open(MESSAGES,0);
		setarec(messages,save_seek);
		if (fd=open(file,1))
			{
			toeof(fd);	/* go to end to check if exists */
			if (getrec(fd)!=0)
				{
				send("\n[File Exists!]\n");
				if (ret_flag=yes_no("[Append to existing file? ]"))
					{
					setrrec(fd,-1);	/* backup rec */
					read(fd,0);
					while(gchar(fd)!=26);	/* test eof */
					setbuf(fd,getbuf(fd)-1);/* backup 1 */
					}
				   else if (ret_flag=yes_no("[Delete existing file? ]"))
						{
						close(fd);
						unlink(file);
						fd=open(file,1);
						}
					  else {
						send("[Aborting message write]\n");
						close(fd);
						return NO;
						}
				}

			msgheader(messages,0,0x82);	/* read header info */
			get_header(2,buffer);
			read(messages,1);	/* for fgets below */
			fputs(buffer,fd);
			for (line_count=0; line_count<message.lines; line_count++)
				{
				fgets(buffer,messages);
				fputs(buffer,fd);
				send(buffer);
				}
			fputs("\r\n\032",fd);	/* cr/lf and eof */
			write(fd,0);	/* finish up (make sure all written) */
			close(fd);
			}
			else send("\n[Unable to open file]\n");
		} /* y/n */
	} /* output to file */
putchar('\n');
return ret_flag;
}


/* end file MEREAD.C */


