/*
     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.
*/	 

/*
readlib.c
*/

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h> 
#include <time.h>
#include <signal.h>
#ifndef unix
#include <dos.h>
#include <io.h>
#ifdef WIN32
#include <direct.h>
#else
#include <dir.h>
#endif
#endif

#include "system.h"
#include "ansi.h"
#include "makemail.h"
#include "qlib.h"
#include "reader.h"
#include "readlib.h"

extern const unsigned char codelu[] ;
extern const unsigned char codepc[] ;
extern const unsigned char code7bit[] ;
extern void Display(const int mode, struct fentry *bptr, int blen) ;
extern int  SeekNum(const char *str);

static void Initials(const byte * str, byte * dst, const int len) ;
static void RefMessage(FILE *fp, struct MsgHeaderType *Msg ) ;
static int  affect(char *var, const char *sign, char *value, char *value2, char *aLine );
static void PrePath(char *path);
struct fentry *findstr( unsigned char *s1, unsigned char *s2, struct fentry **sptr) ;

/*
 * Creates the Home Pathname. In the Unix version we look for for the
 * environment variable ATP. If that is not found we look for the HOME
 * variable and make our home path with that. If that fails we use the
 * current working directory as out home path. If that fails, we exit after
 * printing an error message. Note that Unix doesn't pass the path in
 * argv[0], only the name of the program. The MS-DOS version assumes that
 * argv[0] contains the current path. MakeHomePath is invoked from main() and
 * is passed argv[0].
 */

void
MakeHomePath(void)
{
	int             i;
	char           *pt;

	if ((pt = (char *) getenv("ATP")) != NULL) {
		strcpy(HomePath, pt);
		PrePath(HomePath);
	} else if ((pt = (char *) getenv("HOME")) != NULL) {
		strcpy(HomePath, pt);
		PrePath(HomePath);
	} else if ((pt = GETWD (HomePath, MAXPATHS)) != NULL) {
		PrePath(HomePath);
	} else {
		printf("\nERROR: MakeHomePath() module readlib.c\n");
		return;
	}

	i = strlen(HomePath);
	while (i) {
		if (HomePath[i] == SEP || HomePath[i] == ':' ||
		    HomePath[i] == SEPDOS)
			break;
		HomePath[i] = '\0';
		i--;
	}

	pt = HomePath;
	while (*pt) {
		if (*pt == SEPDOS)
			*pt = SEP;
		pt++;
	}
}


/*
 * Read the configuration file
 *
 */

int
ReadConfig(void)
{
	char            Path[MAXPATHS], RCLine[MAXPATHS], var[100], sign[100], value[100], value2[100];
	int             count = 0, donehere = FALSE;
	FILE           *cfg;

	printf("%s...\n", txt[53]);	/* "Reading config file" */
    speller[0] = 0 ;
	strcpy(OrigTag, " \n"); /* blank tagline */
	strcpy(UserTag, "  \n");
	strcpy(Archiver, "zip");        /* initialize default packer */
	strcpy(UnArchiver, "unzip");	/* initialize default unpacker */
	strcpy(Editor, "vi");			/* initialize default editor */
#ifdef UNIXCMDS
	strcpy(qwklist, "ls *.q* ");	/* initialize qwklist command */
	strcpy(bltlist, "ls blt*.* ");	/* initialize qwklist command */
#else
	strcpy(qwklist, "dir *.q* ");
	strcpy(bltlist, "dir blt*.* ");
#endif
	strcpy(Path, HomePath);
	strcat(Path, ".");
	strcat(Path, CONFIG_FILE);
	if ((cfg = fopen(Path, "rb")) == NULL) {	/* try to open cfg "dot" file */
		strcpy(Path, HomePath);
		strcat(Path, CONFIG_FILE);
		if ((cfg = fopen(Path, "rb")) == NULL) {	/* try again non-dot file     */
			/* "Unable to open config file" */
			printf("\n%s %s or .%s ! \n", txt[52], Path, CONFIG_FILE);
			return (ERROR);
		}
	}
	while (fget(RCLine, 255, cfg)) {
		count++;
		if (RCLine[0] != '#' &&  ( strlen(RCLine) >= (unsigned) 2) ) {
			var[0] = sign[0] = value[0] = value2[0] = '\0' ;	
			sscanf(RCLine, "%s %s %s %s", var, sign, value, value2);
			if ((donehere = affect(var, sign, value, value2, RCLine )) == ERROR) {
				/* "error in config file in line..." */
				printf("%s %s %s %d\n", txt[54], Path, txt[55], count);
				printf("%s %d : %s\n", txt[56], count, RCLine);
				fclose(cfg);
				return (ERROR);
			} else if (donehere == DONE)
				break;
		}
	}
	fclose(cfg);
	return (OK);
}

/*
 * Affects known configuration variables to their global values. Returns
 * ERROR on an invalid line. Ignores unknown variables.
 */

static int
affect(char *var, const char *sign, char *value, char *value2, char *aLine )
{
	char           *tptr;
	int             tmpint ;
	long			tmplong;

	strlwr(var);
	if (strcmp(sign, "="))
		return (ERROR);

	if (!strcmp(var, "editor") && value[0] ) {
		if ((tptr = strstr(aLine, " = " )) != NULL){
			if ((tptr = strstr(tptr, value)) != NULL){
				strcpy(Editor, tptr );
				return (OK);
			}
			else
				return (ERROR);
		}
		
	}
	if (!strcmp(var, "workpath")) {
#ifdef UNIXCMDS 
		if ( value[0] != SEP) { 
			GETWD (WorkPath, MAXPATHS);
			strcat( WorkPath, value );
		} else 
#endif
		strcpy( WorkPath, value );
		PrePath( WorkPath);
		strcat(WorkPath, WORK_DIR);
		return (OK);
	}
	if (!strcmp(var, "mail")) {
		MailPath[0] = 0 ;
		if (value[0] != SEP && value[1] != ':') {
			GETWD (MailPath, MAXPATHS);
			PrePath(MailPath);
        	} 
		strcat(MailPath, value);
		PrePath(MailPath);
		return (OK);
	}
	if (!strcmp(var, "reply")) {
		strcpy(ReplyPath, value);
		PrePath(ReplyPath);
		return (OK);
	}
	if (!strcmp(var, "archiver") && value[0] ) {
		if ((tptr = strstr(aLine, " = " )) != NULL){
			if ((tptr = strstr(tptr, value)) != NULL)
				strcpy(Archiver, tptr);
		} else {
			return (ERROR);
		}
		return (OK);
	}
	if (!strcmp(var, "unarchiver") && value[0] ) {
		if ((tptr = strstr(aLine, " = " )) != NULL){
			if ((tptr = strstr(tptr, value)) != NULL)
				strcpy(UnArchiver, tptr);
		} else {
			return (ERROR);
		}
		return (OK);
	}
	if (!strcmp(var, "ansi")) {	/* Starting in ansi mode or not... */
		strlwr(value);
		ansi = strcmp(value, "off") ? 1 : 0;
		return (OK);
	}
	if (!strcmp(var, "bell")) {	/* Starting in ansi mode or not... */
		strlwr(value);
		silent = strcmp(value, "on") ? 1 : 0;
		return (OK);
	}
	if (!strcmp(var, "color")) {	/* Starting in ansi color mode or not... */
		strlwr(value);
		color = strcmp(value, "on") ? 0 : 1;
		return (OK);
	}
	if (!strcmp(var, "user")) {	/* Get User First & Last Name      */
		sprintf(User1Name, "%s %s", value, value2);
		strcpy(UserName, User1Name);
		return (OK);
	}
	if (!strcmp(var, "tagline")){
		if ( value[0] && sign[0] == '=') {	/* Get persistent tagline */
			tptr = strchr(aLine, '=') ;
			tptr++;
			tptr++;
			strcpy(OrigTag, tptr);	/* Copy the Original tagline from config */
			strcat(OrigTag, "\n");
		}else{
			strcpy(OrigTag, " \n"); /* blank tagline */
		}
		return (OK) ;
	}
	if (!strcmp(var, "tagstyle")) {	/* default tag style Fido or PCB */
		strupr(value);
		if (!strcmp(value, "FIDO")) {
			fido = TRUE;
			strcpy(CurTag, FidoTag);
		}
		else{
			fido = FALSE;
			strcpy(CurTag, TagLine);
		}
		return (OK);
	}
	if (!strcmp(var, "autotag")) {	/* default tag style Fido or PCB */
		strupr(value);
		if (!stricmp(value, "OFF")) {
			autotag = FALSE ;
		}
		return (OK);
	}
	if (!strcmp(var, "graphics")) {	/* default tag style Fido or PCB */
		strupr(value);
		if (!stricmp(value, "ON")) {
			graphics = TRUE ;
		}
		return (OK);
	}
	if (!strcmp(var, "pcb")) {	/* default tag style Fido or PCB */
		strupr(value);
		if (!stricmp(value, "OFF")) {
			pcbext = FALSE ;
		}
		return (OK);
	}
	if (!strcmp(var, "header")) {	/* default tag style Fido or PCB */
		strupr(value);
		if (!stricmp(value, "OFF")) {
			HeadLetter = FALSE ;
		}
		return (OK);
	}
	if (!strcmp(var, "charset")) {	/* default tag style Fido or PCB */
		strupr(value);
		if (!strnicmp(value, "iso", 3) || !strnicmp(value, "lat", 3)) {
			charset = ISOLAT1 ;
		} else if (!strnicmp(value, "dos", 3) || !strnicmp(value, "msd", 3)) {
			charset = CHRDOS  ;
		} else{
			charset = CHR7BIT  ;
		}
		return (OK);
	}
	if (!strcmp(var, "taglist")) {	/* signal that old atprc was found */
		printf("\n\n\n READ THE DOCS: you must update your atprc file!\n\n");
		printf(" \"taglist\"  not valid opton for this release. \n");
		printf(" Taglines are now stored in textfile \"taglines.atp\".\n\n");
		abort();
	}
	if (!strcmp(var, "screenlen")) {	/* default screenlength */
		if (Numeric(value)) {
			tmpint = atoi(value);
			tmpint = (tmpint < 0) ? -tmpint : tmpint;
			if (tmpint > 2 && tmpint < 301)
				ScrnLines = tmpint;
		}
		return (OK);
	}
	if (!strcmp(var, "screencol")) {	/* default screenwidth */
		if (Numeric(value)) {
			tmpint = atoi(value);
			tmpint = (tmpint < 0) ? -tmpint : tmpint;
			if (tmpint > 2 && tmpint < 301)
				ScrnCols = tmpint;
		}
		return (OK);
	}
	if (!strcmp(var, "truncate")) {	/* default database truncation length */
		if (Numeric(value)) {
			tmplong = atol(value);
			tmplong = (tmplong < 0) ? -tmplong : tmplong ;
			if (tmplong < 1 )
				tmplong = 1 ;
			TruncNum = tmplong;
		}
		return (OK);
	}
	if (!strcmp(var, "qlist") && value[0] ) {	/* get command for listing packets */
		strcpy(qwklist, strstr(aLine, value));
		return (OK);
	}
	if (!strcmp(var, "blist") && value[0] ) {	/* get command for listing packets */
		strcpy(bltlist, strstr(aLine, value));
		return (OK);
	}
	if (!strcmp(var, "speller") && value[0] ) { /* get name of spelling checker */
		strcpy(speller, strstr(aLine, value));
		return (OK);
	}
return(OK);
}




/*
 * Adds the last separator to a pathname. Must be room enough for that in the
 * string !
 */

static void
PrePath(char *path)
{
	int             l;
	
	ADDRIVE (path); 
	l = strlen(path);
	if (path[l - 1] != SEP && path[l - 1] != SEPDOS) {
		path[l] = SEP;
		path[l + 1] = EOS;
	}
}



/*
 * Builts the full work directory pathname, and Deletes all files in the work
 * directory.
 *
 * ( System dependants functions are in system.c )
 */

void
Clean(void)
{
	if ( WorkPath[0] == '\0' ) {		
		strcpy(WorkPath, HomePath);
		strcat(WorkPath, WORK_DIR);
	}

	if (access(WorkPath, F_OK ))
		my_mkdir(WorkPath);
	else {
		printf("%s %s...\n", txt[57], WorkPath);	/* "Cleaning" */
		Erase(WorkPath);
	}
}


/*
 * FGET : Get a string like fgets, without any space or lf on the right.
 */

char *
fget(char *s, int n, FILE * fp)
{
	int             ch1 = EOF , ct = 0;
	char            tbuf[300];
	char           *p2;

	if (n > 300)
		return (NULL);

	p2 = tbuf;
	while (ct < (n - 1) && ct < 300) { /* get 'n' chars */
		ch1 = fgetc(fp);
		if (ch1 == EOF || ch1 == '\n')
			ct = 300;
		else if (ch1 != '\r') {
			*p2 = ( char ) ch1;
			ct++;
			p2++;
		}
	}
	*p2 = '\0';
	StripRSpace(--p2);
	while (ct < 300) {   /* keep getting chars till end of line is found */
		ch1 = fgetc(fp);
		if (ch1 == EOF)
			break;
		ct++;
		if (ct == 300)
			return (NULL);
		else if (ch1 == '\n') {
			ct = 300;
		}
	}
	strcpy(s, tbuf);
	if (ch1 == EOF)
		return (NULL);
    else
		return ( s );
}

/* ------------------------------------------------------------------- */
/*
 * Get conference, open global files etc...
 */

int
GetConf(const int num)
{				/* expects the raw array index as argument */
	char            tmp[MAXPATHS];
	struct stat     stats;

	sprintf(tmp, "%s%s%c%d.idx", HomePath, CurBoard, SEP, ConfNumbers[num]);
	if (FilesOpen) {
		fclose(fidx);
		fclose(fmsg);
		FilesOpen = FALSE;
	}
	if (access(tmp, F_OK )) {	/* File does not exists, no mail. */
		red();
		printf("%s %s\n", txt[44], tmp);	/* "No mail on conf" */
		return (ERROR);
	} else {		/* Ok file exists, read it . */
		if ((fidx = fopen(tmp, "r+b")) == NULL){
			printf("%s %s\n", txt[49], tmp);	/* "unable to read file" */
			return (ERROR);
		}
	}
	stat(tmp, &stats);
	if ( (TotMsg = (long int) (stats.st_size / sizeof(struct MyIndex))) < (long) 1 ){
		red();
		printf("%s %s\n", txt[44], tmp);	/* "No mail on conf" */
		return (ERROR);
	} 
	sprintf(tmp, "%s%s%c%d.cnf", HomePath, CurBoard, SEP, ConfNumbers[num]);
    if ((fmsg = fopen(tmp, "r+b")) == NULL) {
		printf("%s %s ! \n", txt[58], tmp);	/* "Error Reading file" */
		fclose(fidx);
		return ERROR;
	}
	/* Go  to Last message read */
#ifdef ATPDBG
	Index.LastRead = (-99L) ; /* seed Index.LastRead with known bad value */
#endif	
	if(fread((char *) &Index.LastRead,(size_t) sizeof(struct MyIndex), 1, fidx) != (size_t) 1 ) {
		printf("Can't read index in GetConf()\n");
	}
	if( Index.LastRead == VIRGINDX ) /* virgin index, seek first message */
	  fseek(fidx, 0L, SEEK_SET);
	else
	  fseek(fidx, (long) Index.LastRead * (long) sizeof(struct MyIndex), SEEK_SET);
	CurConf = num;
	FirstDone = FALSE;
	FilesOpen = TRUE;
	return (OK);
}



/*
 * Copy the current msg in file tmpname with quotes.
 */

void
QuoteMsg(const char *tmpname)
{

	FILE           *fq;
	struct MsgHeaderType *Msg;
	unsigned long     i;
	int             col;
	byte           *ptr ;

	char		quote[10];
	char		tmp1[MAXPATHS];
	char		tmp2[50];
	char		tmp3[50];
	char		tmp4[50];
	char		tmp5[50];

	Msg = (struct MsgHeaderType *) rbuf;

	tmp2[0] = 0;
	if (!strnicmp((char *) (Msg->Author), "SYSOP", 5))
		strcpy(quote, "Sys> ");
	else if (!strnicmp((char *) (Msg->Author), "UUCP", 4))
		strcpy(quote, "> ");
	else {
		memcpy( tmp1, Msg->Author, 25 );
		tmp1[25] = 0 ;
		col = sscanf( tmp1, "%s %s %s %s",tmp2,tmp3,tmp4,tmp5) ; 
		if (col){
			if( col == 1 ) tmp3[0] = tmp2[1]? tmp2[1] : ' ' ;	
		} else
		 	tmp3[0] = tmp2[0] = ' ' ;
	
		switch(col){
	case 3:
		sprintf(quote, "%c%c%c> ", tmp2[0], tmp3[0], tmp4[0] );	/* Initials.. */
		break;
	case 4:
		sprintf(quote, "%c%c> ", tmp2[0], tmp5[0] );	/* Initials.. */
		break;
	default:
		sprintf(quote, "%c%c> ", tmp2[0], tmp3[0] );	/* Initials.. */
	}
	}
	printf("\n%s %s ...\n", txt[59], quote);	/* "Quoting message with " */

	if ((fq = fopen(tmpname, "w")) == NULL) {
		printf("%s %s !\n", txt[50], tmpname);	/* "Unable to create file" */
		return;
	}

	RefMessage(fq, Msg);	/* Dear User, in a message to... */

	ptr = (byte *) (rbuf + sizeof(struct MsgHeaderType));
	i = 0 ;
	if( PCBLONG && SubjBuf[0] ) {
		/* while( *ptr++ != 0x0a ) i++ ; */
		if( ptr[70]== 'N' && ptr[69]== 0x20 && (ptr[71]== '\n' || ptr[72]== 0x20 ) ) 
			ptr += 72, i += 72 ;
		else if ( ptr[71]== 'N' && ptr[70]== 0x20 && (ptr[72]== '\n' || ptr[72]== 0x20 ) ) 
			ptr += 73, i += 73 ;
		else {
			i = strlen( SubjBuf ) + 10 ;
			ptr += i ; 
		}
	}
	fprintf(fq, "%s", quote);
	col = strlen(quote);
	while (i < Index.Size) {
		if (*ptr == '\n' ) {
			fprintf(fq, "\n%s", quote);
			col = strlen(quote);
		} else if (*ptr != '\0') {
			if (col < 77) { /* Trunc quoted lines to 77 cols */
				if (charset == ISOLAT1 )
					fprintf(fq, "%c", codelu[(unsigned) (*ptr)]);
				else if (charset == CHR7BIT )
					fprintf(fq, "%c", code7bit[(unsigned) (*ptr)]);
				else
					fprintf(fq, "%c", *ptr == 255 ? '\040' : *ptr );
			}
			col++;
		}
		i++;
		ptr++;
	}
	fclose(fq);
}


/* Strip Tagline from edited reply */

void
StripTag (const char *tmpname)
{

	unsigned long    i;
	FILE           *fq;
	byte           *ptr ;

    if ((fq = fopen(tmpname, "w")) == NULL) {
		printf("%s %s !\n", txt[50], tmpname);	/* "Unable to create file" */
		sleep(4);
		return;
	}
	ptr = (byte *) (rbuf + sizeof(struct MsgHeaderType));
	i = 0;
	if( PCBLONG && SubjBuf[0] ) {
		while( *ptr != 0x0a ) i++ , ptr++ ;
		i++ , ptr++ ;	
	}
	while ( i < Index.Size ){
		if( *ptr == 255 && *(ptr+1) == '\n' && *(ptr+5) == '\n' ) 
			break ;
        if (*ptr == '\n' )
            fprintf(fq, "\n" );
        else if (charset == ISOLAT1 )
			fprintf(fq, "%c", codelu[(unsigned) (*ptr)]);
		else if (charset == CHR7BIT )
			fprintf(fq, "%c", code7bit[(unsigned) (*ptr)]);
		else
			fprintf(fq, "%c", *ptr);
		i++;
		ptr++;
	}
	fprintf(fq, "\n");
	fflush(fq);
	fclose(fq);
}

/*
 * R‚alise l'entˆte de la lettre...
 */

#define PUBLIC    1
#define MYSELF    2
#define NOPE      3

static void
RefMessage(FILE *fp, struct MsgHeaderType *Msg ) 
{
	char            Destin[30];
	char            Ref[30];
	int             mon, day, mod;

	if (!HeadLetter)
		return;
    
    Msg->MsgDate[2] = Msg->MsgDate[5] = '-' ;		
	sscanf((char *) (Msg->MsgDate), "%d-%d", &mon, &day);
	Initials((byte *) (Msg->Author), (byte *) Destin, 25);Destin[25]=0;
	Initials((byte *) (Msg->ForWhom), (byte *) Ref, 25);Ref[25]=0;

	if (!strnicmp((char *) (Msg->ForWhom), "ALL", 3))
		mod = PUBLIC;
	else if (!strnicmp((char *) (Msg->ForWhom), UserName, strlen(UserName)))
		mod = MYSELF;
	else
		mod = 0;

	if (strnicmp((char *) (Msg->Author), "UUCP", 4 )) {
	fprintf(fp, "%s %s,\n", txt[96], Destin);	/* "Cher"           */
	fprintf(fp, "%s", txt[97]);	/* "Dans un msg du" */
	fprintf(fp, " %d %s, ", day, Months[mon - 1]);
	switch (mod) {
	case PUBLIC:
		fprintf(fp, "%s :\n\n", txt[98]);	/* "vous ‚crivez"   */
		break;

	case MYSELF:
		fprintf(fp, "%s :\n\n", txt[99]);	/* "vous m'‚crivez" */
		break;

	default:
		fprintf(fp, "%s", txt[100]);		/* "destin‚ …"      */
		fprintf(fp, " %s, ", Ref);
		fprintf(fp, "%s :\n\n", txt[98]);	/* "vous ‚crivez"   */
	}
	}

}



/*
 * Formatte le nom en minuscules, avec les initiales Upcase, dans dst, null
 * terminated.
 */
static void
Initials(const byte * str, byte * dst, const int len)
{
	int             m, i;

	m = 1;
	for (i = 0; i < len; i++) {
		*dst = *str;
		if ( *dst == '.' || *dst == '-' || *dst == ' ' ) {
			m = 1;	/* Next must be Upcase */
			if (m && i < 23) {
				if (!strnicmp((char *) ++str, "mc", 2)) {
					dst++;
					*dst = 'M';
					str++;
					dst++;
					*dst = 'c';
					i += 2;
				} else
					str--;
			}
		} else {
			*dst = m ? toupper(*dst) : tolower(*dst);
			m = 0;
		}
		str++;
		dst++;
	}

	*dst = 0;		/* build a null-terminated string */
	dst--;
	while (*dst == 32) {
		*dst = 0;
		dst--;
	}



}



/*
 * more : prompts "more  ?" and wait for yes, oui, ja . returns  1 for yes, 0
 * for no. 'def ' manages the CR default answer.
 *
 */

int
more(const int def)
{
	char            tmp[80] ;
	char		   *tmp1 ;

	for (;;) {
		high();
		yellow();
		if( def == YES )
			sprintf(tmp," %s ? %s : ", txt[60], txt[106]);
		else
			sprintf(tmp," %s ? %s : ", txt[60], txt[107]);
		luxptr = NULL ;
		while ((tmp1 = readline(tmp, FALSE))==NULL);
		strcpy(tmp, tmp1);
		free(tmp1);
		clear();
/*		up(1);  */
		printf("\r %-75s \r"," ");  /* erase prompt */
		switch ((int) tmp[0]) {
		case 'o':
		case 'y':
		case 'O':
		case 'Y':
		case 'j':
		case 'J':
			return (1);

		case 'N':
		case 'n':
			return (0);

		case '+':
		case '-':
		case 0:	/* CR */
        	case 10:
			if (def == YES) {
				return (1);
			} else {
				return (0);
			}

		}
	}
}



/*
 * YesNo : prompts "Y/N : " and wait for yes, oui, ja . returns  1 for yes, 0
 * for no.
 *
 */

int
YesNo(const int def, const char *prmt )
{
	char            tmp[80];
	char		   *tmp1 ;

	for (;;) {
		if(def == YES)
			sprintf(tmp,"%s %s : ", prmt, txt[106]);
        else
		    sprintf(tmp,"%s %s : ", prmt, txt[107]); 
		luxptr = NULL ;
		while ((tmp1 = readline(tmp,FALSE))==NULL);
		strcpy(tmp, tmp1) ;
		free(tmp1);
		clear();
/*		up(1); */
		printf("\r %-75s \r", " " );  /* erase prompt */
		switch ((int) tmp[0]) {
		case 'o':
		case 'y':
		case 'O':
		case 'Y':
		case 'j':
		case 'J':
			return (1);

		case 'N':
		case 'n':
			return (0);
		
		case 0:	/* CR */
			if (def == YES)
				return (1);
			else
				return (0);

		}
	}
}


void
PackReply(void)
{

	char            RepFile[MAXPATHS];
	char            MsgFile[MAXPATHS];
	char            Command[MAXPATHS];


	sprintf(RepFile, "%s%s.rep", ReplyPath, CurBoard);
	sprintf(MsgFile, "%s%c%s.msg", WorkPath, SEP, CurBoard);
	if( !Chk4Rep() && Cnf2Msg( MsgFile ) ){  /* make bbs.msg from 9001.cnf */
		sprintf(Command, "%s %s %s", Archiver, RepFile, MsgFile);
		yellow();
		high();
		printf("%s %s\n", txt[65], RepFile);	/* "packing replies in" */
		green();
		fflush(stdout);
		system(Command);
		ReplyExist = FALSE;
		unlink(MsgFile);
	}
	else
		printf("No replies packed.\n");
}

/* Chk4Rep returns TRUE if bbsname.rep exists */
int
Chk4Rep(void){ 

	char            RepFile[MAXPATHS];
	char            prmbuf[80] ;

	sprintf(RepFile, "%s%s.rep", ReplyPath, CurBoard);
	if (!access(RepFile, F_OK )) {
		red();
		high();
		/* "Warning ! file already exist " "delete it ?" */
		printf("%s   %s %s %s...!\n", txt[2], txt[62], RepFile, txt[63]);
		sprintf(prmbuf, "            %s ", txt[64]);
		if (YesNo(YES,prmbuf))
			unlink(RepFile);
		else{
			return(TRUE);
			}
	}
	return(FALSE) ;
}

void
Chk4Cnf(const char *tpath ){  /* does reply conference exist ? */

	char            Tcnfbuf[MAXPATHS];
	char		    Tidxbuf[MAXPATHS];
	char            prmbuf[80];

	sprintf(Tcnfbuf, "%s%c%d.cnf", tpath, SEP, REPL_CONF);
	sprintf(Tidxbuf, "%s%c%d.idx", tpath, SEP, REPL_CONF);

	ReplyExist = FALSE ;
	if (!access(Tcnfbuf, F_OK )) {
		red();
		high();
		/* "Warning ! file already exist " "delete it ?" */
		printf("%s   %s %d.cnf %s %s...!\n", txt[2], txt[62], REPL_CONF, ConfName[RCONF_IDX], txt[63]);
		sprintf(prmbuf,"            %s ", txt[64]);
		if (YesNo(YES,prmbuf)){
			unlink(Tcnfbuf);
			unlink(Tidxbuf);
			ConfActive[RCONF_IDX] = 0 ;
		}
		else
	        ReplyExist = TRUE ; 
	}

}
/*
 * UPDATECONF:  Write only if necessary the last read pointer in the first
 * index structure of the file.
 */
void
UpdateConf(int mode)  /* valid modes are UPDATE and RESET */  
{
	struct MyIndex  Idx;
	long			here ;

	if (ActvCnt < 1 || !(ConfActive[CurConf])) {
		printf("No active conference to update.\n");
		if (FilesOpen){
			printf("ERROR: module UpdateConf() -- open files, inactive Conf\n");
			printf("ActvCnt = %d  CurAct = %d \n", ActvCnt , ConfActive[CurConf] ) ;
		} ;
		return;
	}
	if (!FilesOpen) {
		printf("ERROR: module UpdateConf() -- bad file pointer for fseek()\n");
		return;
	}
	if (fseek(fidx, 0L, SEEK_SET)) {
		printf("UpdateConf() Seek error...\n"); 
		return;
	}
	fread((char *) &Idx.LastRead, 1, sizeof(struct MyIndex), fidx);
	if (((Idx.LastRead >= Index.MsgNum) && mode == UPDATE)  || ! FirstDone ) 
		return; /* nothing to do */
			
	Idx.LastRead = Index.MsgNum;
	fseek(fidx, 0L, SEEK_SET);
	fwrite((char *) &Idx.LastRead, 1, sizeof(struct MyIndex), fidx);
	printf("%s.\n", txt[66]);	/* "Last read pointer updated" */

	here = Idx.LastRead * sizeof(struct MyIndex);
	fseek(fidx, here, SEEK_SET);
}

/*------------------------------------------------------------------------*/
/*
 * NPRINT: Print a string not null-terminated on stdout.
 */
void
nprint(const byte * str, int len)
{
	while (len--)
		putchar(*str++);
}

/*------------------------------------------------------------------------*/
/*
 * NFPRINT: Print a string not null-terminated in file fp
 */
void
nfprint(FILE * fp, const byte * str, int len)
{
	while (len--)
		fputc(*str++, fp);
}

/*----------------------------------------------------------------------*/
/*
 * STR2MEM : copies a string without the null character in order to fill
 * correctly the Qmail header.
 */
void
str2mem(char *mem, const char *str)
{

	while (*str) {
		*mem = *str;
		str++;
		mem++;
	}
}

/*----------------------------------------------------------------------*/
/*
 * scpy : copies len bytes to src, deleting left spaces.
 *
 */
void
scpy(char *dest, const char *src, const int len)
{
	int    i;

	for (i = 0; i < len; i++)
		*(dest + i) = *(src + i);

	*(dest + i) = 0;

	i--;
	while (*(dest + i) == 32) {
		*(dest + i) = 0;
		i--;
	}

}

/*
 * VIEW :         View a file with more.
 *                note that the tmp buffer must be large enough to
 *                handle all ansi escape sequences and vt100 line
 *                graphics sequences (or you will bomb on a seg fault).
 */
void
view(const char *Path, const char *File)
{
	FILE           *fp;
	char		   *tmp ;
	unsigned char  *buf, *bptr, *ptr ;
	unsigned        line = 0;

	if(( tmp = (char *) malloc((size_t)2000))==NULL) {
		printf("malloc 1 in view() failed\n\n");
		return;
	}
	sprintf( tmp, "%s%c%s", Path, SEP, File);
	if ((fp = fopen(tmp, "rb")) == NULL) {
		red();
		printf("%s %s\n", txt[67], tmp);	/* "No file" */
		free(tmp);
		return;
	}
	if (( buf = (byte *) malloc((size_t)600) )==NULL){
		printf("malloc 2 in view() failed\n\n");
		free(tmp);
		return;
	}
	clear();
	cyan();
	printf("\n\n");
	while ( fget((char *) buf, 250, fp)) {
		line++;
		if (line > ScrnLines - 2) {
			line = 0;
			if (!more(YES))
				break;
			cyan();
		}
		/* translate DOS character set to LINUX character set */
		if(charset != CHRDOS ){
			ptr = buf;
			bptr = (byte *) tmp ; *bptr = 0 ;
			while (*ptr != '\0') {
				if ( graphics && vtspecial(*ptr) ){ /* use vt100 graphics codes */
					*bptr = '\016';
					bptr++ ;
					*bptr =  codevt[ (unsigned) *ptr ]  ;
	    			bptr++ ;
	    			*bptr   =  '\017'; 
				} else
				*bptr = charset == ISOLAT1 ? codelu[(unsigned) (*ptr)]
			                           : code7bit[(unsigned) (*ptr)];
				ptr++ ; bptr++ ;
				*bptr = '\0' ;
			}
			bptr = (byte *) tmp ;
		} 
		else
		    bptr = buf ;
		puts((char *) bptr);
	}
	free(buf);
	free(tmp);
	fclose(fp);
}



/* view tagline list */

void
tagview(const char *Path, const char *File)
{

	FILE           *fp;
	char            tmp[MAXPATHS];
	unsigned char   buf[513];
	int             line = 0, taglin = 0 ;

	sprintf(tmp, "%s%c%s", Path, SEP, File);
	if ((fp = fopen(tmp, "rb")) == NULL) {
		red();
		printf("%s %s\n", txt[67], tmp);	/* "No file" */
		return;
	}
	clear();
	cyan();
	printf("\n\n");
	while (fget((char *) buf, 250, fp)) {
		line++;
		if (line > ScrnLines - 7) {
			line = 0;
			if (!more(YES))
				break;
			cyan();
		}
		printf("%4d: %s\n", taglin, buf);
		taglin++ ;	
	}
	fclose(fp);
	more(YES) ; /*!!*/
}


/*
 * Si un rigolo tape ce mot dans le shell...
 */
void
merde(void)
{
	magenta();
	high();
	printf("\n");
	printf("EspŠce de petit connard, on t'a pas appris la politesse  ???%c\n", BELL );
	printf("Va te faire foutre !!!\n\n");
}

/*
 * NUMERIC : Returns 1 if the string is a number, 0 if not.
 */
int
Numeric(const char *str)
{
	if (*str == 0)
		return (0);
	while (*str) {
		if (*str < '0' || *str > '9')
			return (0);
		str++;
	}
	return (1);
}

/*
 * IsQuoted(str)   Returns 1 if the string contains c in the 6 left chars.
 */

int
IsQuoted(const unsigned char c, const unsigned char *str)
{
	int             i;

	for (i = 0; i < 6; i++) {
		if (*str == 0)
			return (0);
		if (*str++ == c)
			return (1);
	}
	return (0);
}

/*
 * DATE : prints the date :-)
 */

void
Date(void)
{
	time_t   t;
	char buf[50] ;
	
	blue();
	high();
	time(&t);
 	memcpy(buf, ctime(&t), 24 );
 	buf[24] = 0 ;	
	printf("%s", buf );
	green();
	printf("\n");
}

/*
 * EmptyMsg : Tell that there is no BBs loaded.
 */

void
EmptyMsg(void)
{
	red();
	high();
	printf("%s ", txt[68]);	/* "Hey !" */
	clear();
	magenta();
	printf("%s\n", txt[69]);/* There is no bbs loaded !" */
	printf("%s...\n", txt[70]);	/* use 'read' 'load' or 'help' command" */
	clear();
}

/* 
 * 	ShiftLeft shifts a string left at p1, if n==2 then string is shifted
 *	two spaces left
 */

void 
ShiftLeft(char *p1, const int n)
{
	char           *p2;

	p2 = p1;
	p2++;
	if (n == 2)
		p2++;
	while (*p2 != '\0') {
		*p1 = *p2;
		p2++;
		p1++;
	}
	*p1 = '\0';
	return ;
}


/* 
 *  Scans a line until there are no more backspace or 
 *  del or '\r' characters 
 */

void
StripDel(char *tp)
{
	char           *p;
	p = tp;
	while (*p != '\0') {
		if (p == tp)  /* first character on line */
			switch (*p) {

			case '\010':	/* backspace */
			case '\177':
				ShiftLeft(p, 1);	/* del       */
				break;
			case '\015':	/* carriage return */
				*p = '\0' ;
				return;
			case '\0':
				return;

			default:
				p++;
			}

		else
			switch (*p) {

			case '\010':

			case '\177':
				p--;
				ShiftLeft(p, 2);
				break;
			case '\015':	/* carriage return */
				*p = '\0' ;
				return;
			case '\0':
				return;

			default:
				p++;
			}

	}
}

/*
 * Qlist sets up shell command line for listing QWK packets in the mail
 * directory  sorted by creation time
 */

void
Qlist(const char *cmdlist)
{

	char            tmp1[MAXPATHS];
	char			tmp2[MAXPATHS];
	int 			l ;

	strcpy(tmp2, MailPath); l = strlen(tmp2) ;
	tmp2[--l] = (char) 0 ;
	GETWD (tmp1, MAXPATHS);	/* save current directory      */
  	CHPATH (tmp2);			/* change to Mail directory    */
	system(cmdlist);		/* execute command line        */
	CHPATH (tmp1);			/* restore current directory   */
}

void
Blist(const char *cmdlist)
{

	char            tmp1[MAXPATHS];
	char			tmp2[MAXPATHS];

	tmp2[0] = 0 ;
	sprintf(tmp2,"%s%s", HomePath,CurBoard); 
	GETWD (tmp1, MAXPATHS);	/* save current directory      */
  	CHPATH (tmp2);			/* change to Mail directory    */
	system(cmdlist);		/* execute command line        */
	CHPATH (tmp1);			/* restore current directory   */
}

/*------------------------------------------------------------------------*/

static const unsigned char tup8bit[] = {

        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
        0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
        0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
        0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
        0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
        0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
        0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
        0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
        0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
        0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
        0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
        0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 

        0x80, 0x9a, 0x90, 0x83, 0x8e, 0x85, 0x8f, 0x80,  /* 87 */
        0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,  /* 8f */
        0x90, 0x92, 0x92, 0x93, 0x99, 0x95, 0x96, 0x97,  /* 97 */
        0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,  /* 9f */
        0xa0, 0xa1, 0xa2, 0xa3, 0xa5, 0xa5, 0xa6, 0xa7,  /* a7 */
        0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,  /* af */
        0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,  /* b7 */
        0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,  /* bf */
        0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,  /* c7 */
        0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,  /* cf */
        0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,  /* d7 */
        0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,  /* df */
        0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,  /* e7 */
        0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,  /* ef */
        0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,  /* f7 */
        0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff } ;

/* DTC
 * search conference for text string
 *
 */

#ifndef FIND
#define FIND 4
#endif
 
struct fentry *
findstr( unsigned char *s1, unsigned char *s2, struct fentry **sptr)	/* function to look for search string s2 in text string s1 */
{
	byte	*p1, *p2 ;
	static struct fentry *entry ; /* remembers last link */
	struct fentry *tentry ; /* temporary pointer */
	
	if( *sptr == NULL) entry = NULL ;

	p1 = s1;
	p2 = s2;

	while (*s1)		/* while the end of string s1 has not been reached, */
	{				/* look for search string s2 */
		/* strip off lowercase if needed, while s2 matches within s1, */
		/* DTS pre-upshifted string s2 in calling routine */
		while ( tup8bit[ *p1 ] == *p2 )
		{
			p1++;				/* advance string compare pointers */
			p2++;
			if (!*p2)	{		/* if end of search string s2 is reached, */
			        			/* return ptr to position in string s1 where s2 found */	
				tentry = malloc ( sizeof( struct fentry )) ;
				tentry->fnext = NULL ;
				tentry->findpt = (char *) s1 ; 
				if( *sptr != NULL )
					entry->fnext = tentry ;
				else
					*sptr = tentry ; /* first in linked list */
				entry = tentry ;				
			}
			if (!*p1)			/* if end of string s1 reached prematurely, */
				return(entry);	/* return last entry in linked list */
		}
		p1 = ++s1;				/* if mismatch occurs, advance s1 string pointer */
		p2 = s2;				/* and reset search string pointer s2 */
	}
	return( entry );		/* if end of string s1 reached, */
}							/* return last entry in list */


int
findtxt(const char *fndargs, const int mode) { /* valid modes are FIND & NEXT */
	static int findlen=0;
	static char findbuf[256] ;
	static long nm ;
	struct fentry *sentry = NULL, *tentry ;
	long offst ;
	byte tchar = 0 ;
	char nmbuf[30] ;

	if (mode == FIND ){
		strcpy(findbuf, fndargs);
		nm = 1 ;

		/* DTS added "for" and "findlen" below. "Next"s are faster if we
		 *   upshift the target string once when "find" is done. 
		 */
		findlen = iso2dosup( (byte *) &findbuf[5] );
	}
	if (findbuf[5] == (char) 0 || nm > TotMsg || nm < 1 )
		return(0) ; /* nothing to do */
	
#ifdef HAVE_SIGINT 
	signal(SIGINT, SIG_IGN);
#endif	
	while( nm <= TotMsg )
	{
		sprintf(nmbuf,"%ld",nm);
		nm++ ;
		if (!SeekNum( nmbuf ))	/* seek to next message in conference */
			return(0);

		/* search header fields then message body */
		for( offst = 21 ; offst < 129 ; offst+=25 ) {
			if( offst == 96 ) 
				offst = 128 ;
			if( offst < 96 ) {    /* mark end of strings in header */
				tchar = rbuf[offst+25] ; 
				rbuf[offst+25] = 0 ; 
			} 
			findstr( (byte *) &rbuf[offst], (byte *) &findbuf[5], &sentry) ;
			if( offst < 96 ) /* restore saved character in header */
				rbuf[offst+25] = tchar ;
		}
		if( sentry != NULL ){
			Display(0, sentry, findlen);
			break;
		}
	}
	while( sentry != NULL ) {  /* free linked list */
				tentry = sentry->fnext ;
				free( sentry );
				sentry = tentry ;
	} 
#ifdef HAVE_SIGINT 
	signal(SIGINT, SIG_DFL);
#endif
	return(1);	
}

struct fentry *
hprint( byte *hbuf, unsigned offst, unsigned len, struct fentry **bptr, int blen ) 
{
	char linbuf[200], *pt,  *chkptr ;
	byte *ptr ;
	struct fentry *tpr;
	int i, vidon = FALSE ; 

	tpr = *bptr ;
	ptr = hbuf + offst ;
	pt = linbuf;
	chkptr = linbuf + 180 ;  /* security for buffer overun */
	*pt = 0 ;

	for( i = 0 ; i < len ; i++ ) {
	if( blen && tpr != NULL ) { 
	if ( ptr == (byte *) tpr->findpt )	/* Beginning of the found string */
		if( ansi )
		{
			strcpy( pt, "\033[7m"); pt += 4 ;  /* reverse video on */
			vidon = TRUE ;
		} else {
			strcpy( pt, "}*"); pt += 2 ;
		}

	if ( ptr == (byte *) (tpr->findpt + blen)) /* End of the found string */
		if( ansi )
		{
#ifdef VT220 
 			if ( stricmp(termtype,"xterm") ) {
				strcpy( pt, "\033[27m") ; /* reverse video off */
				pt += 2 ;
			}
			else	
#endif
			strcpy( pt, "\033[m") ;  /* reverse video off */
			pt += 3 ;
			vidon = FALSE ;
			tpr = tpr->fnext ;
		} else {
			strcpy( pt, "*{"); pt += 2 ;
		}
	}
	if(*ptr != '\0' ){
		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  /* use 7 bit character set */
			*pt = code7bit[ (unsigned) (*ptr) ]; 
		} 
		else
			*pt = *ptr ;
	}
	else 
		i = len ; /* done */
	if( pt > chkptr )
		i = len ; /* buffer full, done */
	pt++, ptr++ ;	
	}
	if( vidon ) { /* turn off reverse video */
#ifdef VT220
 	if ( stricmp(termtype,"xterm") ) {
		strcpy( pt, "\033[27m") ; /* reverse video off */
		pt += 2 ;
	}
	else	
#endif
	strcpy( pt, "\033[m"); /* reverse video off */
	pt += 3 ;
	}
	*pt = 0 ; /* mark end of string */
	printf("%s", linbuf );	
	return( tpr );
}

/* translate search target and count length */
int
iso2dosup( byte *dpt )
{ 
	int ct = 0 ;	
	while(  *dpt && ct < 256 ) {
		if(charset == ISOLAT1){ /* must search with DOS char. set! */
			if (*dpt > 0x7f)
				*dpt = codepc[ *dpt];	/* translate back to DOS set */
		}
		*dpt = tup8bit[*dpt]; /* international capitalization */
		ct++, dpt++ ;
	}	
return ct ;	
}
