/***********************************************************
	mn.c -- main module of LH
***********************************************************/
#include <ctype.h>
#include <stdio.h>
#include <io.h>
#include <dos.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "lh.h"
#include "errmes.h"
#include "intrface.h"
#include "disp.h"

#define SECURITY 0

#define CRCPOLY  0xA001  /* CRC-16 */

char work[4096];
char lhtmp1[] = "LHTMP)1(.LZH";
char lhtmp2[] = "LHTMP)2(.LZH";
FILE *inredir = NULL, *response = NULL;
int  outredir;
int  paramcount = -2;
char cmd;
int  cmdupdate;
char *env;
char workdir[MAX_PATH];
#if 0
char *pager = "LESS";
char *keyword = "";
#endif
char arcname[MAX_PATH];
char filename1[MAX_PATH];
char filename2[MAX_PATH];
char filename3[MAX_PATH];
FILE *file1, *file2, *file3;
int errorlevel = 0;

static time_t arcstamp;

/*******************************
		display usages
*******************************/
void usage(void)
{
	extract_internal(stdout, use);
	exit(2);
}

void update_arcstamp(void)
{
	if (arcstamp < hpb.utc) arcstamp = hpb.utc;
}

static void set_arcstamp(FILE *f)
{
	if (flg_t) setfiletime(f, arcstamp);
}

static char *readword(FILE *file)
{
	char *p;
	int c;

	while (((c = getc(file)) & 0xff) <= ' ');
	if (c < 0) {
		fclose(file);
		return NULL;
	}
	p = work;
	do {
		*p++ = c;
	} while ((c = getc(file)) > ' ');
	*p++ = '\0';
	return work;
}

static void disparcname(char *title)
{
	FILE *f;

	f = (cmd == 'L') ? stdout : stderr;
	if (flg_n == 0) {
		fprintf(f, "\n%s archive : %s\n\n", title, arcname);
	}
}

static int executecmd(void)
{
	int modified, err;
	char far *bdir, *path;
	ulong size0, size;
	uchar c;

	make_crctable(CRCPOLY);
	err = 0;
	arcstamp = 0;
	modified = 0;
	strcpy(filename1, arcname);
	if (cmdupdate) {
		strcpy(backpath(filename1), lhtmp1);
		if (remove(filename1) && errno != ENOENT)
			error(RDONLY, filename1);
		rename(arcname, filename1);
	}
	file1 = myeopen(filename1, "rb", NULL);
	if (cmdupdate || cmd == 'S') {
		if (file1 == NULL) {
			fclose(mywopen(arcname, MKFILEERR));
			remove(arcname);
		}
		if (flg_w) {
			strcpy(filename2, workdir);
			convdelim(filename2, DELIM);
			c = filename2[strlen(filename2) - 1];
			if (c != DELIM && c != ':') strcat(filename2, DELIMSTR);
			strcat(filename2, lhtmp2);
		} else {
			strcpy(filename2, arcname);
			strcpy(backpath(filename2), lhtmp2);
		}
		file2 = mywopen(filename2, NULL);
		if (file2 == NULL) {
			file2 = mywopen(lhtmp2, NULL);
			if (file2 == NULL)
				error(MKTMPERR, filename2);
			strcpy(filename2, lhtmp2);
		}
		setvbuf(file2, NULL, _IOFBF, 0x2000);
	} else {
		setvbuf(file1, NULL, _IOFBF, 0x2000);
	}
	switch (cmd) {
	case 'V':
		flg_x = 1;
		cmd = 'L';
	case 'L':
		disparcname("Listing of");
		initlist();
		break;
	case 'A':
		flg_c = 1;
		cmd = 'U';
	case 'U':
	case 'M':
		if (file1) {
			disparcname("Updating");
		} else {
			disparcname("Creating");
		}
		mklist();
		break;
	case 'F':
		disparcname("Freshening");
		break;
	case 'D':
		disparcname("Deleting from");
		break;
	case 'P':
	case 'E':
		disparcname("Extracting from");
		break;
	case 'T':
		disparcname("Testing");
		break;
	case 'S':
		disparcname("Making SFX of");
		initsfx();
		break;
	}

/************/
	if (file1) {
		size0 = inithdr();
		if (cmd == 'T' && 
		    stricmp(arcname + strlen(arcname) - 4, ".LZH") == 0 && 
		    size0 != 0) {
			eprintf(EXTRADATA);
		}
		if (cmdupdate) {
			rewind(file1);
			copyfile(file1, file2, size0, 0);
		}
		while (file1 && (path = gethdr(&err)) != NULL) {
			bdir = matchpat(path);
			switch (cmd) {
			case 'L':
				if (bdir) {
					list();
				}
				break;
			case 'U':
			case 'M':
				modified += append();
				break;
			case 'F':
				modified += freshen(bdir);
				break;
			case 'D':
				if (bdir) {
					dispalone("Deleted");
					eprintf("\n");
					modified++;
				} else {
					copylzh();
				}
				break;
			case 'E':
			case 'P':
			case 'T':
				if (bdir) {
					extract(bdir);
				}
				break;
			case 'S':
				if (bdir) {
					if (copysfx()) modified++;
				}
				break;
			}
			free(path);
		}
	} else {
		size0 = 0;
		if (!cmdupdate) error(NOARCERR, arcname);
	}

	/************/

	if (!err) {
		switch (cmd) {
		case 'L':
			endlist(getfiletime(file1));
			break;
		case 'U':
		case 'M':
			modified += endappend();
			break;
		case 'S':
			makesfx(bdir);
			break;
		}
	}
#if SECURITY
	if (cmd == 'T') {
		extern int security(void);

		if (security()) return 1;
	}
#endif
	if (err) error(BROKENARC, arcname);
	if (cmd == 'M') deletefiles();
	if (cmdupdate || (cmd == 'S' && file2)) {
		putc('\0', file2);
		size = ftell(file2);
		fflush(file2);
		if (ferror(file2)) error(WTERR, filename2);
		set_arcstamp(file2);
		fclose(file2);
		if (file1) {
			set_arcstamp(file1);
			fclose(file1);
		}
		if (modified == 0) {
			rename(filename1, arcname);	/* restore the old archive */
			remove(filename2);
		} else {
			if (rename(filename2, arcname)) {
				if (diskspace(filename1) < size) error(COPYERR, NULL);
				eprintf("Copying TMP to ARC ... ");
				rename(filename1, arcname);
				file1 = mywopen(arcname, COPYERR);
				file2 = myropen(filename2);
				copyfile(file2, file1, size, 0);
#if 0
				if (fflush(file1)) error(WTERR, filename2);
#endif
				set_arcstamp(file1);
				fclose(file1);
				fclose(file2);
				remove(filename2);
				eprintf("done.\n");
			} else {
				if (cmd != 'S') remove(filename1);
			}
			if (size - size0 <= 1) remove(arcname);
		}
	} else {
		fclose(file1);
	}
	return 0;
}

static int execute(void)
{
	struct find_t findbuf;
	int nofile;
	int testflag;

	testflag = 0;
	nofile = _dos_findfirst(arcname, 0x07, &findbuf);
	if (nofile && strchr("AUM", cmd) == NULL)
		error(NOARCERR, arcname);
	if (cmdupdate) {
		if (strpbrk(arcname, "*?")) error(NOARCERR, arcname);
					/* when updating archive, wild cards can't used */
		if (!nofile && findbuf.attrib & 0x01)
			error(RDONLY, arcname);
		executecmd();
	} else {
		do {
			backpath(arcname);
			strcat(arcname, findbuf.name);
			testflag |= executecmd();
		} while (!_dos_findnext(&findbuf));
	}
	if (cmd != 'L' && testflag == 0) tstpat();
}

int main(int argc, char *argv[])
{
	uchar c, *p, *q;
	int i;
	static fileinputflag = 0;
	static char far *basedir = "";

	initbreak();
	getswchar();
	initpat();
	if ((p = getenv("TMP")) != NULL 
		&& (p = strtok(p, " \t")) != NULL) {
		strcpy(workdir, p);
		flg_w = 1;
	}
	if ((env = getenv("LHA")) == NULL)
		env = getenv("LHARC");
	if (!isatty(0)) {
		fileinputflag = 1;
		inredir = fdopen(dup(0), "rt");
		fclose(stdin);
		fopen("con", "rt"); 			/* open stdin */
	}
	outredir = !isatty(1);
	argc--;
	argv++;
	while (1) {
		if (env) {
			while (*env && (uchar)*env <= ' ') env++;
			if (*env == '\0') {
				env = NULL;
				continue;
			}
			p = env;
			while (*env > ' ') env++;
			if (*env) {
				*env++ = '\0';
			}
		} else if (response) {
			fileinputflag = 1;
			if ((p = readword(response)) == NULL) {
				response = NULL;
				continue;
			}
		} else if (argc) {
			argc--;
			p = *argv++;
		} else if (inredir == NULL || (p = readword(inredir)) == NULL) {
			break;
		}

		if (*p == swchar && swchar != '-' || *p == '-' && !flg_at) {
			p++;
			getopt(p);
			continue;
		} else if (*p == '@' && !flg_at) {
			if (!response) {
				p++;
				if ((response = fopen(p, "rt")) == NULL)
					error(RDERR, p);
				continue;
			}
		}

		if (paramcount == -2) {
			/* get command */
			cmd = toupper(*p);
			if (p[1] != '\0' || !strchr("EXTDLVAUMFPS", cmd)) {
				cmd = 'L';
				paramcount++;
			}
			/* command updating archive? */
			cmdupdate = (int)strchr("AUMFD", cmd);
			/* command 'X' = 'E -x1m1' */
			if (cmd == 'X') {
				cmd = 'E';
				flg_x = flg_m = 1;
			}
		}
		if (paramcount == -1) {
			/* get archive name */
			i = strlen(p);
			strcpy(arcname, p);
		} else if (paramcount >= 0) {
			convdelim(p, DELIM);
			c = p[strlen(p) - 1];
			if (c == DELIM || c == ':') {
				basedir = strcmp(p, "." DELIMSTR) ? regbdir(p) : "";
				continue;
			} else {
				regpat(p, basedir);
			}
		}
		paramcount++;
	}
	if (paramcount == -2) usage();
	if (paramcount == -1) error(NOARCNMERR, NULL);
	if (paramcount == 0) {
		if (cmd == 'D' || fileinputflag) {
			error(NOFNERR, NULL);
		}
		regpat("+", basedir);
	}
	if (flg_o) flg_h = 0;

	p = convdelim(arcname, DELIM);
	if ((q = strchr(p, '.')) == NULL) {
		strcat(arcname, ".LZH");	/* if no extension */
	} else if (stricmp(".LZH", q) && cmdupdate) {
		if (flg_m == 0) {
			eprintf(NOTLZH, arcname);
			c = getyn();		/* if the extension is not '.LZH' */
			if (c == 'N') {
				return(2);
			}
		}
		flg_h = 0;
	}

	execute();
	return errorlevel;
}
