/*
 *  MBUSER.C - 6/12/87
 */

#include "mb.h"

char *usfile, *usbfile;
USER_HDR *ufhs;
USER	 *tuser;
char *um[num_um];
char tcall[ln_call];
short maxusers;
static char *users;

int ufl;

/*
 *  Clean the user file.
 *  Force drain of buffers, update of directory items.
 */

clnuser()
{
#if 0	/* SHARE	/* AY-880725 */
	sync();
#else
	close(ufl);
	ufl = open(usfile, O_RDWR | O_BINARY);
#endif
}

/*
 *  Close the user file.
 */

clsusr()
{
	close (ufl);
}

/*
**  Open the user file.
*/

opnusr()
{
register PORTS *p;

/*
**  Allocate space for the user file records.
*/

	ufhs = (USER_HDR *) malloc(sizeof(USER_HDR));

	tuser = (USER *) malloc(sizeof(USER));
	tuser->rn = 0;

	users = (char *) malloc(ln_call * maxusers);
	if (users is NULL) errall();

/*
**  Open the file. If it does not exist, make one.
*/

	ufl = open(usfile, O_RDWR | O_BINARY);
	if (ufl < 0)
	{
		ufl = open(usfile, O_CREAT | O_RDWR | O_BINARY, pmode);
		if (ufl < 0) { 
			nofile(usfile); 
			exit(1); 
		}
		inuhdr();
		write_rec(ufl, 0, (char *)ufhs);
	}

/*
**  Read the user calls.
*/
#if SHARE /* AY-880725 */
	db_lock(ufl);
#endif
	read_rec(ufl, 0, (char *)ufhs);
	rdusers();
#if SHARE /* AY-880725 */
	db_unlock(ufl);
#endif
}

/*
**  Read each user record, build list of calls.
*/

rdusers()
{
	register int i;
	register char *up;

	if (ufhs->version < us_version)
	{
		sprintf(port->line, "Updating user file from version %d to version %d\n",
		    ufhs->version, us_version);
		outstr(port->line);
	}

	for (i = 1, up = users;
	    (i <= ufhs->count) and (i <= maxusers); i++, up += ln_call)
	{
		read_rec(ufl, i, (char *)tuser);
		strncpy(up, tuser->call, ln_call);

		if (ufhs->version < us_version)
		{
			if (ufhs->version < 6) remnl(tuser->path);
			if (ufhs->version < 7) tuser->ssid = tuser->ssid - '0';
			write_rec(ufl, i, (char *)tuser);
		}
	}

	if (ufhs->version < us_version)
	{
		ufhs->version = us_version;
		write_rec(ufl, 0, (char *)ufhs);
	}

	printf("%d users in %s\n\r", ufhs->count, usfile);
}

/*
 *  initialize the user file header.
 */

inuhdr()
{
	curtim();
	ufhs->count = 0;
	ufhs->version = us_version;
	strncpy(ufhs->date, l_date, ln_date);
	strncpy(ufhs->time, l_time, ln_time);
	ufhs->lmnr = mfhs->next_msg - 1;
	ufhs->dirty = false;
	fill (ufhs->free, '\0', 112);
}

/*
 *  Do we know this user?
 */

finduser(call)
char *call;
{
	register int i;
	register char *up;

	for (i = 1, up = users; i <= ufhs->count; i++, up += ln_call)
		if (matchn(call, up, ln_call)) return i;

	return 0;
}

/*
 *  Read in a user record.
 */

rduser(call, buf)
char *call;
USER *buf;
{
	register int i;

	if (i = finduser(call))
	{
		read_rec(ufl, i, (char *)buf);
		buf->rn = i;
		return;
	}

	/*
 *  There wasn't one, make one.
 */

	curtim();

	strncpy(buf->call, call, ln_call);
	strncpy(buf->date, l_date, ln_date);
	strncpy(buf->time, l_time, ln_time);
	buf->msg_number = 0;
	buf->ssid  = 0;
	buf->state = 0;
	ljsf(buf->handle, um[0], 12);
	buf->options = 0;
	buf->port = ' ';
	fill(buf->path, ' ', pathl);
	*buf->path = '\0';
	buf->log_count = 0;
	fill(buf->home_bbs, ' ', ln_call);
	buf->rn = 0;	/* Non valid record */
	fill(buf->unu2, 0, 3);
}

/*
 *  Update the user record to the file.
 */

upduser(buf)
USER *buf;
{
	if (!buf->rn) {
		if (ufhs->count >= maxusers) return;
		strncpy (users + (ln_call * ufhs->count), buf->call, ln_call);
		buf->rn = ++ufhs->count;
	}
	curtim();
	strncpy(buf->date, l_date, ln_date);
	strncpy(buf->time, l_time, ln_time);
	buf->msg_number = mfhs->next_msg;
	buf->log_count++;
	DB_LOCK (ufl);	/* AY-880725 */
	write_rec(ufl, buf->rn, (char *)buf);
	write_rec(ufl, 0, (char *)ufhs);
	DB_UNLOCK (ufl); /** AY-880725 */
}

/*
 *  Print the path to a user.
 */

puser()
{
	register int i;

	pcall(tcall, port->fld[1]);
	i = finduser(tcall);
	if (!i) { 
		port->msg = mfind; 
		return; 
	}

	read_rec(ufl, i, (char *)tuser);
	outnb(tuser->call, ln_call);
	if (tuser->port is 'L') {
		outstr(" Linked to "); 
		outnb(cport->user->call, ln_call);
		outstr(" Through the GateWay at "); 
		outstr(tuser->path);
	} else if (!*tuser->path) {
		outstr(" is a direct connect from "); 
		outnb(cport->user->call, ln_call);
	} else {
		outstr(" connected to "); 
		outnb(cport->user->call, ln_call);
		outstr(" via "); 
		outstr(tuser->path);
	}
	outchar('\n'); 
	return;
}

/*
 *  Print a user record.
 */

prtuser(p)
USER *p;
{
	fill(port->cmd, ' ', ln_call);
	if (p->options & u_local)	port->cmd[0] = 'L';
	if (p->options & u_bbs)	port->cmd[1] = 'B';
	if (p->options & u_expert)	port->cmd[2] = 'E';
	if (p->options & u_delete)	port->cmd[3] = 'D';
	if (p->options & u_sysop)	port->cmd[4] = 'S';
	if (p->options & u_exclude) port->cmd[5] = 'K';
	/* log_count is unsgined short,So we must use %4u AY-880527 */
	sprintf(tmp->scr,                                /* AY-871030 */
	"%6.6s %6.6s %4.4s %4u %5u %6.6s %2.2d%c%6.6s %-12.12s %s\n",
	    p->call, p->date, p->time, p->log_count,
	    p->msg_number, p->home_bbs, p->ssid,
	    p->port, port->cmd, p->handle, p->path);
	outstr(tmp->scr);                                /* AY-871030 */
}

/*
 *  The "display users" command.
 */

duser()
{
	register FILE *fl;
	register int i;
	register short ok;

	if (port->flds is 1)
		pgst(um[2]);
	else {
		XEPARSE();
		if ((fl = fopen(port->fld[1], "r")) isnt NULL) { 
			fclose(fl); 
			port->msg = mexst; 
			return; 
		} if ((fl = fopen(port->fld[1], "w")) is NULL) { 
			port->msg = mcant; 
			return; 
		}
	}

	for (i = ufhs->count; i; i--) {
		read_rec(ufl, i, (char *)tuser);
		ok = false;
		switch(port->opt2) {
		case 'L' : 
			ok = (tuser->options & u_local); 
			break;
		case 'M' : 
			ok = (tuser->options & u_bbs); 
			break;
		case 'S' : 
			ok = (tuser->options & u_sysop); 
			break;
		case 'U' : 
			ok = true; 
			break;
		case 'X' : 
			ok = (tuser->options & u_exclude); 
			break;
		}

		if (ok) {
			if (port->flds is 1) {
				if (isatty(1))	/* AY-880519 */
					pghd();
				prtuser(tuser);
				if (pgck() is 'Q') return;
			} else {
				prtuser(tuser);
				fprintf(fl, "%s", tmp->scr); /* AY-871030 */
			}
		}
	}
	if (port->flds is 1)
		pgdn();
	else fclose(fl);
}

/*
 *  The N, NE, NH (update my user info) command.
 */

chguser()
{
	switch(port->opt2)
	{
	case ' ' : 
		ljsf(port->user->handle, port->line + 2, 12);
		port->user->state setbit u_name;
		break;

	case 'E' : 
		port->user->options flipbit u_expert;
		break;

	case 'H' : 
		pcall(port->user->home_bbs, port->fld[1]);

		if (matchn(port->user->home_bbs, cport->user->call, ln_call))
			port->user->options setbit u_local;
		else port->user->options clrbit u_local;

		port->user->state setbit u_home;
		port->user->state clrbit u_sent;
		break;
	}
	port->msg = mdone;
}

/*
 *  EU command with no argument.
 *  Loop through all users, ask delete for each one.
 */

edusera()
{
	register word i;

	for (i = ufhs->count; i; i--)
	{
		read_rec(ufl, i, (char *)tuser);
		if (tuser->rn isnt i)
		{
			sprintf(tmp->scr, "User record %u has record # %u\n", i, tuser->rn);
			tuser->rn = i;
		}

		prtx(um[2]); 
		prtuser(tuser);

		prtx(um[3]); 
		getcmd();
		if (port->mode & gone) return;
		if (port->opt1 is 'Q') return;
		if (port->opt1 is 'Y')
		{
			tuser->options |= u_delete;
			write_rec(ufl, tuser->rn, (char *)tuser);
			ufhs->dirty = true;
		}
	}
}

/*
 *  Edit a user record.
 */

eduser()
{
	register USER *u;

	pcall(tcall, port->fld[1]);
	if (matchn(tcall, port->user->call, ln_call)) u = port->user;
	else { 
		u = tuser; 
		rduser(tcall, u); 
	}

	prtuser(u);
	prtx(um[3]);
	getcmd();
	if (port->mode & gone) return;
	if (port->opt1 is 'Q') return;
	if (port->opt1 is 'Y') u->options |= u_delete; 
	else
	{
		prtx(um[4]);
		getcmd();
		if (port->mode & gone) return;
		if (port->opt1 is 'Y') u->options flipbit u_expert;

		prtx(um[5]);
		getcmd();
		if (port->mode & gone) return;
		if (port->opt1 is 'Y') u->options flipbit u_bbs;

		prtx(um[6]);
		getcmd();
		if (port->mode & gone) return;
		if (port->opt1 is 'Y') u->options flipbit u_sysop;

		prtx(um[7]);
		getcmd();
		if (port->mode & gone) return;
		if (port->opt1 is 'Y') u->options flipbit u_exclude;

		prtx(um[8]);
		getcmd();
		if (port->mode & gone) return;
		if (port->flds) pcall(u->call, port->fld[0]);

		prtx(um[9]);
		getcmd();
		if (port->mode & gone) return;
		if (port->flds) u->ssid = atoi(port->fld[0]);

		prtx(um[10]);
		getcmd();
		if (port->mode & gone) return;
		if (port->flds)
		{
			u->state setbit u_name;
			ljsf(u->handle, port->line, 12);
		}

		prtx(um[11]);
		getcmd();
		if (port->mode & gone) return;
		if (port->flds) u->port = port->opt1;

		prtx(um[12]);
		getcmd();
		if (port->mode & gone) return;
		if (port->flds) strncpy(u->path, port->fld[0], pathl);
		else if (*port->line is ' ') *u->path = '\0';

		prtx(um[13]);
		getcmd();
		if (port->mode & gone) return;
		if (port->flds)
		{
			u->state setbit u_home;
			u->state clrbit u_sent;
			pcall(u->home_bbs, port->fld[0]);
			if (matchn(u->home_bbs, cport->user->call, ln_call))
				u->options setbit u_local; 
			else u->options clrbit u_local;
		}
		else if (*port->line is ' ')
		{
			fill(u->home_bbs, ' ', ln_call);
			u->options clrbit u_local;
			u->state clrbit u_home;
			u->state setbit u_sent;
		}
	}
	prtuser(u);
	if (!u->rn)
	{
		if (ufhs->count >= maxusers) return;
		strncpy (users + (ln_call * ufhs->count), u->call, ln_call);
		u->rn = ++ufhs->count;
	}
	write_rec(ufl, u->rn, (char *)u);
	ufhs->dirty = true;
}

#if !GU_NO	/* AY-880725 */
/*
 *  Backup the user file.
 */

untuser()
{
register char *rp, *wp, *lp;
register PORTS *p;
register int uflb;
register int incnt, inrec;

	prtx(um[1]);
	lp = tmp->scr + (128 * (scrmax / 128));
	upduser(port->user);

#if !(XENIX|UNIX|BSD)	/* AY-881108 */
	close(ufl);
	unlink(usbfile);
	if (samedir(usfile, usbfile)) rename(usfile, usbfile); 
	else copy(usfile, usbfile);
	unlink(usfile);

	ufl  = open(usfile,  O_CREAT	| O_RDWR | O_BINARY, pmode);
#else
	unlink(usbfile);
	sprintf(tmp->scr, "cp %s %s", usfile, usbfile);
	system(tmp->scr);
	DB_LOCK(ufl);
#endif
	uflb = open(usbfile, O_RDONLY | O_BINARY);

	incnt = ufhs->count;
	inuhdr();

	inrec = 1;
	while(incnt) {
		for (rp = tmp->scr; (rp < lp) and incnt;) {
			incnt--;
			read_rec(uflb, inrec++, rp);
			if (!(((USER *)rp)->options & u_delete)) rp += 128;
		}
		for (wp = tmp->scr; wp < rp; wp += 128)
			write_rec(ufl, ++ufhs->count, wp);
	}
	write_rec(ufl, 0, (char *)ufhs);
	close (uflb);
	clnuser();
	rdusers();
	rduser(port->user->call, port->user);
	DB_UNLOCK(ufl);	/* AY-881108 */
}
#endif
