/******************************************************************************
 *	Metal Enter (send) message routine.
 *
 *	File name: MESEND.C
 *
 *   Metal and Metal Message System are Trademarked and
 *	    Copyright (c) 1984,1985,1986 Tim Gary
 *		    All rights reserved.
 *
 *	This module contains the message entry routine (enter, reply, etc)
 *
 *****************************************************************************
 *
 * 1.50xx 08/13/86 User.phone klude stuff added, fix for new free_space
 * 1.50xx 08/04/86 Disable wrap flag set for upload mode.
 * 1.50xx 04/12/86 Warning added for max message lines..
 * 1.50xx 03/17/86 Group menu fixed, allow full/partial group "Name" selection
 * 1.50xx 03/10/86 Group/section menu added for entering a message..
 * 1.50xx 03/06/86 Faster summary lookup..
 * 1.50xx 03/04/86 Fix bug causing messages to be tagged..
 * 1.40xx 02/28/86 Deleted msg[].reply references..  use msg_reply()..
 * 1.40xx 02/10/86 Help displays from help library..
 * 1.40xx 02/06/86 Check for sysop made before valid receiver test..
 * 1.40xx 02/05/86 Added check for valid user when entering message..
 * 1.40xx 01/26/86 New format of time/date, etc..
 * 1.31a  10/13/85 Release version.  Cosmetic changes,  Check for disk space
 *		   remaining before allowing message entry.
 * 1.30xx 6/15/85  Subject of APPLY command 'New User Application'.
 * 1.30xx 6/09/85  EOL char added for edit command, subject ok prompt fixed.
 * 1.30xx 3/03/85  Z3 stuff looked into and general touchups
 * 1.20b 01/10/85  Add link to messages for sysop enter message..
 * 1.20b 01/07/85  Alternate end of message text char, and blank line accept
 * 1.20a 11/07/84  Subject confirmation on reply.
 * 1.20a 11/04/84  Apply stuff added, private msg to sysop.
 * 1.10e 11/02/84  Fixed for new get/put counters.
 * 1.10e 10/30/84  Added privmsgs counter.
 * 1.10b 10/02/84  Cosmetics (deleted extra spaces).
 * 1.10a  9/28/84  Edit bug looked into.
 * 1.10a  9/27/84  More cosmetic fixes.
 * 1.10a  9/14/84  Added simplistic line edit of message text...
 * 1.10a  9/01/84  Routine taken from MS.C for overlay metal.
 *
 * 1.01a  7/14/84  Message editing bugs fixed (delete line.. movmem changed).
 *		   Added subject truncation notice on message entry.
 * 1.01a  6/30/84  Cleaned up more functions.
 * 1.01a  6/26/84  Cleaned up a few functions, and added MULTI_USER stuff.
 * 1.01a  6/10/84  Fixed to work with Aztec C 1.06. Started Multi-user stuff.
 *
 * 1.0b	  4/13/84  Modified for upper/lower case names, and added check for
 *		maximum messages allowed (killed and active ones).
 *
 * 1.0a	  3/16/84  Fixed reply bug.
 *
 * 1.0	  1/20/84  New format of Message file headers.
 * p3.0	 12/14/83  pre-release version 3.0 mods for MCONFIG..
 *
 *****************************************************************************/

#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	NOPOSTHLP  "MSGNOPSTHLP"
#define	PRIVHLP	   "MSGPRIV HLP"
#define	ENTERHELP  "MSGENTERHLP"
#define	UPLOADHLP  "MSGUPLD HLP"

static char *lp[MAXMLINES];	/* array of pointers to msg text lines */

/************************************************************************** 
 * enter a message, or reply to a message... mode=0 to enter, -1 to reply *
 *	or msg # to reply without asking for #.. (ie for read/reply)	  *
 **************************************************************************
 * if func=0, then reply or enter, if func=1 then APPLY command, private
 *    message to sysop (subject 'New User Application'), func=2 then comments
 *    to the system.. 
 */

ovmain(func,mode)
 int func;		/* definition required, but variable not used */
 unsigned mode;
{
char *ptr,temp[81],*reserve;	/* reserve=reserved alloc block for files */
int a,b,c,edit_mode;
unsigned space_left,free_space();
register int loop,line;

if (!(user.type_ptr->privflags & POSTMSG) && func<1)
	{
	ltype(METHELP,NOPOSTHLP);  /* user can't post messages til sysop.. */
	return;
	}

summary=open(SUMMARY,F_RD);
space_left=free_space(summary->_fcb.f_drive);
close(summary);	            /* effect of loging disk */

if ((totalmsgs>=O.MAXTOTMSGS) || (msgcount>=O.MAXMSGS) || space_left<10)
	{
	send("\nSorry, the message base is full.\nPlease try to leave your message at a later time.");
	return;
	}

if (mode==0)	/* regular msg entry */
	{
	if (func<1)
		{
	GET_TO:	ask("Who to (RETURN for all) ? ",
			message.receiver,NAMELEN,UPLOW);
		capstr(message.receiver);
		if (message.receiver[0]=='\0') strcpy(message.receiver,"ALL USERS");
		  else	{
			users=open(USERFILE,0);
			if (ustrcmp(message.receiver,"sysop"))
			   if (find_user(message.receiver)<0)
				{
				send("\n[There is nobody on the system by that name]\n");
				ask("Enter message anyway (y/n)? ",temp,2,UP);
				users=close(users);
				putchar('\n');
				if (*temp=='N') goto GET_TO;
				}
			users=close(users);
			}
		}
	   else {
		strcpy(message.receiver,"Sysop");
		send("To: Sysop\n");
		}
	if (func!=1) { if (get_topic(message.topic)==ERROR) return; }
	   else {
 		strcpy(message.topic,"* New User Application *");
		askquest();   /* ask sysop defined qestion */
		}
       }
       else
	{	/* reply to message */
	if ((int)mode==-1)	/* regular reply command.. */
	 	{
	 	ask("Reply to what message ? ",temp,6,UP);
	 	if (!isdigit(*temp)) return; /* not alpha, return to command */
		mode=atoi(temp);	/* convert to number */
		if (!mode) return;	/* invalid message #=0 */
		messages=open(MESSAGES,F_RD | F_UNLOCK);
			/* the following assumes open file */
		}
	/* both regular and read/reply use the following */
	/* mode=message number replying to */
	/* file must be open before...  from read, or whatever.. */
	a=getindex(mode);	/* get index into msg array, of msg mode */
	if (a==ERROR)
		{
		close(messages);
		send("\n[Message not found]\n");
		return;
		}
	setarec(messages,msg[a].seek);	/* seek to message replying to */
	read(messages,0);	/* get the header */
	movmem(bufloc(messages),&message,128);	/* get stuff into structure */

	strcpy(message.receiver,message.sender);
	printf("\nTo: %s\nAbout: %s   ** %s **",
		message.receiver,message.topic,group[message.group].name);
	close(messages);	/* close the file */
	do 
	   send("\n[Is the subject ok (y/n)? ] ");
	 while ((c=tolower(getd()))!='n' && c!='y');
	if (c=='n')
		{
		send("[no]\n");
		if (get_topic(message.topic)==ERROR) return;
		}
	   else	send("[yes]\n");

	if (message.status==DEADMSG) mode=0;	/* make rest of stuff nonrep */
	}	/* end of initial reply stuff all the rest of entermsg is
	      as it was, except to end where pointers are setup to the reply */

if (func>=1)
	{
	send("\nMessage will be Private.\n");
	message.status=PRIVMSG;
	}
 else
  do {
   message.status=NORMMSG;	/* default to normal message */
   if (strcmp(message.receiver,"ALL USERS") ||
        !(user.type_ptr->privflags & POSTPRIV))
     {
     send("(Private/Normal) ?");
     getl(buffer,UP);
     *buffer=tolower(*buffer);
     } else *buffer='n';
   if (*buffer=='p') message.status=PRIVMSG;		/* private msg */
     else if (*buffer=='?')
		{
		ltype(METHELP,PRIVHLP);
		continue;	/* and ask again */
		}
     else if (*buffer!='n') send("[Normal (public) message]\n");
   break;	/* what, you say???  yeh, yeh.. see the continue above?? */
   } while (TRUE);

 if ( !(user.flags&EXPERT) )		 /* not expert.. tell him what to do */
	{
	sprintf(buffer,
"\nEnter message text following each line number.\
\nTo edit or end, hit RETURN alone on a line.\
\nUp to %d characters (letters/numbers) on a line,\
\nand %d lines maximum.\n",O.MAXMSGLINE,O.MLINES);
	send(buffer);
	}

reserve=malloc(2*(sizeof(FILE))+10);	/* make sure there's room for files */
edit_mode=ON;	/* blank line to enter editor */

/********************************/
/* Lines may be up to MAXMSGLINE long, and up to MLINES lines	*/
/*   can be entered... limitted by avaliable memory only! 	*/
/********************************/
/* Main loop	*/
/****************/

 for (line=1; line<=O.MLINES; line++)
	{
  cont:	printf("%2d%c ",line,edit_mode ? ':' : '/');
	getl(buffer,UPLOW+(edit_mode ? MSGLINE : 0));	/* get line up to MAXLINE long */
	if ((edit_mode==ON && *buffer=='\0') ||
		(edit_mode==OFF && !strcmp(buffer,"/")) ) break;
	if (save_line(line,buffer)==ERROR) break;
	/* above allocs space, and puts line there if room.. ERROR==no room */
	if (line>O.MLINES-3) send("::: 3 lines left :::\n");
	}
 do	{
	if ( !(user.flags&EXPERT) )
		{
		send("\n(A)bort,  (C)ontinue, (D)elete, (E)dit,\n\
(I)nsert, (L)ist, (R)eplace, (S)ave");
		if (user.status==SYSOP) send("\n(F)ile read");
		send(" :: Select");
	   }
	   else
		if (user.status!=SYSOP) send("\nA,C,D,E,I,L,R,S,U");
		   else send("\nA,C,D,E,I,L,R,S,U,F");
	sepstr=' ';
	ask(" ? ",temp,10,UP|NOTOS);
	sepstr='\0';
	switch (*temp)
		{
	case '?':
		ltype(METHELP,ENTERHELP);
		if (user.status==SYSOP)
			send("\n(F)ile transfer to message text\n");
		break;
	case 'A':
		ask("Are you sure you wish to abort message entry? ",
			buffer,3,UP);
		if (*buffer!='Y') break;	/* nope, not sure */
		for (loop=0; loop<line-1; loop++) free(lp[loop]);
		free(reserve);
		return;
	case 'C':
		if (line>O.MLINES+10) break;  /* can cheat 10 times */
		goto cont;	/* yuk!!!!!!!!!!!!! */
	case 'D':
		line=del_line(line);
		break;
	case 'E':
		edit_line(line);
		break;
	case 'F':
		if (user.status==SYSOP) line=read_file(line);
		break;
	case 'I':
		line=ins_line(line);
		break;
	case 'L':
		for (loop=1; (loop<line) && (!breakkey()); loop++)
			printf("\n%2d  %s",loop,lp[loop-1]);
		putchar('\n');
		break;
	case 'R':
		rep_line(line);
		break;
	case 'S':
		if (line<=1) {
			send("\n[No message text]\n");
			*temp='\0';
			}
		break;		/* another save check later... */
	case 'U':
		if (edit_mode==ON)
			{
			edit_mode=OFF;
			if ( user.flags&EXPERT )
			  send("\n[Upload mode, use \"/\" to finish entry]\n");
			 else ltype(METHELP,UPLOADHLP);
			goto cont;	/* yuk again */
			}
		  else	{
			send("[Normal operation mode ON]\n");
			edit_mode=ON;
			}
		break;
	default:
		strloc=0;
		break;
 		}	/* end switch */
	} while (*temp!='S');	/* get command while not save command */

free(reserve);	/* put space back in memory queue */

#ifdef MULTI_USER

while ((counters=open(COUNTERS,F_RD))==NULL)	/* wait for counters */
	{
	unsigned t;
	send("\nQueued.");
	for (t=0; t<30000; t++);	/* delay a bit */
	}
rename(COUNTERS,"$$$met$$.$$$");
close(counters);
mu_update();		/* see if anything happened.. */

#endif /* multi user */

printf("\n[Saving message #%u]",nextmsg);

/* get new time/date if RTC defined */

if (O.RTC) readclock();

msg[mindex].parent=mode;	/* mode=parent #, or 0 if not reply.. */
msg[mindex].flags=0;		/* no flags on */
msg[mindex].group=message.group;

/* add to message file */

	messages=open(MESSAGES,F_RW | F_UNLOCK);	/* r/w open */
	summary=open(SUMMARY,F_RW | F_UNLOCK);		/* speed reasons.. */
	toeof(messages);		/* seek to end of file */
	message.seek=getrec(messages);	/* get the current cp/m record # */
	message.number=nextmsg;		/* setup structure to be written */
	message.parent=msg[mindex].parent;
	strcpy(message.sender,user.name);
	message.lines=line-1;
	movmem(date,message.date_entr,3);
	movmem(time,message.time_entr,2);
	setmem(message.date_read,3,0);
	setmem(message.time_read,2,0);
	movmem(&message,bufloc(messages),128);	/* copy structure to buffer */

	write(messages,1);

/* deal with summary file */
	movmem(bufloc(messages),bufloc(summary),128);	/* copy msg buffer */

	for (loop=1; loop<line; loop++)
		{
		if (*lp[loop-1]=='<' && user.status==SYSOP) *lp[loop-1]='<'+0x80;
		fputs(lp[loop-1],messages);	/* write the line */
		putc('\n',messages);		/* why not...	  */
		free(lp[loop-1]);	/* free up memory */
		}
	putc('\n',messages);
	if (getbuf(messages)) write(messages,0);	/* flush buffer */
	close(messages);

	toeof(summary);		/* compute file size.. set rr to eof */
 	write(summary,0);

	++msgcount;

	close(summary);

	msg[mindex].number=nextmsg;		/* update number */
	msg[mindex++].seek=message.seek;	/* seek location */
	lmsg=nextmsg++;				/* last msg #  	 */
	++totalmsgs;				/* total active+killed msgs */
	if (message.status==PRIVMSG) ++privmsgs;	/* # private msgs */

/* write new counters.. */
	pcounters(0);

#ifdef MULTI_USER
    unlink("$$$met$$.$$$");
#endif

}	/* enter command */


askquest()
{
char temp_time[2],temp_date[3];
unsigned n;

if (O.QUESTION[0]!='\0')
	{
	while (1) {
	   if (user.phone[0]!='\0') printf("Your previous answer to this question was '%s'.\nPress RETURN to retain this value.\n");
	   ask(O.QUESTION,user.phone,12,UPLOW);
	   if (O.QUESTION[0]=='!' && user.phone[0]=='\0')
		{
		send("\nYou must answer this question if you wish to use this system.");
		continue;
		}
	   break;
	   } 
	n=user.lastread;
	user.lastread=nextmsg ? nextmsg-1 : 0;
	movmem(user.time,temp_time,2);
	movmem(user.date,temp_date,3);
	movmem(time,user.time,2);
	movmem(date,user.date,3);
	send("[saving response]");
	putuser(user.number);	/* write new user info back to file */
	movmem(temp_time,user.time,2);
	movmem(temp_date,user.date,3);
	user.lastread=n;	/* restore last read msg number */
	}

}


/* write user specified to correct place in users file, 0=write to current
   possition in the OPEN users file */ 

putuser(un)
register unsigned un;
{
register usr *up;
register int flag;

if ((users=open(USERFILE,F_RW | F_LOCK))==NULL) return ERROR;   /* else, open it */
up=bufloc(users);
setarec(users,un);
read(users,0);
user.number=up->number;
movmem(&user,bufloc(users),128);	/* get user vars */
user.number=un;
write(users,0);	/* write record, no increment... */
close(users);		/* either method called closes the users file */

return NULL;		/* NULL=all's well */
}


get_topic(s)
 char *s;
{
char temp[81],temp1[81];
register int gr;

sprintf(temp1,"Group (return=** %s **, '?' for list) ? ",group[0].name);
do {
   gr=0;
   ask(temp1,temp,40,UP);
   if (*temp=='\0') break;
   if (*temp=='?')	/* display available groups */
	{
	send("\nEnter one of the following numbers:\n\n");
	for (gr=0; gr<n_groups; gr++)
		{
		if (group[gr].read_flags & user.group_flags)
			{
			sprintf(temp,"%2d. %s\n",gr+1,group[gr].name);
			if (send(temp)==ERROR) break;
			}
		}
	putchar('\n');
	continue;
	}
   if ( (gr=atoi(temp))>0 && gr<=n_groups)
	{
	if (group[gr-1].read_flags & user.group_flags)
		{
		--gr;
		break;
		}
	send("\n[Group not found]\n");
	}
	else   if (!gr)	{
			int i;
			for (i=(-1),gr=0; gr<n_groups; gr++)
				if (usindex(temp,group[gr].name))
					{
					i=gr;
					break;
					}
			if (i!=(-1)) break;
			}

    } while (TRUE);		/* endless */

printf(" ** %s **\n",group[gr].name);
message.group=gr;	/* set this up */

about:	ask("Subject ? ",temp,TOPICLEN,UPLOW);
	if (strlen(temp)>TOPICLEN)	/* tell him it's too long.. */
		{
		temp[TOPICLEN]='\0';	/* truncate topic */
		printf("\nSubject truncated to: %s\n",temp);
		ask("Is this ok (y/n)? ",temp+TOPICLEN+2,2,UP);
		if (temp[TOPICLEN+2]=='N') goto about;	/* ask topic again */
		if (temp[TOPICLEN+2]!='Y') send("[Yes assumed]\n");
		}	/* I'm sick of slandering goto, in certain
			   cases, it makes life much easier... */
	strcpy(message.topic,temp);
	if (!(*message.topic)) return ERROR; /* return hit? yep->return */

return NULL;
}


/********************************************************
 * save line pointed to by buf, in message buffer..	*
 ********************************************************/

save_line(line,buf)
 register int line;
 register char *buf;
{
if ((lp[line-1]=malloc(strlen(buf)+2))==0)	/* try to get space */
	{
	send("\n[Message buffer full!! Line not entered]\n\
[Please save message, and continue in a new one]\n");
	return ERROR;		/* and exit to enter command mode */
	}
strcpy(lp[line-1],buf);	/* setup line pointer for later use */
return NULL;
}


/*****************************************
 * read in a message from a regular file *
 *****************************************/

read_file(line)
 register int line;
{
char file[20];
register FILE *fd;
register int oline;
char *bp;
int i;

oline=line;	/* for ending output of # lines read */

ask("\nFile to copy to message text? ",file,19,UP);
if ((fd=open(file,0))!=NULL)	/* try to open file */
	{
	read(fd,1);	/* fgets needs initial read */
	while (line<=O.MLINES && i!=0x1a && i!=EOF)
		{
		bp=buffer;
		while (1) {
		   if ((i=getc(fd))==EOF) break;
		   if (i=='\r' || i==0x1a)
			break;
		   if (i!='\n') *bp++=i;
		   }
		*bp='\0';	/* terminate string */
		if (save_line(line,buffer)==ERROR) break;	/* no space */
		send("\n");	/* to allow ^s */
		printf("%2d: %s",line++,buffer);
		}
	printf("\n\n[%d lines read from %s]\n",line-oline,file);
	close(fd);
	}
	else send("[File NOT found]");

return line;
}


ins_line(cline)
 register int cline;
{
register char *ptr;
register int ln,loop;
char temp[11];

if (cline<O.MLINES)
	{
	ask("Insert before what line ?",temp,10,UP);
	putchar('\n');
	ln=atoi(temp);
	if ((ln>0) && (ln<=cline))
		{
		printf("%3d: ",ln);
		getl(buffer,UPLOW+MSGLINE);
		if ((ptr=malloc(strlen(buffer)+2))==0)
			{
			send("\n[Message buffer FULL, line not entered!]\n");
			return cline;
			}
		/* move line pos pointers up a line */
		for (loop=cline+2; loop>=ln; loop--)
			lp[loop]=lp[loop-1];

		lp[ln-1]=ptr;
		strcpy(ptr,buffer);	/* insert the line */
		cline++;	  /* one more line	*/
		}
		 else send("\n[Invalid line]");
	}
	else
	   {
	   sprintf(buffer,"\n[Max of %d lines!!]",O.MLINES);
	   send(buffer);
	   }

return cline;
} /* ins_line */



del_line(cline)
 register int cline;
{
register int ln	,i;
char temp[11];

ask("Delete which line ?",temp,10,UP);
putchar('\n');
ln=atoi(temp);
if ((ln>0) && (ln<cline))
	{
	free(lp[ln-1]);		/* unallocate the space */
	for (i=ln; i<=cline; i++) lp[i-1]=lp[i];
	cline--;				/* minus one line */
	}
  else send("\n[Line not found]");

return cline;
} /* del_line */


rep_line(cline)
 register int cline;
{
register int ln,tlen;
char temp[11];

ask("Replace which line? ",temp,10,UP);
ln=atoi(temp);
if ((ln>0) && (ln<cline))
	{
	printf("\nLine Was:\n%5d: %s\n",ln,lp[ln-1]);
	send("\nEnter new line, or Return if no change:\n");
	printf("%5d: ",ln);
	getl(buffer,UPLOW+MSGLINE);
	if (*buffer=='\0')		/* null line? */
		return;
	tlen=strlen(lp[ln-1]+2);	/* temp save */
	free(lp[ln-1]);
	save_line(ln,buffer);
	}
  else send("\n[Invalid line]");
} /* rep_line */


edit_line(cline)
 register int cline;
{
register int ln,tlen;
int eol_flag=FALSE;
char *sptr;
char temp[129];

ask("Edit which line? ",temp,10,UP);
ln=atoi(temp);
if ((ln>0) && (ln<cline))
	{
	while (1) {
	   printf("\nLine Was:\n%5d: %s\n",ln,lp[ln-1]);
	   send("\nEnter old text to be removed: ");
	   getl(temp,UPLOW+MSGLINE);
	   if (*temp=='\0')		/* null line? */
		return;
	   if (temp[strlen(temp)-1]=='#')
		{
		temp[strlen(temp)-1]='\0';
		eol_flag=TRUE;
		}
	   sptr=sindex(temp,lp[ln-1]);	/* order important!! */
	   if (sptr) break;	/* string is there.. */
	     else send("\n[String not found!]\n");
	   }

	tlen=strlen(temp);
	strncpy(buffer,lp[ln-1],sptr-lp[ln-1]);
	buffer[sptr-lp[ln-1]]='\0';	/* make sure its terminated 9/28 */

	send("\nEnter new replacement text: ");
	getl(temp,UPLOW+MSGLINE);

	strcpy(&buffer[strlen(buffer)],temp);	/* fix new line up... */
	if (!eol_flag) strcpy(&buffer[strlen(buffer)],sptr+tlen);

	if (strlen(buffer)>O.MAXMSGLINE)
		{
		send("\nNew line to long.  Edit aborted.\n");
		return;
		}

	printf("\n%3d: %s\n",ln,buffer);
	free(lp[ln-1]);
	save_line(ln,buffer);
	}
  else send("\n[Invalid line]");
} /* edit_line */


/* End of file */

