/*
 *  MBFILE.C - 6/23/87
 */
/*
 *  History of Modifiy - by A.Yamada(JA3JWI)
 *
 *  2. Support /EX for the ETX(got a part from 4.0's code       87/12/08
 *  1. Implement to Xenix.
 */


#include "mb.h"

word filesize;
char *fm;
DIRPATH *dphd;

#if (XENIX|UNIX|BSD)
#define FLOW_NO() flow_no()
#define FLOW_YES() flow_yes()
#else
#define FLOW_NO()
#define FLOW_YES()
#endif

/*
 *  Prepend path given by opt2 to file spec given by p.
 */

DIRPATH *getdir(p)
char *p;
{
	DIRPATH *dp;

	for (dp = dphd; dp isnt NULL; dp = dp->next) if (dp->id is port->opt2)
	{
		strcpy(port->line, dp->path);
		strcat(port->line, p);
		if (!(port->mode & p_sysop)) for (; *p; p++)
			if ((*p is ':') or (*p is '\\') or (*p is '/'))
			{ 
				port->msg = mcant; 
				return NULL; 
			}
		return dp;
	}
	port->msg = mndir; 
	return NULL;
}

/*
 *  Display the directory paths.
 */

shpaths()
{
	DIRPATH *dp;

	sprintf(port->line, "Use %c and directory ID:\n", port->opt1);
	outstr(port->line);
	for (dp = dphd; dp isnt NULL; dp = dp->next) {
		sprintf(port->line, "%c%c %s\n", port->opt1, dp->id, dp->name);
		outstr(port->line);
	}
}

/*
 *  Display directory.
 */

prtdir()
{
char *tmpnam(), tmpfile[30];

#if	(XENIX|UNIX|BSD)
FILE *fp;
#endif
	DIRDEF dirdef;
	register short gap, i, j, k, l, ndir;
	register word totsize;

	XEPARSE();
	if (port->mode & (local | sysop)) {
		if (port->opt2 is ' ') {
			if (port->flds is 1) { 
				shpaths(); 
				return; 
			}
			strcpy(port->line, port->fld[1]);
		} else if (getdir(port->fld[1]) is NULL)
			return;
	} else {
		if (port->opt2 is ' ') { 
			shpaths(); 
			return; 
		}
		if (getdir(port->fld[1]) is NULL)
			return;
	}
#if	(XENIX|UNIX|BSD)
	tmpnam(tmpfile);
	sprintf(tmp->scr, "mbdir -a %s > %s", port->line, tmpfile);
	if (system(tmp->scr) == 0) {
		dload(tmpfile);
		unlink(tmpfile);
	} else {
DBGMSG((stderr, "Can't execute mbdir\n\r"));
		perror(tmpfile);
		fprintf(stderr, "\r");
	}
#else
	if (!diropen(port->line, &(tmp->dirent[0]), &dirdef)) { 
		port->msg = mfind; 
		return; 
	}

/*
 *  Get 'em
 */

	ndir = 0;
	while (tmp->dirent[ndir].size >= 0) {
		for (i = 0; i < ndir; i++)
			if (match(tmp->dirent[ndir].name, tmp->dirent[i].name))
			{
				tmp->dirent[i].size += tmp->dirent[ndir].size;
				ndir--;
			}
		dirnext(&(tmp->dirent[++ndir]), &dirdef);
	}

/*
 *  Sort 'em.
 */

	sort(tmp->scr, ndir, sizeof(DIRENT), tmp->scr + (sizeof(DIRENT) * ndir));

/*
 *  Sort 'em.  from RLI3.2
 */
/*
  for (gap = ndir/2; gap; gap /= 2)
  for (i = gap; i < ndir; i++)
  for (j = i - gap; j >= 0; j -= gap)
  {
    if (strcmp(tmp->dirent[j].name, tmp->dirent[j + gap].name) <= 0)
      break;
    strcpy(t.name, tmp->dirent[j].name);
    t.size = tmp->dirent[j].size;
    strcpy(tmp->dirent[j].name, tmp->dirent[j + gap].name);
    tmp->dirent[j].size = tmp->dirent[j + gap].size;
    strcpy(tmp->dirent[j + gap].name, t.name);
    tmp->dirent[j + gap].size = t.size;
  }
*/
/*
 *  Print 'em.
 */

	outchar('\n');
	totsize = 0; 
	gap = (ndir + 2) / 3;
	for (i = 0; i < gap; i++) {
		for (l = 0, k = i; (l < 4) and (k < ndir); l++, k += gap) {
			totsize += tmp->dirent[k].size;
			if (k isnt i) outstr(" | ");
			sprintf (port->line,
			    "%-12s %4uk", tmp->dirent[k].name, tmp->dirent[k].size);
			outstr(port->line);
		}
		outchar('\n');
	}

	sprintf(port->line, "\n%uk of %uk used, %uk free.\n\n",
	    totsize, dirdef.size, dirdef.free);
	outstr(port->line);
#endif
}

/*
 *  Output a line from the help file.
 */

helpo()
{
	if ((port->line[0] isnt '!') or (port->user->options & u_sysop)) { 
		if (port->line[0] is '!') port->line[0] = ' '; 
		outstr(port->line); 
	}
}

/*
 *  Find specific subject header in file.
 */

helps()
{
	short found = false;

	while (!found and (fgets(port->line, linelen, port->fl) isnt NULL))
		if ((port->line[0] is port->opt1) and
		    (port->line[2] is port->opt2)) found = true;

	if (!found) {
		sprintf(port->line, "\nNo help for - %c\n\n", port->opt2);
		port->msg = port->line;
		return;
	}

	found = false;
	while (!found and (fgets(port->line, linelen, port->fl) isnt NULL))
	{
		found = ((port->line[0] is '#') or (port->line[0] is '?'));
		if (!found) helpo();
		if (isbreak()) break;
	}
}

/*
 *  Dump all the help information.
 */

helpa()
{
	short ok = false;
	while ((fgets(port->line, linelen, port->fl) isnt NULL)) {
		if ((port->line[0] is '#') or (port->line[0] is '?')) {
			ok = (port->line[0] is port->opt1);
		}
		else if (ok) helpo();
		if (isbreak()) break;
	}
}

/*
 *  User wants help.
 */

help()
{
	if (port->flds is 1) port->opt2 = '_'; 
	else port->opt2 = *port->fld[1];
	if (port->opt1 is 'H') port->opt1 = '#';

	if ((port->fl = fopen(helpfile, "r")) is NULL) { 
		port->msg = mfind; 
		return; 
	}

	if (port->opt2 is '?') helpa(); 
	else helps();

	fclose(port->fl);
}

#if	!RENFIL_NO
/*
 *  N command, rename a file.
 */

renfil()
{
	register int fl;

	if ((fl = open(port->fld[1], O_RDONLY)) < 0)
	{ 
		nofile(port->fld[1]); 
		return; 
	}
	close(fl);
	if ((fl = open(port->fld[2], O_RDONLY)) >= 0)
	{ 
		close(fl); 
		port->msg = mexst; 
	}
	else rename (port->fld[1], port->fld[2]);
}
#endif

#if	!KILFIL_NO
/*
 *  Z command, delete a file.
 */

kilfil()
{
	XEPARSE();
	if (port->opt2 is ' ') strcpy(port->line, port->fld[1]);
	else if (getdir(port->fld[1]) is NULL) return;

	if (!unlink(port->line)) port->msg = mdone; 
	else nofile(port->line);
}
#endif

/*
 *  Are the two files in the same directory?
 */

samedir(t, f)
char *t, *f;
{
	register char *te, *fe;

        if ((te = strrchr(t, '/')) is NULL) te =strrchr (t,'\\'); /* Nov12,89*/
        if ((fe = strrchr(f, '/')) is NULL) fe = strrchr(f,'\\'); /* Nov12,89*/
	if ((te is NULL) and (fe is NULL)) return true;
	if ((te - t) isnt (fe - f)) return false;
	return matchn(te, fe, (int)(fe - f) + 1);
}

/*
 *  Copy a file.
 */

copy(f, t)
char *f, *t;
{
	register int n, in, out;

	filesize = 0;

	if ((in = open(f, O_RDONLY | O_BINARY)) < 0) return false;

	out = creat(t, pmode);
	close(out);
	out = open(t, O_RDWR | O_BINARY);

	while ((n = read(in, tmp->scr, scrmax)) > 0)
	{ 
		filesize += n; 
		write (out, tmp->scr, n); 
	}

	close(in);
	close(out);
	return true;
}

#if 0	/* Use copy() for insted. AY-881106 */
/*
 *  Merge a file.
 */

merge(f, t)
char *f, *t;
{
	register int n, in, out;

	filesize = 0;

	if ((in = open(f, O_RDONLY | O_BINARY)) < 0) return false;

	if ((out = open(t, O_RDWR | O_BINARY | O_APPEND)) < 0)
	{ 
		out = creat(t, pmode); 
		close(out); 
		out = open(t, O_RDWR | O_BINARY); 
	}

	while ((n = read(in, tmp->scr, scrmax)) > 0)
	{ 
		filesize += n; 
		write (out, tmp->scr, n); 
	}

	close(in);
	close(out);
	return true;
}
#endif

#if	!COPFIL_NO
/*
 *  V command: copy a file.
 */

copfil()
{
	register int n;

	XEPARSE();
	if ((n = open(port->fld[2], O_RDONLY | O_BINARY)) >= 0) { 
		port->msg = mexst; 
		close(n); 
		return; 
	}

	if ((n = open(port->fld[1], O_RDONLY | O_BINARY)) < 0)
	{ 
		nofile(port->fld[1]); 
		return;
	}
	close(n);
	copy(port->fld[1], port->fld[2]);
}
#endif

/*
 *  Upload, common code.
 */

uload(tname)
char *tname;
{
	register char *tp;
	int flag;    /* AY-870912 */

	if ((port->mode & local) and (port->dev is p_console))
		if (editor(tname))
			return;

	if ((port->fl = fopen(tname, "w")) is NULL)
	{ 
		port->msg = mcant; 
		return; 
	}

	filesize = 0;
	flag = false;  /* AY-870912 */
	while (true)
	{
		while(!getdat())
			;

		if (port->mode & gone)
		{
			fclose(port->fl);
                                                /* Nov11,89 unlink */
                        unlink(tname);
                        return;
		}

/*
 *  Stuff the line into the file.
 */

		if (match(port->line, "/EX\n")
			or match(port->line, "/ex\n")
			or match(port->line, "~.\n"))	/* for cu like :-) AY-880916 */
		{
			fclose(port->fl);
			return;
		}

		if ((tp = strchr(port->line, cpmeof)) is NULL)
		{
			filesize += strlen(port->line);
			fputs(port->line, port->fl);
		}
		else
		{
			if (tp isnt port->line)
			{
				*tp++ = '\n';
				*tp   = '\0';
				filesize += strlen(port->line);
				fputs(port->line, port->fl);
			}
			fclose(port->fl);
			return;
		}
	}
}

/*
 *  Upload a file, from local console and remote sysop.
 */

uloadl()
{
	XEPARSE();
	if ((port->fl = fopen(port->fld[1], "r")) isnt NULL)
	{ 
		port->msg = mexst; 
		fclose(port->fl); 
		return; 
	}
	prtx(fm);
	uload(port->fld[1]);
}

/*
 *  Upload a file, from logged in user.
 */

uloadr()
{
	DIRPATH *dp;

	if (port->opt2 is ' ') { 
		shpaths(); 
		return; 
	}
	XEPARSE();
	if ((dp = getdir(port->fld[1])) is NULL) return;
	if (!(dp->flags & dp_upload)) { 
		port->msg = mcant; 
		return; 
	}
	if (!(port->priv & p_upload)) { 
		port->msg = mcant; 
		return; 
	}
	if ((port->fl = fopen(port->line, "r")) isnt NULL)
	{ 
		port->msg = mexst; 
		fclose(port->fl); 
		return; 
	}
        strcpy (port->cmd, port->line ) ;       /* Nov16,89  line-->cmd */
        log('F', 'U', ' ', port->cmd ) ;
	prtx(fm);
        uload(port->cmd);
}

/*
 *  Download, common code.
 */

dload(fname)
char *fname;
{
	if ((port->fl = fopen(fname, "r")) is NULL) { 
		nofile(fname); 
		return; 
	}

	FLOW_YES();
        while(fgets(tmp->scr, scrmax, port->fl) isnt NULL)
        {
                if (isbreak () ) break ;  /* add Nov 16,89 */
                outstr(tmp->scr);
        }

	FLOW_NO();

	fclose (port->fl);
}

/*
 *  Display the "info" file.
 */

dloadi()
{
	dload(infofile);
}


/*
 *  Download a file, by logged in user.
 */

dloadr()
{
	DIRPATH *dp;

	if (port->opt2 is ' ') { 
		shpaths(); 
		return; 
	}
	XEPARSE();
	if ((dp = getdir(port->fld[1])) is NULL) return;
	if (!(dp->flags & dp_dnload)) { 
		port->msg = mcant; 
		return; 
	}
	if (!(port->priv & p_dnload)) { 
		port->msg = mcant; 
		return; 
	}
	log('F', 'D', ' ', port->line);
	dload(port->line);
}

/*
 *  Download a file, by remote sysop.
 */

dloads()
{
char *skipsp();

	if (port->opt2 is ' ')
	{
		if (port->flds is 1) { 
			shpaths(); 
			return; 
		}
#if	(XENIX|UNIX|BSD)  /* AY-871209 */
		strcpy(tmp->scr, (skipsp(port->line + 2)));
		strcpy(port->line, tmp->scr);
#else
		strcpy(port->line, port->fld[1]);
#endif
	}
	else
	{
#if	(XENIX|UNIX|BSD)
		unbl(port->fld[1], skipsp(port->line), 14);
#endif
		if (getdir(port->fld[1]) is NULL) return;
	}
	log('F', 'D', ' ', port->line);
	dload(port->line);
}

/*
 *  Download a file, by local console.
 */

dloadl()
{
char *skipsp();
register PORTS *tp;

	if (port->opt2 is ' ')
		port->opt2 = 'L';
	if ((tp = findport(port->opt2)) is NULL)
	{ 
		port->msg = mnport; 
		return; 
	}
#if	(XENIX|UNIX|BSD)  /* AY-871209 */
	unbl(tmp->scr, skipsp(port->line + 2), BUFSIZ);
	unbl(port->line, tmp->scr, BUFSIZ);
	if ((cport->fl = fopen(port->line, "r")) is NULL) { 
		nofile(cport->line); 
		return; 
	}
#else
	if ((cport->fl = fopen(cport->fld[1], "r")) is NULL) { 
		nofile(cport->fld[1]); 
		return; 
	}
#endif
	ioport(tp);
	pgst(NULL);

	FLOW_YES();
	while(fgets(tmp->scr, scrmax, cport->fl) isnt NULL) {
		outstr(tmp->scr);
		if (pgck() is 'Q') break;
#if (XENIX|UNIX|BSD)	/* AY-880825 */
		getdat();
		ioport(cport);		/* AY-880824 */
		pgck();
		ioport(tp);			/* AY-880824 */
#endif
	}
	fclose (cport->fl);

	FLOW_NO();

#if	(XENIX|UNIX|BSD)
	cport->fl = NULL;
#endif
        if (tp isnt cport) term(cport, tp, false ); /* NOV.11,89 */
	ioport(cport);
}
