/* Citadel/UX sysop utilities for release 3.4
 * The software assumes that if any user who has access to this program is
 * allowed to use the sysop utilities. Make sure that the permissions
 * are correct for this.
 */

#define CLN (5184000L)		/* user purge time */
#define RLN (1209600L)		/* room purge time */

#include <fcntl.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "citadel.h"

long atol();
long lseek();
char *malloc();

struct config config;

int hash(str)
char str[]; {
	int h = 0;
	int i;

	for (i=0; i<strlen(str); ++i) h=h+((i+1)*tolower(str[i]));
	return(h);
	}

long finduser(file,name)
int file;
char *name; {
	FILE *fp;
	int c=0;
	int uh,fh;
	long pp;
	
	uh=hash(name);
	fp=fopen("hashtab","r");
	while(fread((char *)&fh,sizeof(int),1,fp)>0) {
		if (uh==fh) {
			pp=(long)c * (long)sizeof(struct usersupp);
			lseek(file,pp,0);
			return(pp);
			}
		++c;
		}
	fclose(fp);
	return(-1L);
	}

main(argc,argv) 
int argc;
char *argv[];
{
	int a;
	char aaa[100];

	get_config();

	if (!strcmp(argv[1],"-u")) {
		userpurge();
		exit(0);
		}
	if (!strcmp(argv[1],"-r")) {
		roompurge();
		exit(0);
		}
	if (!strcmp(argv[1],"-h")) {
		write_hashtab();
		exit(0);
		}

while(1) {
	printf("\n\n\n\n\n\n\n\n\n\n\n\n");
	printf("%s\nCitadel/UX Sysop Utilities\n\n",HUMANNODE);
	printf(" 1. Purge old rooms\n");
	printf(" 2. \n");
	printf(" 3. Write userlog hash table\n");
	printf(" 4. Unlock message file\n");
	printf(" 5. Sort the userlog by User ID\n");
	printf(" 6. Sort the userlog by login name\n");
	printf(" 7. Purge old users\n");
	printf(" 9. Quit\n");
	printf("\n\n\n\n\n\n\n\n\n\n\n");
	printf(" Please enter your selection: ");
	gets(aaa);
	a=atoi(aaa);

	switch(a) {
	   case 1:	roompurge();
			break;
	   case 3:	write_hashtab();
			break;
	   case 4:	unlock();
			break;
	   case 5:	sortlog("usersupp",1);
			write_hashtab();
			break;
	   case 6:	sortlog("usersupp",0);
			write_hashtab();
			break;
	   case 7:	userpurge();
			break;
	   case 9:	exit(0);
	   default:	printf("Selection not available\n");
	   	}
 	    }
	}

write_hashtab() {
	struct usersupp u;
	int h;
	int in,out;
	
	in=open("usersupp",O_RDONLY);
	out=creat("hashtab",0600);
	while(read(in,&u,sizeof(struct usersupp))) {
		h=hash(u.fullname);
		write(out,&h,sizeof(int));
		}
	close(in);
	close(out);
	return(0);
	}

/* The msgmain file is locked through the MMstructure file during writes,
 * to avoid two processes writing in the same place. If the program crashes
 * while the file is locked, run this program to unlock it.
 */

unlock() {

	struct msgmain msgmain;
	FILE *fp;

fp=fopen("MMstructure","rb");
fread((char *)&msgmain,sizeof(struct msgmain),1,fp);
msgmain.MMflags = msgmain.MMflags & ~MM_BUSY;
fclose(fp);
fp=fopen("MMstructure","wb");

fwrite((char *)&msgmain,sizeof(struct msgmain),1,fp);

fclose(fp);

return(0);
}

sortlog(filename,how)
char *filename;
int how; {
	char aaa[100];
	struct usersupp rec1;
	struct usersupp rec2;
	int file;
	long aa,cc,dd,nrecs;

	system("clear");
	sprintf(aaa,"cp %s usersupp.bak",filename);
	system(aaa);
	file=open(filename,O_RDWR);
	if (file<0) return(file);
	aa=lseek(file,0L,2); nrecs=(aa/sizeof(struct usersupp));
	for (cc=0; cc<nrecs; ++cc) {
		printf("Sorted %5ld of %5ld records.\n",cc,nrecs);
		for (dd=(nrecs-1L); dd>cc; --dd) {
			aa=((dd-1L)*sizeof(struct usersupp));
			lseek(file,aa,0);
			read(file,&rec1,sizeof(struct usersupp));
			read(file,&rec2,sizeof(struct usersupp));
		    if ( ((how==0)&&(strucmp(rec1.fullname,rec2.fullname)>0))
			|| ((how==1)&&(rec1.eternal>rec2.eternal))) {
				lseek(file,aa,0);
				write(file,&rec2,sizeof(struct usersupp));
				write(file,&rec1,sizeof(struct usersupp));
				}
			}
		}
	close(file);
	return(0);
}


int struncmp(lstr,rstr,len)
char lstr[],rstr[];
int len; {
	int pos = 0;
	char lc,rc;
	while (pos<len) {
		lc=tolower(lstr[pos]);
		rc=tolower(rstr[pos]);
		if ((lc==0)&&(rc==0)) return(0);
		if (lc<rc) return(-1);
		if (lc>rc) return(1);
		pos=pos+1;
		}
	return(0);
	}


userpurge() {		/* removes anyone who hasn't called in 2 months */
	int a,b;
	FILE *fp1,*fp2;
	long aa;
	char aaa[100],bbb[100];
	struct usersupp usersupp;
	long now,call;
	FILE *post,*ls;

post=(FILE *)popen("aidepost","w");
if (post==NULL) post=(FILE *)popen("cat >/dev/null","w");
fprintf(post,"The following users have not called in the past %ld seconds\n",
		CLN);
fprintf(post,"or have been marked for deletion, and have been purged:\n");
time(&now);
printf("userpurge: <<  Purging user file   >>\n");
fp1=fopen("usersupp","r");
if (fp1==NULL) {
	printf("No usersupp file available.\n");
	return(1);
	}
fp2=fopen("usersupp.new","w");
if (fp2==NULL) {
	printf("Can't open the new file.\n");
	fclose(fp1);
	return(2);
	}
	b=1;
	while (fread((char *)&usersupp,sizeof(struct usersupp),1,fp1)==1) {
		call=now-(usersupp.lastcall);
		strcpy(aaa,usersupp.password);
		pwcrypt(aaa,PWCRYPT);
		if (!strucmp(aaa,"deleteme")) call=CLN+1L;
		if (usersupp.axlevel==0) call=CLN+2L;
		if ((call<=CLN)||(usersupp.flags&US_PERM)) {
			b=fwrite((char *)&usersupp,
				sizeof(struct usersupp),1,fp2);
			if (b<1) fprintf(stderr,"userpurge: cannot rewrite\n");
			}
		else {
			printf("           #%-5ld %s\n",
				usersupp.eternal,usersupp.fullname);
			fprintf(post,"           #%-5ld %s\n",
				usersupp.eternal,usersupp.fullname);
			}
		}
END:	fclose(fp1);
	fclose(fp2);
	pclose(post);
	if (b>=1) {
		unlink("usersupp");
		link("usersupp.new","usersupp");
		unlink("usersupp.new");
		}
	printf("userpurge: << Rewriting hash table >>\n");
	write_hashtab();

	return(0);
	}


roompurge() {	/* remove any rooms which have not been accessed in 2 weeks */
	int file,a,b;
	char fname[50];
	long act,now;
	FILE *post;
	struct stat sbuf;
	struct quickroom quickroom;

	post=(FILE *)popen("aidepost","w");
	if (post==NULL) post=(FILE *)popen("cat >/dev/null","w");
	fprintf(post,
		"The following rooms have not been used for %ld seconds\n",RLN);
	fprintf(post,"and have been deleted from the room files:\n");
	time(&now);

	file=open("quickroom",O_RDWR);
	for (a=0; a<MAXROOMS; ++a) {
		sprintf(fname,"./rooms/fullrm%d",a);
		b=stat(fname,&sbuf);
		act=now-(long)sbuf.st_mtime;
		read(file,&quickroom,sizeof(struct quickroom));
		if ((a>2)&&(quickroom.QRflags&QR_INUSE)&&(act>RLN)&&(b>=0)
			&&((quickroom.QRflags&QR_NETWORK)==0)
			&&((quickroom.QRflags&QR_DIRECTORY)==0)) {

			quickroom.QRflags=quickroom.QRflags-QR_INUSE;
			lseek(file,(long)a*sizeof(struct quickroom),0);
			write(file,&quickroom,sizeof(struct quickroom));
			printf("roompurge: %20s deleted %ld\n",
				quickroom.QRname,act);
			fprintf(post,"%s\n",quickroom.QRname);
			}	
		}
	close(file);
	pclose(post);
	return(0);
	}


pwcrypt(text,code)
char text[];
int code; {
	int a;
	for (a=0; a<strlen(text); ++a) text[a]=(text[a]^(((code|128)^a)&0xFF));
	return(0);
	}
