/****************************************************************
 *   User edit/add routines for Metal/Z-MSG
 *
 *	FILE: MEUSER.C
 *
 *	     Copyright (c) 1984, 1985, 1986 Tim Gary
 *		    All rights reserved
 *
 ****************************************************************
 *
 * 1.50xx 08/13/86 Added support for user.phon kludge
 * 1.50xx 03/12/86 Allow group access code changes..
 * 1.40xx 02/10/86 External help files (lib members) used..
 * 1.40xx 02/04/86 Mods for use with hashed users file..
 * 1.40xx 01/26/86 Fixed for new format of things..
 * 1.31a  10/13/85 Release version.  Minor bug fixes in scan to user
 *		   number and if user not found.
 * 1.30xx 6/29/85  Packed down to under 8k.. must stay this way
 * 1.30xx 5/26/85  Minor cosmetic bugs fixed (prompt mode, etc)
 * 1.30xx 5/15/85  Edit user function made simpler.
 * 1.30xx 5/01/85  Split Add function to other overlay (space)
 * 1.30xx 4/25/85  Edit user fixed... was wiping previous user
 * 1.30xx 4/08/85  Fixed so selective read user funcs work
 * 1.30xx 4/04/85  Few bug fixes (won't re-delete users)
 * 1.20c 04/01/85  Not an April Fools joke.. mass stuff added
 * 1.20c 03/29/85  Still more mass user stuff added
 * 1.20c 03/23/85  More advanced mass-user delete method..
 * 1.20a 11/07/84  More work on the ADD command (gcntrs change)
 * 1.10e 11/03/84  # calls initialized in ADD
 * 1.10e 10/30/84  User width initialized.
 * 1.10a  9/12/84  Cosmetic fixes.
 * 1.10a  9/08/84  Cosmetic fixes.
 * 1.10a  9/01/84  Split from mutil for overlay Metal.
 *
 * 1.01a  6/10/84  Fixed for Aztec C 1.06.
 *
 * 1.0b	  4/13/84  Fixed for upper/lower case names.
 *
 ****************************************************************/

#include "xpm.h"	/* CPMIO header file for i/o operations.*/
#include "megen.h"	/* general defines		*/
#include "meglob.h"	/* global variable definitions	*/
#include "meovfn.h"	/* overlay function numbers	*/
#include "mefiles.h"	/* file names			*/

#include "ctype.h"

#define	EDITHLP "EDITMAINHLP"	/* must be exactly 11 chars	*/
#define	STATHLP	"EDITSTATHLP"	/* mass function time help	*/
#define	DATEHLP	"EDITDATEHLP"	/* mass function date help	*/
#define	CALLHLP	"EDITCALLHLP"	/* mass function calls help	*/

static int dead_rec_no=0;	/* for deleted user */
static int dead_user_no=0;	

/* main program */

ovmain(func,parm)
int func;
char *parm;
{

if (user.status==SYSOP)
	{
	if (func==EDITUSER)
		{
		init_tags();
		user_sweep(parm);
		}
	 else {		/* delete user */
		char temp[NAMELEN+2];
		users=open(USERFILE,1);
		if (del_user(parm)==ERROR) send("\n[User not found]\n");
		  else send("\n[Deleted]");
		close(users);
	      }
	}

}	/* main */


edituser()
{
register int cfast;
char temp[50];
usr *up;

up=bufloc(users);

/**********************************
 * begin editing user             *
 *********************************/

send("\n[Edit]\n\nHit return if no change.\n");

     do	{
	sprintf(buffer,"Name: %s : ",up->name);
	ask(buffer,temp,NAMELEN,UPLOW);
	if (*temp!='\0')
		{
		capstr(temp);
		if (isdigit(*temp))
			{
			send("First char can't be numeric!");
			continue;
			}
		   else {
			usr *tbuf;
			tbuf=malloc(128);
			movmem(up,tbuf,128);
			del_user(tbuf->name);	/* delete old user */
			strcpy(tbuf->name,temp);
			add_user(tbuf);
			up=bufloc(users);
			movmem(tbuf,up,128);
			free(tbuf);
			break;
			}
		}
	} while (*temp!='\0');


   sprintf(buffer,"City: %s : ",up->city);
   ask(buffer,temp,CITYLEN,UPLOW);
   capstr(temp);
   if (*temp!='\0') strcpy(up->city,temp);

     do {
	sprintf(buffer,"Password: %s : ",up->pass);
	ask(buffer,temp,PASSLEN,UP);
	if (*temp!='\0')
		{
		if (isdigit(*temp))
			{
			send("First char can't be numeric!");
			continue;
			}
		   else {
			strcpy(up->pass,temp);
		 	break;
			}
		}
	} while (*temp!='\0');

	sprintf(buffer,"Answer to Sysop question:: %s : ",up->phone);
	ask(buffer,temp,12,UP);
	if (*temp!='\0') strcpy(up->phone,temp);

     do {
	sprintf(buffer,"Status: '%c' (%s)  :",up->status,up->status==SYSOP ?
	"SYSOP" : up->status==SPECIAL ? "SPECIAL" : up->status==NORMAL ?
        "NORMAL" : up->status==NOCPM ? "NO OS" : 
	up->status==TWIT ? "*TWIT*" : "OTHER");

	ask(buffer,temp,10,UPLOW);
	if (*temp=='\0') continue;
	if (!index("+snxXabcde",*temp))
		{
		send("Bad status.  Try:\n'+' for SYSOP\n's' for SPECIAL\
\n'n' for NORMAL\n'x' for NO Operating System\n'X' for TWIT\
\nor 'a','b' or 'c' for user defined types\n");
		continue;
		}
	   else {
		up->status=*temp;
		break;
		}
	} while (*temp!='\0');

	do {
	   printf("Group read flag is currently %4x hex.\n",
		   up->group_flags);
	   ask("Enter new flag (in hex): ",temp,5,UP);
	   if (isxdigit(*temp)) up->group_flag=xtou(temp);
	   } while (*temp!='\0');

  write(users,0);		/* write new version */
  send("[Saved]\n");

} /* edituser */


user_sweep(name)
char *name;
{
register int flag;	/* to abort do loop */
int offset,c,all;
char temp[MAXLINE];
usr *up;

all=FALSE;
flag=TRUE;
users=open(USERFILE,0);

if (name) strcpy(temp,name);
  else *temp='\0';

if (strloc && !(*temp))
	ask("",temp,NAMELEN,UPLOW);	/* fudge to get parm */

if (*temp) {	/* if name passed, then it's from the selective read */ 
	if (find_user(temp)>=0) edituser();
	  else send("\n[User not found]\n");
	close(users);
	return TRUE;
	}

offset=0;
up=bufloc(users);

do {

   setrrec(users,offset);
   if (read(users,0)!=128)
	{
	putchar('\n');	/* mark end of file */
	setarec(users,0);
	offset=0;
	continue;
	}

   if (!all && (up->file_info&DEADUSER))
	{
	if (offset==0) offset=1;
	continue;		/* skip deleted users */
	}

   offset=0;			/* clear this afterwards */

   out_user();
   send("--> ");
   switch(c=tolower(getchar()))
	{
	case ' ':
	case '\n':
	case '\r':
		offset=1;	/* advance */
		break;
	case 'b':
	case '-':		/* backup one user */
	case '\b':
		offset=-1;
		break;
	case 'd':		/* delete? */
		purge_user();
		offset=1;	/* and bump past him */
		break;
	case 'u':
		unpurge_user();	/* undelete this user... */
		break;
	case 'a':		/* show all users (deleted ones too..) */
		all= all ? FALSE : TRUE;
		if (all) send("\n[All users]");
		  else send("\n[Only active Users]");
		break;
	case 'z':		/* to eof */
		toeof(users);
		offset=-1;	/* so next read will backup */
		break;
	case 'm':		/* mass delete from current position */
		mass_func();
		break;
	case 't':
		tag_users();
		break;
	case 'i':
		printf("\nPass: %s\nCity: %s\nAnswer to Sysop question: %s",up->pass,up->city,up->phone);
		break;
	case 'e':		/* edit this user */
		edituser();
		break;
	case '1':
	case '2':
	case '3':
	case '4':
	case '5':
	case '6':
	case '7':
	case '8':
	case '9':
		sprintf(temp,"%c",(char)c);	/* start of number */
		while ( isdigit(c=getchar()) && strlen(temp)<MAXLINE)
			sprintf(temp,"%s%c",temp,(char)c);
		if (c!='\r' && c!='\n' && c!=' ')
			{
			send("..abort\n");
			break;
			}
		setarec(users,atoi(temp)-1);
		if (read(users,0)!=128)
			{
			setarec(users,0);
			read(users,0);
			}
		break;
	case 'f':		/* find by name */
		ask("\nName to search for -> ",temp,NAMELEN,UPLOW);
		if (*temp) {
			unsigned sav_seek;
			sav_seek=getrec(users);
			if (find_user(temp)<0) {
				setarec(users,sav_seek);
				if (!finduser(temp)) setarec(users,sav_seek);
				}
			}
		break;
	case 'x':		/* abort this mode */
		flag=FALSE;
		break;
	default:
		ltype(METHELP,EDITHLP);		/* sweep_help(); */

	} /* switch */

   putchar('\n');		/* goto next line */
   } while (flag);		/* do... */

close(users);
return NULL;

}        /* deleteuser */


out_user()
{
char temp[8];
usr *up;
up=bufloc(users);

if (up->file_info&DEADUSER) strcpy(temp,"[dead]");
  else sprintf(temp,"%3u",getrec(users)+1);

printf("%s (%c - group %04x) %4u calls. %8s  %-26s",temp,up->status,
	up->group_flags,up->calls,ascdate(up->date),up->name);

}


purge_user()	/* delete user at current location */
{
usr *up;
register unsigned tu;

up=bufloc(users);
if (up->file_info&DEADUSER) return;	/* ignore already deleted users */

send("\n[User deleted]");
up->file_info|=DEADUSER;		/* zap him..	  */
write(users,0);				/* and do this... */
}


unpurge_user()	/* restore user at current location */
{
usr *up;

up=bufloc(users);
if ( !(up->file_info&DEADUSER) ) return;	/* not dead to start with */

send("\n[User restored]");
up->file_info^=DEADUSER;			/* reset status.. */
write(users,0);					/* and do this... */
}


/* To free a bit of room in compiling, zap a few unused defines */
#undef OSCOM
#undef BYECOM
#undef WELCOME

#define LT 3
#define GT 2
#define EQ 1
#define NOT 256
static char date_pat[10];		/* date pattern */
static int date_flag;			/* flag if date < or > or == */
static char stat_pat[10];		/* status matchers */
static int stat_flag;			/* flag if status == or != */
static int calls_num;			/* # of calls matcher */
static int calls_flag;			/* if < or > or == */
static int prompt_flag;			/* wether or not prompted mode */

init_tags()
{
*date_pat=*stat_pat='\0';	/* clear date/status flags */
date_flag=stat_flag=calls_flag=prompt_flag=calls_num=0;
}


show_tags()
{
printf("\n\nDate: %s %s	Status: %s %s	Calls: %s %u\n",
	date_flag==GT ? ">" :
		date_flag==LT ? "<" :
			date_flag==EQ ? "=" : "(none)",date_pat,
	stat_flag==EQ ? "=" :
		stat_flag==NOT ? "NOT" : "(none)",stat_pat,
	calls_flag==GT ? ">" :
		calls_flag==LT ? "<" :
			calls_flag==EQ ? "=" : "(none)",calls_num);
} /* show pat */


mass_func()
{
unsigned start_rec;		/* initial record #, and one to change */
int flag;
char temp[MAXLINE+1];

if ( !(calls_flag+stat_flag+date_flag) )
	{
	send("\nNo 'Tags' set.  Use the 'T' function to set them.\n\n");
	return;
	}

show_tags();

send("\nNote: function starts scanning at the CURRENT location,\n\
NOT at the start of the users file!!\n\n");

ask("Perform mass delete function (y/n)? ",temp,2,UP);
if (*temp!='Y') return;

sprintf(temp,"Prompted mode (RETURN=%s)? ",prompt_flag ? "YES" : "NO");
ask(temp,temp,2,UP);
switch (*temp) {
	case 'N':
		prompt_flag = !prompt_flag;
		break;
	case 'Y':
		prompt_flag = YES;
		break;
	case '\0':
		break;
	default:
		send("[aborted]\n");
		return;
	} /* switch */

start_rec=getrec(users);	/* save starting place */

while (read(users,0)==128)
	{
	usr *up;
	up=bufloc(users);
	flag=match_date();	/* check for date match */
	flag&=match_calls();	/* check for calls match */
	flag&=match_stat();	/* see if status matches */
	if (flag && !(up->file_info&DEADUSER))	/* if not already gone, and a match.. */
		{
		if (prompt_flag)
			{
			out_user();
			send("Delete? ");
			*temp=tolower(getchar());
			if (*temp=='y') purge_user();
			if ( ((*temp)&0x0b) == 0x0b)	/* ^k to abort */
				{
				send("[Purge aborted]");
				break;
				}
			  else send("\n[User REMAINS]");
			putchar('\n');
			}
		  else purge_user();
		}
	setrrec(users,1);	/* goto next record location for read */
	if (breakkey()) { send("\n[Mass deletion aborted!]\n"); break; }

	} /* while */
setarec(users,start_rec);	/* back to where we began */
read(users,0);			/* and read */

} /* mass function */


match_date()
{
int flag;
usr *up;
char td_pat[9],td_usr[9];

up=bufloc(users);

if (!date_flag) return TRUE;	/* fake match if no date pattern */

strncpy(td_pat,date_pat+6,2);	strncpy(td_pat+2,date_pat,2);
strncpy(td_pat+4,date_pat+2,2); td_pat[6]='\0';
strncpy(td_usr,ascdate(up->date)+6,2);
strncpy(td_usr+2,ascdate(up->date),2);
strncpy(td_usr+4,ascdate(up->date)+2,2); td_usr[6]='\0';

if (date_flag==EQ && !strcmp(td_usr,td_pat)) return TRUE;
if (date_flag==LT && (strcmp(td_usr,td_pat)==-1)) return TRUE;
if (date_flag==GT && (strcmp(td_usr,td_pat)==1)) return TRUE;

return FALSE;
}


match_stat()
{
usr *up;
int flag;
up=bufloc(users);

if (!stat_flag) return TRUE;	/* fake match if no status pattern */

flag=index(stat_pat,up->status);
if (stat_flag==EQ && flag) return TRUE;		/* match */
if (stat_flag==NOT && !flag) return TRUE;	/* also a match */
return FALSE;		/* otherwise no match */
}


match_calls()
{
usr *up;
up=bufloc(users);

if (!calls_flag) return TRUE;	/* fake match if no calls pattern */

if (calls_flag==EQ && up->calls==calls_num) return TRUE;
if (calls_flag==LT && up->calls<calls_num) return TRUE;
if (calls_flag==GT && up->calls>calls_num) return TRUE;

return FALSE;	/* otherwise no match */
}


tag_users()
{
char temp[MAXLINE+1];	/* parm holder */

show_tags();
ask("\nChange current tags (y/n)? ",temp,2,UP);
if (*temp!='Y') return;

send("\nReturn alone at a prompt CLEARS that match string!\n");
do {
   *date_pat='\0';		/* clear this */
   date_flag=0;		/* and this */

   ask("\nDate match string (? for help) -> ",temp,13,UP);
   if (*temp=='?') {
	ltype(METHELP,DATEHLP);
	continue;
	}
    switch (*temp) {
	case '\0':
		break;
	case '>':
		date_flag=GT;		/* Greater than flag */
		strcpy(date_pat,temp+1);
		break;
	case '<':
		date_flag=LT;
		strcpy(date_pat,temp+1);
		break;
	case '=':
		date_flag=EQ;
		strcpy(date_pat,temp+1);
		break;
	default:
		if (isdigit(*temp))
			{
			date_flag=EQ;
			strcpy(date_pat,temp);
			break;
			}
		  else {  *temp='?'; send("\nBad Match string.\n");  }
		break;
	} /* switch */
   } while (*temp && (strlen(temp)!=9) );	/* date match question */

do {
   *stat_pat='\0';
   stat_flag=0;

   ask("\nUser Status match string (? for help) -> ",temp,10+3,UPLOW);
   if (*temp=='?') {
	ltype(METHELP,STATHLP);
	continue;
	}
    switch (*temp) {
	case '\0':
		break;
	case '=':
		stat_flag=EQ;
		strcpy(stat_pat,temp+1);
		break;
	case '!':
		stat_flag=NOT;
		strcpy(stat_pat,temp+1);
		break;
	default:
		if (index("+snxXabcde",*temp))
			{
			stat_flag=EQ;
			strcpy(stat_pat,temp);
			break;
			}
		  else {  *temp='?'; send("\n[Bad Match String]\n");  }
		break;
	} /* switch */
   } while (*temp && (strlen(temp)<2) );  /* match question */


do {
   calls_num=0;
   calls_flag=0;

   ask("\nTimes user has called match string (? for help) -> ",temp,10,UPLOW);
   if (*temp=='?') {
	ltype(METHELP,CALLHLP);
	continue;
	}
    switch (*temp) {
	case '\0':
		break;
	case '=':
		calls_flag=EQ;
		calls_num=atoi(temp+1);
		break;
	case '>':
		calls_flag=GT;
		calls_num=atoi(temp+1);
		break;
	case '<':
		calls_flag=LT;
		calls_num=atoi(temp+1);
		break;
	default:
		if (isdigit(*temp))
			{
			calls_flag=EQ;
			calls_num=atoi(temp);
			break;
			}
		  else {  *temp='?'; send("\n[Bad Match String]\n");  }
		break;
	} /* switch */
   } while (*temp && (strlen(temp)<2) );  /* match question */

show_tags();

} /* tag_users */


finduser(name)
char *name;
{
register int cfast;
char temp[MAXLINE+1];
usr *up;

if (!name) {
	ask("Enter full or partial user name? ",temp,MAXLINE,UP);
	if (*temp=='\0') return FALSE;          /* exit to main */
	}
	else strcpy(temp,name);

up=bufloc(users);

send("\n[Searching..");
while ((cfast=read(users,1))==128)
         {
	 if (!(getrec(users)%25)) putchar('.');
         cfast=128;
	 if (!(up->file_info&DEADUSER))
       	         if (usindex(temp,up->name) || usindex(temp,up->phone)) break; /* found him */
                	 /* I know.. the index func. looks backwards..  */
         }
if (cfast!=128)
        {
        send("]\n[Not found]");
        return FALSE;
        }

setrrec(users,-1);	/* back to where user was actually read */
putchar(']');	/* make things look neato */
return TRUE;
}


/* End Of File */

