/*

     ATP QWK MAIL READER FOR READING AND REPLYING TO QWK MAIL PACKETS.
     Copyright (C) 1992  Thomas McWilliams 
     Copyright (C) 1990  Rene Cougnenc
	 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation; either version 1, or (at your option)
     any later version.
     
     This program is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.
     
     You should have received a copy of the GNU General Public License
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/


/*
 * Change Log: $Log: read.c,v $
 * Revision 1.400  1992/11/28  09:54:05  root
 * second release
 *
 * Revision 1.310  1992/07/08  23:15:14  root
 * first release -- minor bug fix in read.c
 *
 * Revision 1.30  1992/07/05  15:36:19  root
 * first release of ATP
 *
 * Revision 1.2  1992/04/19  12:50:02  root 1st semifunctional UNIX version.
 *
 */

/* define prompts and ansi sequences for prompts */

#define	SRMPT  "%s [ %s ] > "  /* format string for simple prompt  */
#define PFROM  "      From: " 
#define PRTO   "        To: "
#define PSUBJ  "   Subject: "
#define PSECR  "  Security: "
#define PTAIL  "[  ]        "
#define BLINK  "\33[5m"
#define CLEAR  "\33[0m"
#define GREEN  "\33[32m"
#define HIGH   "\33[1m"
#define WHIT   "\33[37m"
#define LEFT35 "\33[35D"
#define RGHT25 "\33[25C"
#define PRTAIL "[ " RGHT25 " ]        " LEFT35 WHIT  

#define PRMT1  GREEN HIGH SRMPT
#define PRMT2  GREEN HIGH "%s [ " BLINK "%s" CLEAR GREEN HIGH " ] > "
#define PRMTFR GREEN PFROM PRTAIL   
#define PRMTTO GREEN PRTO  PRTAIL   
#define PRMTSB GREEN PSUBJ PRTAIL
#define PRMTSC GREEN PSECR PRTAIL 

#define SRMTFR "      From: [  ]        "
#define SRMTTO "        To: [  ]        "
#define SRMTSB "   Subject: [  ]        "
#define SRMTSC "  Security: [  ]        "

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef unix
#include <unistd.h>
#else
#include <alloc.h>
#include <io.h>
#include <dos.h>
#include <dir.h>
#endif
#include "system.h"
#include "ansi.h"
#include "makemail.h"
#include "qlib.h"
#include "reader.h"
#include "readlib.h"

#ifndef USESYSTEM   /* have tcgetattr() an tcsetattr() */
#include <termios.h> /* terminal stuff */
#include <sys/wait.h>
static struct termios savedterm ; 
#endif

/* global function declarations */

int main(int argc, char *argv[]);

/* static function declarations */

#ifndef USESYSTEM 
static void jert( int a ); /* catches signal SIGINT for unix */
#endif
static void Purge( void );
static void scruter( void ) ;
static int  findtxt(const char *fndargs, const int mode) ;
static char *findstr( unsigned char *, unsigned char * );
static int  FindActive( const int curconf );
static void showterms( void );
static void ReadShell(void);
static void togltag(void);
static void Load(const char *name);
static void Read(const char *name);
static void chconf(const char *buf);
static void AutoJoin(void);
static void SaveMsg(const char *str);
static void Help(void);
static void Tag( char *line );
static int  ReadNext(const int mode);
static void PutHeader(void);
static void PrintHeader( FILE *fp);
static void Reply(const int mode, const char *line);
static int  AddReply(const char *fname, struct QmailRepType *Qmail);
static void ListConf(void);
static void GoToNum(const char *str);
static int  SeekNum(const char *str);
static void Display(const int mode);
static void Welcome(void);
static void GetBbs(const char *name);

/*  end of static function declarations */

/* constant declarations */

#define TRUE 1
#define FALSE 0
#define NEXT 0
#define AGAIN 1
#define PREVIOUS 2
#define SCAN 3
#define FIND 4
#define KILL 5
#define NUKE 9
#define PRIVATE 13
#define RPT_MASK 0x03 /* lower 2 bits used for display mode repeat constant */

/* global variables */

const char *const TagLine = NTAG ; /* PCBoard style tagline */
const char *const FidoTag = FTAG ; /* Fidonet style tagline */

#ifndef __MSDOS__
static pid_t Proc_ID ;  /* for unix */
#endif
char         CurTag[256];	/* Tag line chosen...                 */
char         UserTag[256];	/* Save run time defined tag-lines    */
char         OrigTag[256];  /* default tag from atprc config file */ 
static int   dflag = TRUE;	/* toggle for default and user defined tagline */

char            HomePath[MAXPATHS];	/* Home directory root of msg dirs    */
char            MailPath[MAXPATHS];	/* Where to look for new mail         */
char            ReplyPath[MAXPATHS];/* Where to put replies               */ 
char            WorkPath[MAXPATHS];	/* Where to archive/unarchive mail .  */
char            CurBoard[50];	    /* Name of the current board...       */

/* variables used by line editor */
char           *luxptr ;         /* passed text to line editor for editing*/

/* variables set in configuration file */

int             SCREENLINES = 25;/* default 25, changeable in config file */
int             SaveConf = -1 ;   /* save current conference */
long            RbufSize = MYBUF ;
char            Editor[50];     /* Name of the standard text editor       */
char            Archiver[50];
char            UnArchiver[50];
char            qwklist[100];	/* command line for listing QWK packets */
char            speller[100];   /* command line for invoking speller    */  
int				autotag = TRUE; /* flag for random taglines             */
int             graphics = FALSE;/* flag for vt100 graphics mode        */
int             charset = CHR7BIT ;   /* which char set? 4 is dummy = undefnd.*/
int             fido = FALSE;	/* Flag for tagline style               */
int             ansi = TRUE ;	/* Flag true if ansi output is on       */

/* variables used for reading, checking, writing, closing files */

struct MyIndex  Index;
FILE           *fidx = NULL, *fmsg = NULL;	/* Index File and msg file, globals */
int             FilesOpen = FALSE;	/* Flag if these files are open         */
int             FirstDone = FALSE;  /* Set if 1st message in conf is read   */
static int      newmail = TRUE;     /* used by AutoJoin()                   */
int             ActvCnt = 0;	/* tracks number of active conferences      */
int             CurConf;	    /* Number of current Conference...          */
long int        TotMsg;		    /* Number of messages in conf               */
byte           *rbuf ;          /* Pointer to work buffer for messages      */
int             pmail = FALSE;	/* Flag indicates if personal mail waiting  */
int             ReplyExist = 0;	/* Flag 1 if there are replies to pack      */
static int      IsEmpty = TRUE;	/* Flag false if a BBS is loaded            */
int             HeadLetter = 1;	/* Flag 1 if automatic header is active     */
static int		caps = FALSE  ; /* Flag for reply ENTER mode                */

#ifdef unix
#ifndef DJD
#define MAXCMDS  21     /* should equal count of the following array */
static const char *const cmds[MAXCMDS] = {"cd", "cp", "echo", "ls", "ln", "lpr", "man", "sort", "sync",
		 "mkdir", "more", "mv", "pwd", "cwd", "rm", "rmdir", "set","cat", "less", "df", "du"
};
#endif
#endif

#ifdef __MSDOS__
#define MAXCMDS 16
static const char *const cmds[MAXCMDS] = { "del","dir","chkdsk","md","rd",
         "cd", "mem","more", "mkdir","set","print","rmdir","sort","copy", "xcopy","type" } ;
#endif

 /*----------------------------------------------------------------------*/
#ifndef USESYSTEM
static int reperror = FALSE ; /* error during replies Reply() */
static void       /* catch a signal in Reply() */
jert(int a) {
	while(kill(Proc_ID, SIGKILL));
	ATPSETERM ; /* restore terminal parameters */
	reperror = TRUE ;
#ifndef HAVE_SETGET
	signal(SIGINT, SIG_DFL);
#else
	cls();
	printf("ERROR child process aborted\n\n");
	system("ls -altr /tmp"); /* list contents of /tmp directory */
	printf("\nERROR please clean your old files from /tmp directory\n\n");
	sleep(1);
#endif	
}
#endif

int
main(int argc, char *argv[])
{
	ATPGETERM ; /* save terminal parameters */
#ifndef __MSDOS__  
	Proc_ID = getpid();  /* for unix */
#endif
	if (strlen( getenv("PATH") ) > (size_t) MAXPATHS ){
		printf("PATH environment too long: %d\n", (size_t) MAXPATHS );
		exit(-1);
	} ;
	MakeHomePath();
	if (ReadConfig())
		return (-1);
    if ((ConfName = MALLOK ( sizeof(string16) * 2 )) == NULL)
	    return (-1);
	Clean();
	clear();
	bblack();
	Title();
	cyan();

	strcpy(CurBoard, txt[10]);     /* First default prompt....   */
	strcpy(ConfName[0], txt[9]);   /* "empty"                    */
	if (fido)
		strcpy(CurTag, FidoTag);   /* setup the default TagLines */
	else
		strcpy(CurTag, TagLine);
	strcat(CurTag, OrigTag);
	if ((rbuf = (byte *) MALLOK (MYBUF)) == NULL) {
		printf("%s\n", txt[1]);	/* Not enough memory */
        printf("%lu bytes\n", MYBUF );
		return (0xFF);
	}
	if (argc == 2)
		GetBbs(argv[1]);
	if(autotag) 		
		ChooseTag();		
	printf("%s\n", CurTag);
        ReadShell();
	MFREE (rbuf);
	if (FilesOpen) {
		fclose(fidx);
		fclose(fmsg);
	}
	MFREE (ConfName);
	free(ConfNumbers);
	free(ConfActive);
	ATPSETERM ; /* restore terminal parameters */
    Clean();
	return (0);
}

/*
 * Main Shell
 */

static void
ReadShell(void)
{
	char           prompt[80];
	char           *tmp = NULL ;
	char           *ptr ;
	int            i ;

	while (1) {
topcat:
 		if(tmp != NULL) {
			free(tmp);
			tmp = NULL;
		}
		luxptr = NULL ;
		if (pmail && (CurConf == findCindex(PERS_CONF))) {
			sprintf(prompt, PRMT2, CurBoard, ConfName[CurConf]);
		} else {
			sprintf(prompt, PRMT1, CurBoard, ConfName[CurConf]);
		} 
		while ((tmp = readline(prompt))==NULL) {
			printf("\r %-75s \r"," ") ;
		}
		add_history(tmp);	
		clear();
		fflush(stdout);
		StripDel(tmp);
		StripSpaceL(tmp);

		for (i = 0; i < MAXCMDS; i++) {	/* Internal shell commands */
			if (!strnicmp(tmp, cmds[i], strlen(cmds[i]))) {
				system(&tmp[0]);
                goto topcat ;  /* break from loop and take it from the top! */
			}
		}

		if (Numeric(tmp))
			GoToNum(tmp);

		else if (!strnicmp(tmp, "show ", 5))
			showterms();

		else if (!strnicmp(tmp, "aide", 4))
			Help();

		else if (!strnicmp(tmp, "cls", 3))
			cls();

		else if (!strnicmp(tmp, "clean", 5))
			Purge();

		else if (!strnicmp(tmp, "conf", 4))
			ListConf();

		else if (!strnicmp(tmp, "date", 4))
			Date();

		else if (!strnicmp(tmp, "fido", 4))
			togltag();

		else if (!strnicmp(tmp, "find ", 5))
			(void) findtxt(tmp, FIND);

		else if (!strnicmp(tmp, "help", 4))
			Help();

		else if (!stricmp(tmp, "last")){
			sprintf(prompt,"%ld",TotMsg);
			GoToNum(prompt);
		}

		else if (!stricmp(tmp, "next" ))
			(void) findtxt(tmp, NEXT);

		else if (!strnicmp(tmp, "scan", 4))
			scruter();

		else if (!strnicmp(tmp, "ql", 2))
			Qlist(qwklist);

		else if (!strnicmp((char *) tmp, "graph", 4)) {	/* toggle autotag line selection */
			if (graphics){
				graphics = FALSE;
				printf(    "\n\t\t +------------------------------+\n");
				printf(      "\t\t |                              |\n");
				printf(      "\t\t |  vt100 graphics are now OFF  |\n");
				printf(      "\t\t |                              |\n");
				printf(      "\t\t +------------------------------+\n\n");
			}else{
				graphics = TRUE ;
				printf("\n\016\t\t lqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqk\n");
				printf(      "\t\t xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaax\n");
				printf(      "\t\t xaa\017 vt100 graphics are now ON\016 ax\n");
				printf(      "\t\t xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaax\n");
				printf(      "\t\t mqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqj\n\n\017");
			}
		}	
		else if (!strnicmp(tmp, "head", 4)) {
			blue();
			high();
			HeadLetter = HeadLetter ? 0 : 1;
			printf("%s ", txt[101]);	/* "Automatic H." */
			printf("%s\n", HeadLetter ? txt[85] : txt[86]);	/* "on" / "off"   */
		} else if (!strnicmp(tmp, "news", 4)) {
			if (ansi) {
				sprintf(tmp, "%s%s%c%s", HomePath, CurBoard, SEP, NEWSG);
				if (!access(tmp, R_OK )) {
					sprintf(tmp, "%s%s", HomePath, CurBoard);
					view(tmp, NEWSG);
					continue;
				}
			}
			sprintf(tmp, "%s%s", HomePath, CurBoard);
			view(tmp, NEWS);
		} else if (!strnicmp(tmp, "time", 4))
			Date();

		else if (!strnicmp(tmp, "welcome", 4))
			Welcome();

		else if (!strnicmp(tmp, "file", 4)) {
			if (IsEmpty) {
				EmptyMsg();
				continue;
			}
			sprintf(tmp, "%s%s", HomePath, CurBoard);
			view(tmp, NEWFILES);
		} else if (!strnicmp(tmp, "load", 4)) {
			if ((!IsEmpty) && ConfActive[CurConf])
				UpdateConf(UPDATE);
			Load(tmp);	/* Load new mail      */
		} else if (!strnicmp(tmp, "merde", 5))
			merde();/* Load new mail      */

		else if (!strnicmp(tmp, "rev", 3)) {
			if ((!IsEmpty) && ConfActive[CurConf])
				UpdateConf(UPDATE);	/* Save current conf pointer */
			Read(tmp);	/* read existing mail        */
		} else if (!strnicmp(tmp, "tag", 3))
			Tag(tmp);	/* change tagline     */

		else if (!stricmp(tmp,"reset")){
			UpdateConf(RESET);
		}
        else if ( tmp[0] == '\0' || tmp[1] == '\0' || tmp[1] == '\040' ){

            switch ( tmp[0] ) {

            case '!':
                if (tmp[1]) {  
                    system((char *) &tmp[1]);
                } else {
                    ptr = getenv( SHELL );
                    if (ptr)
                        system(ptr);
                }
                ATPSETERM ; /* reset terminal paramaters */
                break;

            case 'c':
            case 'C':
                if(CurConf == RCONF_IDX && FirstDone )
                        Reply(EDIT, tmp);
                break;

            case 'e':
            case 'E':
                if(CurConf == RCONF_IDX && tmp[1] == '\0' ) {
                    if (FirstDone)
                        Reply(EDIT, tmp);
                }
                else {
                    Reply(ENTER, tmp);
                }
                break;

            case 'j':
            case 'J':
               	chconf(tmp);
                break;

            case 's':
            case 'S':
                SaveMsg(tmp);
                break;
            default:
            break;
            }
        if( !tmp[1] || !tmp[0] )
	    switch( (int) tmp[0] ) {
            case '?':
		Help();
		break;

	    case 'a':
	    case 'A':
		if (FirstDone)
			Display(0); 
		else
			ReadNext(NEXT);
		break;
#ifdef ATPDBG				
	    case 'i': /* debug */
		printf("CurCon: %d   Index.LastRead: %d\n", CurConf, Index.LastRead);
		break;
#endif
	    case 'k':
            case 'K':
		if(CurConf == RCONF_IDX)
			ReadNext(KILL);
		break;

 	    case 'm':	 /* toggle ANSI mode on/off */
 	    case 'M':
 		ansi = ansi ? FALSE : TRUE ;
 		yellow();
 		high();
 		printf("%s %s .\n", txt[84], ansi ? txt[85] : txt[86]);
 		break;
 
	    case 'p':
	    case 'P':
		if(CurConf == RCONF_IDX)
		ReadNext(PRIVATE);
		break;			

	    case 'q':
	    case 'Q':
	    case 'g':
	    case 'G':
		if (!IsEmpty)
			UpdateConf(UPDATE);	/* Save current conf pointer */
		if (FilesOpen) {
			fclose(fidx);
			fclose(fmsg);
			FilesOpen = FALSE;
		}
		if (ReplyExist) {
			red();
			high();
			printf("%s\n%s %s.\n", txt[2], txt[3], CurBoard);	/* Warning, you have  */
			sprintf(prompt,"%s", txt[4]);	/* Replies,pack them ? */
			if (YesNo(YES,prompt))
			PackReply();
		}
		free(tmp);	
		clear();
		return;

	   case 'n':
 	   case 'N':
		AutoJoin();
		break;

       	   case 'r':
       	   case 'R':
       	   	if (FirstDone && CurConf != RCONF_IDX)
            		Reply(REPLY, tmp);
            	break;

	case '+':
	case 0:
   		ReadNext(NEXT);
		break;

	case '-':
		ReadNext(PREVIOUS);
		break;
         }
      }
   }
}

static void
togltag(void)
{				/* switch tagline styles */
	fido = (fido ? FALSE : TRUE);
	Tag("tag \177");
}


static void
Load(const char *name)
{
	char            BbsName[50];
	char            tmp3[MAXPATHS];
	char            tmp2[MAXPATHS];
	char            tmp[MAXPATHS];
	char            OldDat[MAXPATHS];
	char            NewDat[MAXPATHS];
	char            prmbuf[80]; /* buffer for prompt passed to YesNo */
	char           *tptr;
	struct stat     Oldst;
	struct stat     Newst;
	int             i;

	pmail = FALSE;		/* reset global flag to indicate no personal mail yet */
	if (ReplyExist) {
		red();
		high();
		printf("%s\n%s %s.\n", txt[2], txt[3], CurBoard);	/* Warning, you have  */
		sprintf(prmbuf,"%s", txt[4]);	/* Replies,pack them ? */
		if (YesNo(YES,prmbuf))
			PackReply();
		ReplyExist = FALSE;
	}
	BbsName[0] = '\0';
	sscanf(name, "%s %s", tmp, BbsName);
	if (!BbsName[0]) {
		red();
		printf("%s  %s\n", txt[87], txt[88]);	/* "usage" " load.." */
		return;
	}
	printf("%s %s\n", txt[5], BbsName);

	if (strstr(BbsName, ".qw") == NULL)
		strcat(BbsName, ".qwk");

	sprintf(tmp, "%s%s", MailPath, BbsName);

/*
 * 	Now that we've used BbsName to id the packet file strip any
 * 	trailing digits so the board's subdir doesn't vary w/ packet #.
 */

	tptr = BbsName;
	i = -1;
	while (BbsName[++i]);
	while (BbsName[--i] != '.');
	BbsName[i] = '\0';
	if (!Numeric(tptr))
		while (isdigit(BbsName[--i]))
			BbsName[i] = '\0';

	if (access(tmp, R_OK )) {
		red();
		printf("%s : %s\n", txt[6], tmp);	/* No mail found        */
		printf("%s\n", txt[7]);	/* Try the read command */
		return;
	}
	Clean();		/* Don't forget to clean work directory ! */
	yellow();
	high();
	printf("%s\n", txt[8]);	/* " Extracting Messages..." */
	green();
	fflush(stdout);
	getcwd(tmp3, sizeof(tmp3));	/* save current directory    */
	chdir(WorkPath);	/* change to work directory  */
	sprintf(tmp2, "%s %s", UnArchiver, tmp);    /* build unzip command line  */
	system(tmp2);  /* execute unzip in work dir */
	chdir(tmp3);        /* restore current directory */
	yellow();
	sprintf(tmp3, "%s%c%s", WorkPath, SEP, CNTRL_FILE);
	if (access(tmp3, F_OK )){
		printf("Error: can't find control file: %s\n", tmp3);
		return ;
	}
	sprintf(tmp2, "%s%s", HomePath, BbsName);	/* Access to a board subdir */
	if (access(tmp2, R_OK | W_OK ))
		my_mkdir(tmp2);

	sprintf(OldDat, "%s%s%c%s", HomePath, BbsName, SEP, CNTRL_FILE);
	sprintf(NewDat, "%s%c%s", WorkPath, SEP, CNTRL_FILE);
	if (stat(OldDat, &Oldst) != -1) {	/* If exists an old control.dat */
		stat(NewDat, &Newst);
		if (Newst.st_mtime <= Oldst.st_mtime) {
			red();
			high();
			printf("%s\n%s.\n", txt[2], txt[11]);	/* "New packet older..." */
			sprintf(prmbuf , "%s...", txt[12]);	/* " Do you  want to.." */
			if (!YesNo(NO,prmbuf))
				return;
		}
	}
	strcpy(CurBoard, BbsName);
	MkIndex(WorkPath, tmp2);/* Create Index Files */
	Chk4Rep();
	Chk4Cnf(tmp2);  
	if (FilesOpen) {
		fclose(fidx);
		fclose(fmsg);
		FilesOpen = FALSE;
	}
	IsEmpty = FALSE;
	newmail = TRUE;
	caps = !fido ;
	if (pmail)
		CurConf = findCindex(PERS_CONF);
	else
		CurConf = FindActive(LastConf);
	if (CurConf < 0)
		CurConf = 0;
	GetConf(CurConf);
}


/*
 * Join a BBS without extracting new mail.
 */

static void
Read(const char *name)
{
	char            BbsName[50];
	char            tmp[MAXPATHS];
	if (ReplyExist) {
		red();
		printf("%s\n%s %s.\n", txt[2], txt[3], CurBoard);	/* Warning, you have  */
		sprintf(tmp,"%s", txt[4]);	/* Replies,pack them ? */
		if (YesNo(YES,tmp))
			PackReply();
		ReplyExist = FALSE;
		tmp[0] = '\0' ;
	}
	BbsName[0] = 0;
	sscanf(name, "%s %s", tmp, BbsName);
	if (!BbsName[0]) {
		red();
		printf("%s %s\n", txt[87], txt[89]);	/* "usage " "read..." */
		return;
	}
	printf("%s %s\n", txt[5], BbsName);	/* "Loading" */
	sprintf(tmp, "%s%s%c%s", HomePath, BbsName, SEP, CNTRL_FILE );
	if (access(tmp, F_OK )) {
		printf("%s : %s\n", txt[13], tmp);	/* "No bbs found " */
		return;
	}
	sprintf(tmp, "%s%s", HomePath, BbsName );
	if (ReadControl(tmp)) {
		printf("%s\n", txt[14]);	/* "Error in CONTROL.DAT." */
		return;
	}
	strcpy(CurBoard, BbsName);
	Chk4Rep();
	Chk4Cnf(tmp);
	if (FilesOpen) {
		fclose(fidx);
		fclose(fmsg);
		FilesOpen = FALSE;
	}
	ActvConf();		/* update boolean array of active/inactive flags */
	IsEmpty = FALSE;
	newmail = FALSE;
	caps = !fido ;
	CurConf = FindActive(LastConf);
	if (CurConf < 0)
		CurConf = 0;
	GetConf(CurConf);
}


/*
 * CHCONF : Change active conference.
 */
static void
chconf(const char *buf)
{
	char            Name[50];
	char            tmp[MAXPATHS];
	int             i ;
	unsigned int    m ;

	if (IsEmpty) {
		EmptyMsg();
		return;
	}
	Name[0] = 0;
	sscanf(buf, "%s %s", tmp, Name);
	if (!Name[0]) {
		red();
		printf("%s\n", txt[87]);	/* "Usage" */
		printf("\tj %s\n\t\t%s\n", txt[90], txt[91]);	/* "Conf #" "or" */
		printf("\tj %s\n", txt[92]);	/* "conf name" */
		printf("%s\n", txt[93]);	/* "type conf to list..." */
		return;
	}
	if (Numeric(Name)) {	/* a number is given */
		i = atoi(Name);
		if ((i = findCindex(i)) > -1)
			strcpy(Name, ConfName[i]);
	} else {		/* a name is given   */
		
		m = strlen(Name);
		for (i = 0; i <= LastConf; i++) {
			if (!stricmp(Name, ConfName[i]))
				break;
		}
		if( i > LastConf ) {		
			for (i = 0; i <= LastConf; i++) {
				if (!strnicmp(Name, ConfName[i], m))
					break;
			}	
		}
	}

	if (!stricmp(Name, "MAIN" ))
		i = 0;		/* Special case for "main board" */

	if (i > LastConf || i < 0) {
		printf("\n%s\n", txt[28]);	/* "Unknown conference" */
		return;
	}
	sprintf(tmp, "%s%s%c%d.cnf", HomePath, CurBoard, SEP, ConfNumbers[i]);
	if (access(tmp, F_OK )) {
		red();
		printf("%s : %s  %s\n", txt[6], tmp, ConfName[i]);	/* "No mail found" */
		return;
	}
	UpdateConf(UPDATE);		/* Save current conf pointer */
	if (GetConf(i) == ERROR)
		return;
	blue();
	high();
	printf("\n *  %s %s %s. *\n\n", txt[29], ConfName[CurConf], txt[30]);
	/* "Conference " "joined" */
}


/*
 * Loads next valid conferences.
 */
#define ILR Index.LastRead

static void
AutoJoin(void)
{
	char            tmp[MAXPATHS];
	int             i, j;

	if (IsEmpty) {
		EmptyMsg();
		return;
	}
	if (!ActvCnt) {
		chconf("j MAIN\n");
		return;
	}
	i = CurConf;
	j = ActvCnt ;
	while (j--) {
		i = FindActive(i);
		sprintf(tmp, "j %d\n", ConfNumbers[i]);
		chconf(tmp);
		if ( ILR < 1 || ILR != (TotMsg - 1) || !newmail ){
			return ;
		} 
		else 		
			printf("\t%s.\n", txt[31]);	/* "No new mail" */
	}
	newmail = FALSE;
	printf("\n");
}

#undef ILR

/*
 * Save current message in text file ( append mode ).
 */

static void
SaveMsg(const char *str)
{
	char            dummy[MAXPATHS];
	char            fname[MAXPATHS];
	byte           *ptr;
	FILE           *fp;
    unsigned long   i;
	int             apflag;

	if (IsEmpty) {
		EmptyMsg();
		return;
	}
	fname[0] = 0;
	sscanf(str, "%s %s", dummy, fname);
	if (!fname[0]) {
		high();
		yellow();
	ptr = (byte *) readline(txt[39] );
	clear(); fflush(stdout);
	fname[0] = '\0' ;
	if (ptr != NULL)
		strcpy(fname, (char *) ptr);
	free(ptr) ;
	if (!fname[0]) {
			printf("%s.\n", txt[40]);	/* "Aborted" */
			return;
		}
	}
	apflag = access(fname, W_OK ) ? 1 : 0;

	if ((fp = fopen(fname, "a")) == NULL) {
		red();
		high();
		printf("%s %s\n", txt[51], fname);	/* "unable to open file" */
		return;
	}
	PrintHeader(fp);
	ptr = (byte *) (rbuf + sizeof(struct MsgHeaderType));
	i = 0;
	while (i < Index.Size) {
		if (*ptr != 0){
			if(charset == ISOLAT1 )
	  			fputc( codelu[  (unsigned) (*ptr) ] , fp) ;
			else if (charset == CHR7BIT)
			    fputc( code7bit[(unsigned) (*ptr) ] , fp) ;
			else
				fputc(*ptr, fp);
		}
		i++;
		ptr++;
	}

	fprintf(fp, "\n");

	blue();
	high();
	/* printf("Message %s",apflag ? "Saved in" : "Appended to"); */
	printf("%s %s", txt[41], apflag ? txt[42] : txt[43]);
	clear();
	cyan();
	printf(" %s\n", fname);
	fclose(fp);
}


/*
 * Help message.
 */

static void
Help(void)
{
	unsigned      i;

	white();
	high();
	printf("\n%s", hlp[1]);
	clear();
	printf("\n");
	for (i = 0; i < strlen(hlp[1]); i++)
		putchar('-');
	printf("\n");
	high();
	printf("\r\t q,g\t%s\n", hlp[2]);
	printf("\t k\t%s\n", hlp[3]);
	printf("\t !\t%s\n", hlp[4]);
	printf("\t +\t%s\n", hlp[5]);
	printf("\t -\t%s\n", hlp[6]);
	printf("\t a\t%s\n", hlp[7]);
	printf("\t e\t%s\n", hlp[8]);
	printf("\t j\t%s\n", hlp[9]);
	printf("\t m\t%s\n", hlp[10]);
	printf("\t n\t%s\n", hlp[11]);
	printf("\t r\t%s\n", hlp[12]);
	printf("\t s\t%s\n", hlp[13]);
	printf("\t conf\t%s\n", hlp[14]);
	printf("\t clean\t%s\n", hlp[15]);
	printf("\t load\t%s\n", hlp[16]);
#ifdef ENGLISH
	printf("\t review\t%s\n", hlp[17]);
#else
	printf("\t revois\t%s\n", hlp[17]);
#endif
	printf("\t files\t%s\n", hlp[18]);
	printf("\t tag help\t%s\n", hlp[19]);
	printf("\t head\t%s\n", hlp[22]);
	printf("\t scan\t%s\n", hlp[24]);
	printf("\t qlist\t%s\n", hlp[23]);
	printf("\n");
}



/*
 * Change Reader Signature :-)
 */
static void
Tag( char *line)
{
	char            dummy[50];
	char            tmp[256];
	char            tmp2[256];
	int             i,j ;
	tmp2[0] = tmp[0] = 0;

	sscanf(line, "%s %s %s", dummy, tmp, tmp2);

 	if (tmp2[0] == 0 && (strnicmp((char *) tmp, "list", 4) == 0)) {	/* list taglines */
		sprintf(tmp2, "%s%s", HomePath, TAGFILE);
		printf("%s\n", tmp2 );
		if (!access(tmp2, R_OK )) {
			tmp[0] = 0 ;
			sprintf(tmp, "%s", HomePath);
			tagview(tmp, TAGFILE );
		}
		printf("\nDefault Tag : %s", OrigTag);
		printf("User defined: %s", UserTag);
		printf("\n");
		return;
	}
	if (tmp2[0] == 0 && Numeric((char *) tmp)) {	/* try to get a tagline from the list */
		i = atoi((char *) tmp);
		i = i < 0 ? -i : i;
		TagSeek(i);
		printf("Current Tag now set to:");
		printf("%s\n", CurTag);
		return;
	}
	if (tmp2[0] == 0 && tmp[0] == '?') {	/* Print current tag */
		printf("Current TagLine is:");
		printf("%s\n", CurTag);
		return;
	}
 	if (tmp2[0] == 0 && (strnicmp((char *) tmp, "rand", 4) == 0)) {	/* select tag at random  */
		ChooseTag();
		printf("Current Tag now set to:");
		printf("%s\n", CurTag);
		return;
	}
 	if ((tmp2[0] == 0 && (strnicmp((char *) tmp, "help", 4) == 0)) || line[3] == '\0') {	/* select tag help menu */
		white();
		high();
		printf("\n%s", taghlp[1]);
		clear();
		printf("\n");
		for (j = 0; j < (int) strlen(taghlp[1]); j++)
			putchar('-');
		printf("\n");
		high();
		printf("\t tag list\t%s\n", taghlp[2]);
		printf("\t tag ?   \t%s\n", taghlp[3]);
		printf("\t tag `n' \t%s\n", taghlp[4]);
		printf("\t tag random\t%s\n", taghlp[5]);
		printf("\t tag swap\t%s\n", taghlp[6]);
		printf("\t tag auto\t%s\n", taghlp[7]);
		printf("\t tag     \t%s\n", taghlp[8]);
		printf("\t tag help\t%s\n", taghlp[9]);
		printf("\t fido    \t%s\n", taghlp[10]);
		printf("\n");
		printf("Current TagLine is:");
		printf("%s\n", CurTag);
		return;
}
 	if (tmp2[0] == 0 && (strnicmp((char *) tmp, "auto", 4) == 0)) {	/* toggle autotag line selection */
		if (autotag){
			autotag = FALSE;
			printf("\nautotag is OFF\n\n");
		}else{
			autotag = TRUE ;
			printf("\nautotag is ON\n");
			ChooseTag();
			printf("Current Tag now set to:");
			printf("%s\n", CurTag);
		}
		return;
	}	
	if ((tmp2[0] == 0) && (strnicmp((char *) tmp, "swap", 4) == 0)){	/* restore standard tag */
		dflag = dflag ? FALSE : TRUE;
		if (fido)
			strcpy(CurTag, FidoTag);
		else
			strcpy(CurTag, TagLine);
		if (dflag)
			strcat(CurTag, OrigTag);
		else
			strcat(CurTag, UserTag);
		printf("Current Tag now set to:");
		printf("%s\n", CurTag);
		return;
	}
	if (!stricmp((char *) tmp, "fido")) {
		fido = (fido ? FALSE : TRUE);
		tmp[0] = '\177' ;
	}
	if (tmp[0] == '\177') {	/* toggle fido tag */
		strcpy((char *) tmp, (char *) CurTag);
		if (fido) {
			line = (char *) tmp + strlen(TagLine);	/* point to start of tag message */
			strcpy(CurTag, FidoTag);
		} else {
			line = (char *) tmp + strlen(FidoTag);
			strcpy(CurTag, TagLine);
		}
		strcat(CurTag, line);
		printf("Current Tag now set to:");
		printf("%s\n", CurTag);
		return;
	} 
	if (line[3] == '\040' ) {
		line += 4;	/* Change current tag to User defined Tag */
		strcpy(UserTag, line);
		strcat(UserTag, "\n");
		if (fido)
			strcpy(CurTag, FidoTag);
		else
			strcpy(CurTag, TagLine);
		strcat(CurTag, UserTag);
		dflag = FALSE;
		printf("Tag is now set to :");
		printf("%s\n", CurTag);
	}

}


/*
 * Print Next,previous or current message.
 */

static int
ReadNext(const int mode)
{
	byte			tchar  ;
	long            here;
    size_t          nrecs ;

    if(mode < 0 || mode > 13 )
		return(0) ;

	if (IsEmpty) {
		EmptyMsg();
		return (0);
	}
	if (!FilesOpen) {
		printf("%s \n", txt[44]);	/* no mail in conf */
		if (mode == SCAN)
			return (0);
		else
			AutoJoin();
		return (0);
	}
	/* if needed, seek to new record in conference index file */
	if ( mode == KILL || mode == NUKE || mode == PREVIOUS || mode == PRIVATE ) {
		here = ftell(fidx) - (long) ((mode & RPT_MASK) * sizeof(struct MyIndex));
		if (here < 0L) {
			printf("%s\n", txt[15]);	/* "First message !" */
			return (0);
		}
		if (fseek(fidx, here, SEEK_SET)) {
			printf("%s.\n", txt[16]);	/* "Seek error" */
			return (0);
		}
	}
	/* get new index information and check for end of conference */
	if (fread( &(Index.LastRead), 1, sizeof(struct MyIndex), fidx)
	    != sizeof(struct MyIndex)) {
		printf("%s\n", txt[17]);	/* "End of messages." */
		if (mode == SCAN || mode == FIND)
			return (0);
		else
			AutoJoin();
		return (0);
	}
	/* use new index information to seek to new message in msg file */
	if (fseek(fmsg, Index.Offset, SEEK_SET)) {
		printf("%s!\n", txt[16]);	/* "Seek Error" */
		return (0);
	}
	fread( &tchar, 1, 1, fmsg);	/* read status into variable */
    fseek( fmsg, Index.Offset, SEEK_SET);   /* re-seek           */

	if (mode == KILL || mode == NUKE ){
		tchar = tchar ^ 0x80 ; 		/* XOR status with 0x80      */
		if( mode == NUKE ) tchar = tchar | 0x80 ; 
		fwrite( &tchar,1, 1,fmsg);	/* write back new status     */
		fflush(fmsg);
		fseek(fmsg,Index.Offset, SEEK_SET); /* re-seek           */
	}
	if (mode == PRIVATE){
		tchar = ( tchar == 0x2A ) ? 0x20 : 0x2A ;	/* XOR status with 0x80      */
		fwrite( &tchar,1, 1,fmsg);	/* write back new status     */
		fflush(fmsg);
		fseek(fmsg,Index.Offset, SEEK_SET); /* re-seek           */
	}
	nrecs = (( Index.Size / 128 ) + 1 ) /* Msg + Head */ ;
	if (mode == SCAN){
		fread( rbuf, 128, 1, fmsg );
		PutHeader();
		}
	else {
    		if ( nrecs > ( RbufSize / 128 ) ) 
        	 	if ( !reup( (unsigned long) (nrecs+1)*128L ))
				return(0) ;
    		if (fread((char *) rbuf, 128, nrecs, fmsg) != nrecs ) {
        		printf("%s? \n", txt[18]);  /* Read Error */
			return (0);
	}
	Display(mode);
	}
 	return (1);
}


/*
 * Prints the Qmail message header pointed by buf .
 */

static void
PutHeader(void)
{
	struct MsgHeaderType Header;
	const char *const Space = "\t\t";
	byte  statu  ;
	int i ;
	byte *pntr ;
	
	memcpy ( &Header.Status, rbuf, sizeof(struct MsgHeaderType) );
	pntr =  (byte *) Header.MsgDate ;
   
	if ( charset == ISOLAT1 ){
    	for( i=0 ; i<88 ; i++ , pntr++ ) /* translate header info */
	       *pntr = codelu[ ( unsigned ) *pntr  ] ;
	}
	else if ( charset == CHR7BIT ){
    	for( i=0 ; i<88 ; i++ , pntr++ ) /* translate header info */
		   *pntr = code7bit[ (unsigned) *pntr  ] ;		
	}

	/* check for lowercase letters in to/from fields */
	caps = TRUE ;
	pntr =  (byte *) (Header.ForWhom) ;
	for( i=0 ; i<50 ; i++ )
		if( pntr[i] >= 'a' && pntr[i] <= 'z' )
			caps = FALSE ;

	/* First line */
	high();
	green();
	printf("\n%s", txt[19]);/* " From :" */
	yellow();
	nprint(Header.Author, 25);
	printf(Space);
	green();
	printf("%s", txt[23]);	/* "Number" */
	yellow();
	nprint(Header.NumMsg, 7);

	/* Second line */
	green();
	printf("\n%s", txt[20]);/* "To:" */
	red();
	if (!strnicmp(UserName1, (char *) (Header.ForWhom), strlen(UserName1))||
	   (!strnicmp(UserName2, (char *) (Header.ForWhom), strlen(UserName2)))) 
		blink();
	nprint(Header.ForWhom, 25);
	printf(Space);

	clear();
	green();
	high();
	printf("%s", txt[24]);	/* " Ref # " */
	red();
	nprint(Header.RefMsg, 7);

	green();
	printf("\n%s", txt[21]);/* "Subject" */
	cyan();
	nprint(Header.Subject, 25);
	printf(Space);
	green();
	printf("%s", txt[25]);	/* "Conf : " */
	magenta();
	printf("%s", ConfName[findCindex(readCnum((byte *) &(Header.BinConfN)))]);
	green();
	printf("\n%s", txt[22]);/* "date:" */
	red();
	nprint(Header.MsgDate, 8);
	green();
	printf("%s", txt[26]);	/* "time:" */
	red();
	nprint(Header.MsgTime, 5);
	clear();
	blue();
	printf("\t[%ld/%ld]", Index.MsgNum + 1, TotMsg);	/* 0 based, print 1 based. */
	statu = Header.Status ;
	if (statu == '+' || statu == '*' || statu >= 0x80) {
		printf("\t\t");
		red();
		high();
		blink();
		if (statu >= 0x80 )
			printf(" %s%c", txt[105], BELL);	/* "KILLED MESSAGE" */
		else			
			printf(" %s%c", txt[27], BELL);	/* "PRIVATE MESSAGE" */
	}
	printf("\n\n");
	clear();
	cyan();
}


/*
 * Prints the Qmail message header in file fp.
 */

static void
PrintHeader(FILE * fp)
{
	struct MsgHeaderType Header;
	const char *const Space = "\t\t";
	int i ;
	byte *pntr ;

	memcpy ( &Header.Status, rbuf, sizeof(struct MsgHeaderType) );
	pntr =  (byte *) Header.MsgDate ;

	if ( charset == ISOLAT1 ){
    	for( i=0 ; i<88 ; i++ , pntr++ ) /* translate header info */
	       *pntr = codelu[ ( unsigned ) *pntr  ] ;
	}
	else if ( charset == CHR7BIT ){
    	for( i=0 ; i<88 ; i++ , pntr++ ) /* translate header info */
		   *pntr = code7bit[ (unsigned) *pntr  ] ;		
	}
	
	
   /* First line */
	fprintf(fp, "\n%s", txt[19]);	/* "from:" */
	nfprint(fp, Header.Author, 25);
	fprintf(fp, Space);
	fprintf(fp, "%s", txt[23]);	/* "number:" */
	nfprint(fp, Header.NumMsg, 7);

	/* Second line */
	fprintf(fp, "\n%s", txt[20]);	/* "to :" */
	nfprint(fp, Header.ForWhom, 25);
	fprintf(fp, Space);
	fprintf(fp, "%s", txt[24]);	/* "ref#" */
	nfprint(fp, Header.RefMsg, 7);

	fprintf(fp, "\n%s", txt[21]);	/* "subj." */
	nfprint(fp, Header.Subject, 25);
	fprintf(fp, Space);
	fprintf(fp, "%s", txt[25]);	/* "Conf : " */
	fprintf(fp, "%s", (char *) (ConfName[findCindex(readCnum((byte *) &(Header.BinConfN)))]));
	fprintf(fp, "\n%s", txt[22]);	/* "date :" */
	nfprint(fp, Header.MsgDate, 8);
	fprintf(fp, "%s", txt[26]);	/* "time:" */
	nfprint(fp, Header.MsgTime, 5);
	fprintf(fp, "\t[%ld/%ld]", Index.MsgNum + 1, TotMsg);	/* 0 based, print 1 based. */
	if (Header.Status == '+' || Header.Status == '*') {
		fprintf(fp, "\t\t");
		fprintf(fp, "  %s\n", txt[27]);	/* "PRIVATE MESSAGE" */
	}
	fprintf(fp, "\n\n");
}

/*
 * Reply to current message or enter a message
 * -------------------------------------------
 */

#define NulConf -1
#define unsave(x,y,z) ( x = y , y = z )

static void
Reply(const int mode, const char *line)
{
	int             i , lowcase ;
	unsigned int    j ;
	char           *intmp ;
	char            fname[MAXPATHS];
	char            tmp[MAXPATHS];
	char            dummy[MAXPATHS];
	int             reedit = FALSE;
	struct MsgHeaderType *Header;
	struct QmailRepType Qmail;
#ifdef USESYSTEM
	char			cmd[MAXPATHS]; /* non-unix needs this */
#endif	
	if (IsEmpty) {
		EmptyMsg();
		return;
	}

	SaveConf = CurConf;

	if (mode == ENTER) {
		if ((sscanf(line, "%s %s", dummy, tmp)) == 2) {
			if (Numeric(tmp)) {   /* find proper index for conference */
				i = atoi(tmp);
				i = findCindex(i);
			} else {/* not numeric */
				if (!strnicmp(tmp, "MAIN", 4))
					i = 0;
				else {   /* search for match in conf list */
					j = strlen(tmp);
					for (i = 0; i <= LastConf; i++)
						if (!strnicmp(tmp, ConfName[i], j))
							break;
				}
			}
			if (i < 0 || i > LastConf) {/* index not found in previous step */
				printf("\n%s\n", txt[28]);	/* Unknown Conference */
				unsave( CurConf, SaveConf, NulConf ) ;
				return;
			}
			CurConf = i;   /* update Current conf. for our purposes */
		}
		if (CurConf == PCONF_IDX || CurConf == RCONF_IDX ) {
			unsave( CurConf, SaveConf, NulConf ) ;
			return;
		}
	    if (CurConf != SaveConf)		
			printf("\n%s %d  %s %s\n", txt[29], ConfNumbers[CurConf],
		       ConfName[CurConf], txt[30]);
	}
	Header = (struct MsgHeaderType *) rbuf;
	if ( (SaveConf >= (RCONF_IDX)) && mode != ENTER ) /* get actual conf. from header */
		CurConf = findCindex(readCnum((byte *) & (Header->BinConfN)));

	if ( (intmp = tempnam( WorkPath, "re" ))!= NULL) /* Temporary file */
		strcpy ( fname, intmp );
	else 		
		sprintf(fname, "%s%c%s", WorkPath, SEP, "reply.tmp" );	

l_edit:			/* this is where we go if we need to re-edit msg. */

	ResetHeader(&Qmail);
	printf("\n");

/* get who the message is from */
morefr:
  	green();
	strcpy (dummy , UserName) ;
	luxptr = dummy ;
	if (mode == EDIT){
		scpy(dummy, (char *) (Header->Author), 25);
	}		
	if (strcmp( luxptr, UserName1))
		add_history(UserName1);
	lowcase = fido  ;	 /* True or False boolean valued */
	if (mode == REPLY ){
		lowcase = FALSE ;
		intmp = (char *) Header->ForWhom ; 
		for ( i=0 ; i < 25 ; i++)
			if ( intmp[i] >= 'a' && intmp[i] <= 'z' )
				lowcase = TRUE ;
	}
	if ( mode == ENTER )
		lowcase = !caps ;
	if (!lowcase ) /* PCBoard likes uppercase to/from field */
		strupr(luxptr);
    while (( intmp = readline(PRMTFR))==NULL) {
	    free(intmp);
	    printf("\r") ;
	}
	strcpy(tmp, intmp);
	add_history(intmp);
	free(intmp);
	luxptr = NULL  ;
	StripDel(tmp);
	if (strlen(tmp) > (unsigned) 25) {
			red();
			printf("%s\n", txt[34]);	/* "Entry too long ! 25 chars max */
			goto morefr;
	}
	if(tmp[0])
	 	str2mem((char *) Qmail.Author, tmp); /* Right name in the from field */
  	else {	
		blue();
		printf("%s.\n", txt[33]);	/* "message aborted" */
		unsave( CurConf, SaveConf, NulConf ) ;
		return;
	}
	
/* get who the message is being sent to */
moreto:
	green();
  	luxptr = dummy ;
	if(mode == EDIT)
		scpy(dummy, (char *) (Header->ForWhom), 25);
	else if ( mode != ENTER )
		scpy(dummy, (char *) (Header->Author), 25);
    else
		strcpy(dummy, "All");
	if ( !fido || ( caps && (mode == ENTER) )) /* PCBoard likes uppercase to/from field */
		strupr(luxptr);
    while (( intmp = readline(PRMTTO))==NULL) {
	    printf("\r") ;
	}
	if ( !fido || ( caps && (mode == ENTER) )) /* PCBoard likes uppercase to/from field */
		strupr(intmp);
	strcpy(tmp, intmp);
	add_history(intmp);
	free(intmp);
	luxptr = NULL  ;
	StripDel(tmp);
	if (strlen(tmp) > (unsigned) 25) {
			red();
			printf("%s\n", txt[34]);	/* "Entry too long ! 25 chars max */
			goto moreto;
	}
	if (!stricmp(tmp, "N") || !tmp[0] ) {
			blue();
			printf("%s.\n", txt[33]);	/* "message aborted" */
			unsave( CurConf, SaveConf, NulConf ) ;
			return;
	}
	str2mem((char *) (Qmail.ForWhom), (char *) tmp);

/* get subject of message */
moresub:

	green();
	if (mode != ENTER ) {
			scpy(dummy, (char *) (Header->Subject), 25);
			luxptr =  dummy ;
	}
    while (( intmp = readline(PRMTSB))==NULL) {
	    printf("\r") ;
	}
	strcpy(tmp, intmp); 
	add_history(intmp);
	free(intmp) ;
	luxptr = NULL; 
	StripDel(tmp);
	if (strlen(tmp) > (unsigned) 25) {
		red();
		printf("%s\n", txt[34]);	/* "Entry too long ! 25 chars max */
		goto moresub;
	}
  	if (!stricmp(tmp, "N") || !tmp[0] ) {
		blue();
		printf("%s.\n", txt[33]);	/* "message aborted" */
		unsave( CurConf, SaveConf, NulConf ) ;
		return;
	}
	str2mem((char *) Qmail.Subject, (char *) tmp);

/* get security of message */		
moresec:
	green();
 	if ((mode != ENTER)&&( Header->Status == '+' || Header->Status == '*')) {
			luxptr =  "Receiver Only (private)" ;
			add_history("None (public)");
	} else {
			luxptr = "None (public)";
			add_history("Receiver Only (private)") ;
	}		
    while (( intmp = readline(PRMTSC))==NULL) {
	    printf("\r") ;
	}
	strcpy(tmp, intmp);
	add_history(intmp);
	free(intmp);
	luxptr = NULL  ;
	StripDel(tmp); StripSpaceL(tmp);
	if (tmp[0]) {
		strupr(tmp);
		if (strlen(tmp) > (unsigned) 25) {
			red();
			printf("%s\n", txt[35]);	/* "Too long! R=...etc..." */
			goto moresec;
		}
		if (tmp[0] == 'R'/* || !strnicmp(tmp,"priv", 4) */ ) 
			Qmail.Status = (char) 0x2A ;
		else	
			Qmail.Status = (char) 0x20 ;
  	} else {	
		blue();
		printf("%s.\n", txt[33]);	/* "message aborted" */
		unsave( CurConf, SaveConf, NulConf ) ;
		return;
	}
	
	sprintf(dummy, "%-7d", ConfNumbers[CurConf]);
	str2mem((char *) Qmail.ConfNum, dummy);	/* Msg goes to the current conference */

	if( mode == EDIT && SaveConf == RCONF_IDX )
		scpy(dummy, (char *) (Header->RefMsg), 7);
	else if ( mode  != ENTER )
		scpy(dummy, (char *) (Header->NumMsg), 7);
	
	str2mem((char *) Qmail.RefMsg, (mode == ENTER) ? "" : dummy );

	if (mode == REPLY && reedit == FALSE)
		QuoteMsg(fname);/* Quote original message... */
	else if (mode == EDIT && reedit == FALSE)
		StripTag(fname);

	white();
	printf("\n%s\n", txt[38]);/* "calling editor" */
	
#ifndef USESYSTEM   /* use fork() instead of system() is preferred */
	reperror = FALSE ;
	signal(SIGINT, jert );

    if( (Proc_ID = fork()) == 0 ){
		execlp( Editor, Editor, fname, NULL );
		exit(-1);
	}
	if( Proc_ID > 0 ){
		if ( wait(&i) < 1 || reperror) ATPABRTRP ;
	}
	else
		ATPABRTRP ;
#else
	sprintf(cmd,"%s %s", Editor, fname);
    system (cmd) ;
#endif
	
	ATPSETERM ; /* reset terminal attributes */

/* Here is where we ask if we want to save message */

  /* Here is where we ask if spelling needs checking */

if(speller[0]){
   	while (( intmp = readline("Check spelling [Y/n] ?"))==NULL ) printf("\r") ;
	StripDel(intmp);
	intmp[0] = tolower( intmp[0] );
    if( intmp[0] != 'n' ){
#ifndef USESYSTEM
    	if( (Proc_ID = fork()) == 0 ){
			execlp( speller, speller, fname, NULL );
			exit(-1);
		}
		if( Proc_ID > 0 ){
			if ( wait(&i) < 1 )
				if(!reperror) ATPABRTRP ; /* unknown error abort */
			cls();
		}
		else
			ATPABRTRP ;
	}
	signal(SIGINT, SIG_DFL);
#else
		sprintf(cmd,"%s %s", speller, fname);
		system(cmd);
	}
#endif	
	ATPSETERM ; /* restore terminal parameters */
	free( intmp );
} /* end of spelling code */

	Tag("tag ?");
	printf("Fido style tagline is %s.\n\n", fido ? "ON" : "OFF");
	printf("select:\n\t`Save' to save reply.\n");
	printf("\t`Edit' to re-edit reply.\n");
	printf("\t`Fido' to toggle tagline style and save reply.\n");
	printf("\t`Abort' to cancel reply.\n\n");
	while (( intmp = readline ("Choose: Save, Edit, Fido, Abort  [Save] ?"))==NULL) printf("\r") ;
	strcpy (tmp,intmp);
	free(intmp);
	StripDel(tmp);
	tmp[0] = tolower(tmp[0]);
	if (tmp[0] == 'e') {
		reedit = TRUE;
		goto l_edit;
	}			/* re-edit message */
	if (tmp[0] != 's' && tmp[0] != '\0' && tmp[0] != 'f') {	/* abort reply */
		printf("\n\n%s\n", txt[33]);
		unlink(fname);
		unsave( CurConf, SaveConf, NulConf ) ;
		return;
	}
	if (tmp[0] == 'f') {
		togltag();
	}
	if (!fido)		/* adjust header for fido or not */
		for (i = 0; i < 50; i++)
			Qmail.ForWhom[i] = toupper(Qmail.ForWhom[i]);

	if ( AddReply(fname, (struct QmailRepType *) &(Qmail.Status)) ){ 
		if (autotag)
			ChooseTag();
		if (SaveConf==RCONF_IDX){
			CurConf = RCONF_IDX ;
			if (mode == EDIT)
				ReadNext(NUKE);
			TotMsg++;
			sprintf(dummy,"%ld",TotMsg);
			GoToNum (dummy);
		}
	}
abrtreps:
#ifndef USESYSTEM
	reperror = FALSE ;
	signal(SIGINT, SIG_DFL);
#endif	
	unsave( CurConf, SaveConf, NulConf ) ;
	return ;
}

/*
 * Add the reply to a Qmail reply.msg file.
 */
static int 
AddReply(const char *fname, struct QmailRepType * Qmail)
{
	if( ! OpenRepFile(ADDREP) )
		return FALSE ;
	if (KodeMessage(fname, Qmail))
		return FALSE ;
	ReplyExist = TRUE ;
	return TRUE ;
}




/*
 * LIST CONF : Prints conferences numbers,names, and status.
 */

static void
ListConf(void)
{

#define pers -2
#define reps -1

 	unsigned		line ;
	int             i=0 ;
	char            tmp[MAXPATHS];

	if (IsEmpty) {
		EmptyMsg();
		return;
	}
	cls();
	magenta();
	high();
	printf("\r%s %s\n", txt[78], BoardName);	/* "Liste des conf. sur" */
	clear();
	red();
	printf("\r");
	for (i = 0; i < (int) (strlen(txt[78]) + strlen(BoardName) + 1); i++)
		putchar('-');
	putchar('\n');

	for (i = pers, line = 0; i < RCONF_IDX ; i++) {
		line++;
		if (line > SCREENLINES - 5) {
			line = 0;
			printf("\n");
			if (!more(YES))
				break;
			cyan();
		}
		if (i ==  pers ) {	/* List personal conference first */
			if (pmail)
				blink();
			i = PCONF_IDX ;
		}
		if (i == reps )     /* List reply conference next */
			i = RCONF_IDX ;	

		sprintf(tmp, "%s%s%c%d.cnf", HomePath, CurBoard, SEP, ConfNumbers[i]);
		red();
		high();
		printf("\n\t\t%4d ", ConfNumbers[i]);
		clear();
		blue();
		printf("......... ");
		magenta();
		if ( (i == PCONF_IDX)  && pmail)
			blink();
		high();
		printf("%-15s ", ConfName[i]);
		clear();
		blue();
		printf("......... ");
		if ( (i == PCONF_IDX)  && pmail)
			blink();
		high();
		if (access(tmp, F_OK )) {
			printf("%s", txt[79]);	/* "Inactive" */
		} else {
			magenta();
			printf("%s", txt[80]);	/* "active" */
		}
		if( i == PCONF_IDX ){
			clear();
			i = pers  ;
		}
		else if (i == RCONF_IDX ) 
			i = reps  ;
	}
	clear();
	printf("\n\n");
#undef reps
#undef pers
}


/*
 * Goes to the msg number represented by the string. and print it.
 * ( Internal count, not BBS numbers ! )
 */

static void
GoToNum(const char *str){
	if( SeekNum( str ))
		Display(0);
}

/*
 * Seek to specific message number
 *
 */

static int
SeekNum(const char *str)
{
	long int        nb;
	size_t			nrecs ; /* number of records to read */

	if (IsEmpty) {
		EmptyMsg();
		return(0);
	}
	nb = atol(str);
	nb = nb - 1 ;
	if (nb < 0 || nb >= TotMsg) {
		red();
		high();
		printf("%s\n", txt[81]);	/* "Number out of range ! " */
		printf("%s ", txt[82]);	/* "Valid msgs are" */
		magenta();
		printf("1 ");
		red();
		printf("%s ", txt[83]);	/* "to" */
		magenta();
		printf("%ld\n", TotMsg);
		return(0);
	}
    if (fseek(fidx, ( nb * (long) sizeof(struct MyIndex)), SEEK_SET)) {
		printf("%s !\n", txt[16]);	/* "seek error" */
		return(0);
    }
    if (fread(&Index.LastRead, 1, sizeof(struct MyIndex), fidx)
	    != sizeof(struct MyIndex)) {
		printf("%s\n", txt[17]);	/* "End of messages " */
		return(0);
	}
	rewind(fmsg);
    if (fseek(fmsg, Index.Offset, SEEK_SET)) {
        printf("%s !\n", txt[16]);
        return(0);
	}
    nrecs = ( (Index.Size / 128 ) + 1 ) ; /* same as (Index.Size+128)/128) */
	if ((fread((char *) rbuf, 128, nrecs , fmsg)) != nrecs ) {
  		printf("%s ? \n", txt[18]);	/* "read error" */
		return(0);
	}
	rbuf[ (Index.Size)+128 ] = '\0' ; /* terminate buffer like a string */
	return(1); /* good seek */

}


/*
 * DISPLAY : Prints the current message,stored in memory.
 */

static void
Display(const int mode)
{
	
	unsigned long   i = 0 ;
	int             QuotedColor, line = 0, count = 0 ;
	byte           *ptr, *pt;
    	byte           *linbuf ; 

	if (IsEmpty) {
		EmptyMsg();
		return;
	}
	cls();
	PutHeader();
	if (( linbuf = (byte *) malloc(400)) == NULL ){ /* local line buffer */
		printf("malloc() failed in read.c module Display()\n\n");
		return;
	}
	cyan();

    	ptr =  rbuf + Index.Size + 127  ;  /* strip off trailing junk */
	while( *ptr == '\0' || *ptr == '\040' || *ptr == '\n' ) {
		*ptr = '\0' ;
	     ptr-- ;
	}
	*(++ptr) = '\n' ;
	
	ptr =  (rbuf + sizeof(struct MsgHeaderType));
	i = 0;
	line = QuotedColor = 0;
	pt = linbuf ;
	*pt = 0;

	while (i < Index.Size) {
		if (count > (int) 79 ) /* Security for long lines       */
			*ptr = '\n';

		if (*ptr == '\n') {    /* Display a total line          */
			count = 0;
			*pt = 0;
			line++;
			pt = linbuf ;
			if (IsQuoted('>', pt) ) {	/* Process colors on quoted line */
				while (*pt != '>')
					putchar(*pt++);
				QuotedColor = 1;
				red();	/* Quote char in red... */
				putchar(*pt++);
				green();	/* Quoted line in green.. */
				puts((char *) pt);
				cyan();
				pt = linbuf ;
			} else {
				if (QuotedColor) {
					cyan();
					QuotedColor = 0;
				}
				puts((char *) linbuf);
			}
		} else if (*ptr) {	/* Non 0 chars */
			if(charset != CHRDOS ){
				if ( vtspecial(*ptr) && graphics ){ /* use vt100 graphics codes */
	       			*pt++ =  '\016';
		   		*pt++ =  codevt[ (unsigned) (*ptr) ]  ;
	       			*pt   =  '\017';
				}
				else if (charset == ISOLAT1 ) 
					*pt = codelu[   (unsigned) (*ptr) ]; /* use iso lookup table */
            	else
					*pt = code7bit[ (unsigned) (*ptr) ];
			} 
			else
				*pt = *ptr ;
			pt++;
			count++;	/* Security for line length ... */
		}

		i++;
		ptr++;

		if (line > SCREENLINES - 8) {
			line = 0;
         	if (mode == KILL || mode == NUKE || mode == PRIVATE)
				break;	
			if (!more(YES))
				break;
			cyan();
		}
	}
	free(linbuf);
	FirstDone = TRUE;
	printf("\n");
}



/*
 * Welcome : Displays the welcome file.
 */

static void
Welcome(void)
{
	char            tmp[MAXPATHS];

	sprintf(tmp, "%s%s%c%s", HomePath, CurBoard, SEP, WELCOME );
	if (!access(tmp, R_OK )) {
		sprintf(tmp, "%s%s", HomePath, CurBoard);
		view(tmp, WELCOME );
	}else{
	sprintf(tmp, "%s%s%c%s", HomePath, CurBoard, SEP, WELCOMEG ); /* ansi welcome */
	if (!access(tmp, R_OK )) {
		sprintf(tmp, "%s%s", HomePath, CurBoard);
		view(tmp, WELCOMEG );
		}	
	}
}

/*
 * GETBBS : Called by main() with argv[1]. Looks for a new QWK packet, if
 * older than message base, just  loads the base.
 */

static void
GetBbs(const char *name)
{
	char            tmp[MAXPATHS];
	char            packet[MAXPATHS];
	char            base[MAXPATHS];
	struct stat     Oldst;
	struct stat     Newst;

	strcpy(tmp, name);
	if (strstr(name, ".qw") == NULL)
		strcat(tmp, ".qwk");

	sprintf(packet, "%s%s", MailPath, tmp);

	if (access(packet, R_OK )) {/* No new mail found */
		printf("%s\n", txt[31]);	/* "no new mail" */
		Read(name);
		return;
	}
	sprintf(base, "%s%s%c%s", HomePath, name, SEP, CNTRL_FILE);
	if (access(base, F_OK )) {
		printf("%s. ", txt[45]);	/* New BBS in this base. */
		sprintf(tmp, "load %s", name);
		Load(tmp);
		return;
	}
	stat(packet, &Newst);
	stat(base, &Oldst);

	if (Newst.st_mtime <= Oldst.st_mtime) {
		blue();
		high();
		printf("%s. %s.\n", txt[46], txt[47]);
		sprintf(tmp, "Read %s", name);
		Read(tmp);
		return;
	}
	sprintf(tmp, "Load %s", name);
	Load(tmp); 
}


static void
Purge(void)
{
	int             i;
	char            tmp[80];
	char            cnf[MAXPATHS];
	char            idx[MAXPATHS];
	struct stat     st;

	if (IsEmpty) {
		EmptyMsg();
		return;
	}
	magenta();
	high();			/* Selective erasing of conferences. */
	printf("\n%s\n", txt[102]);	/* Effacement sélectif des conférences */
	clear();
	red();
	printf("----------------------------------------\n\n");

	for (i = 0; i <= LastConf; i++) {
		sprintf(cnf, "%s%s%c%d.cnf", HomePath, CurBoard, SEP, ConfNumbers[i]);
		sprintf(idx, "%s%s%c%d.idx", HomePath, CurBoard, SEP, ConfNumbers[i]);

		if (stat(cnf, &st) == -1)
			continue;	/* No such file */

onemore:

		green();
		high();
		printf("Conf. %d [ ", ConfNumbers[i]);
		yellow();
		printf("%s", ConfName[i]);
		green();
		printf(" ] takes ");
		yellow();
		printf("%ld", st.st_size);
		green();
		printf(" bytes. Delete (Y)es (N)o (S)top : ");

		fget(tmp, 5, stdin);
		strupr(tmp);

		switch ((int) tmp[0]) {
		case 'N':
			break;

		case 'S':
			return;

		case 'Y':
		case 'O':
		case 'J':
			if (unlink(cnf) == -1)
				printf("Unable to remove file %s\n", cnf);
			if (unlink(idx) == -1)
				printf("Unable to remove file %s\n", idx);
			blue();
			if (i == CurConf) {
				Index.LastRead = 0;
				Index.MsgNum = 0;
				TotMsg = 0;
				if (FilesOpen) {
					fclose(fidx);
					fclose(fmsg);
					FilesOpen = FALSE;
					FirstDone = FALSE;
				}
			}
			ConfActive[i] = FALSE;
			if (i == findCindex(PERS_CONF))
				pmail = FALSE;
			printf("Conference %d is now empty.\n\n", ConfNumbers[i]);
			ActvCnt--;	/* one less active conference */

			break;

		default:
			goto onemore;
		}
	}
	if (!ConfActive[CurConf])
		AutoJoin();
}

/*
 * scan through the message headers 
 */

static void 
scruter(void)
{
	int             i, m;

	m = SCREENLINES / 6;
	do {
		cls();
		for (i = 0; i < m; i++)
			if (!ReadNext(SCAN))
				return ;
	}
	while (more(YES));
	return ;
}

/*
 * search conference for text string
 *
 */

static int
findtxt(const char *fndargs, const int mode) { /* valid modes are FIND & NEXT */
	static char findbuf[256] ;
	static long nm ;
    char *fndpt ;  /* not used but needed for future use */
	char nmbuf[30] ;
	if (mode == FIND ){
		strcpy(findbuf, fndargs);
		nm = 1 ;
	}
    if (findbuf[5] == (char) 0 || nm > TotMsg || nm < 1 )
		return(0) ; /* nothing to do */
	while( nm <= TotMsg ) {
		sprintf(nmbuf,"%ld",nm);
		nm++ ;
		if (!SeekNum( nmbuf ))   /* seek to next message in conference */
			return(0);
	    rbuf[96] = '\0' ;	/* mark end of header search */	
		if ( (fndpt = findstr( (byte *) &rbuf[128], (byte *) &findbuf[5] )) != NULL || 
			 (fndpt = findstr( (byte *) &rbuf[21],  (byte *) &findbuf[5] )) != NULL ) {
			Display(0);
			break;
		}
	}
	return(1);	
}


static char *
findstr( unsigned char *s1, unsigned char *s2)                   /* function to look for search string s2 in text string s1 */
{
    byte    *p1, *p2 ;
	
	p1 = s1;
	p2 = s2;

    while (*s1)                                             /* while the end of string s1 has not been reached, */
    {                                                       /* look for search string s2 */
        while ((isalpha(*p1) ? toupper(*p1) : *p1) ==       /* strip off lowercase if needed */
              (isalpha(*p2) ? toupper(*p2) : *p2))          /* while s2 matches within s1, */
        {
            p1++;                                           /* advance string compare pointers */
            p2++;
            if (!*p2)                                       /* if end of search string s2 is reached, */
                return( (char * ) s1);                                 /* return ptr to position in string s1 where s2 found */
            if (!*p1)                                       /* if end of string s1 reached prematurely, */
                return(NULL);                               /* return NULL indicating incomplete match */
        }
        p1 = ++s1;                                          /* if mismatch occurs, advance s1 string pointer */
        p2 = s2;                                            /* and reset search string pointer s2 */
    }
    return(NULL);                                           /* if end of string s1 reached, */
}                                                           /* return NULL indicating string s2 not in s1 */


/*
 * Search array for next active conference, wrapping around 
 * to start if need be.
 */

static int
FindActive(const int curcon)
{
	int             i;
	for (i = curcon + 1; i <= LastConf; i++) {
		if (ConfActive[i])
			return (i);
	}
	for (i = 0; i <= curcon; i++) {
		if (ConfActive[i])
			return (i);
	}
	return (-1);
}

static void 
showterms(void){
	int i = 0;	
	while( terms[i] != NULL && i < 50 ){
		printf("%s\n",terms[i]) ;
		i++;
	}

}

