#include "global.h"
#include "commands.h"
#include "mailbox.h"
#include "files.h"

extern void usercvt (void);

static int dombnewprofile (int argc, char *argv[], void *p);
static int dombdelprofile (int argc, char *argv[], void *p);
static int dombchgprofile (int argc, char *argv[], void *p);
static int domblistprofile (int argc, char *argv[], void *p);

static int dopasswd (int argc, char *argv[], void *p);
static int donewprofile (int argc, char *argv[], void *p);
static int dodelprofile (int argc, char *argv[], void *p);
static int dochgprofile (int argc, char *argv[], void *p);
static int dolistprofile (int argc, char *argv[], void *p);
static int doprofileext (int argc, char *argv[], void *p);
static int doprofileusermod (int argc, char *argv[], void *p);

static const char *profileExt = NULLCHAR;
static int profileUsermod = 0;


/* profile subcommand table */
static struct cmds ProTab[] = {
	{ "add",		donewprofile,		0, 3, "profile add <name> (<level> | <path> <perms>)" },
	{ "change",		dochgprofile,		0, 3, "profile change <name> (<level> | <path> <perms>)" },
	{ "delete",		dodelprofile,		0, 2, "profile delete <name>" },
	{ "fileext",		doprofileext,		0, 0, NULLCHAR },
	{ "list",		dolistprofile,		0, 2, "profile list <name>" },
	{ "passwd",		dopasswd,		0, 2, "profile passwd <username>" },
	{ "usermodifyable",	doprofileusermod,	0, 0, NULLCHAR },
	{ NULLCHAR,		NULL,			0, 0, NULLCHAR }
};



int
doprofile (int argc, char *argv[], void *p)
{
	return subcmd (ProTab, argc, argv, p);
}





static int
dopasswd (int argc, char *argv[], void *p OPTIONAL)
{
struct mbx m;

	m.privs = SYSOP_CMD;
	m.quickfile = (FILE *) -1;
	m.authenticated = 1;
	m.sid = 0;
	m.user = Curproc->output;
	m.mfile = NULLFILE;
	strcpy (m.name, "sysop");
	(void) dombpasswd (argc, argv, &m);
	return 0;
}



static int
doprofileusermod (int argc, char *argv[], void *p OPTIONAL)
{
	return setbool (&profileUsermod, "Allow users to modify their passwords in PBBS", argc, argv);
}




static int
doprofileext (int argc, char *argv[], void *p OPTIONAL)
{
char *cp;

	if (argc < 2)	{
		if (profileExt != NULLCHAR)
			tprintf ("%s\n", profileExt);
	} else	{
		free (profileExt);
		profileExt = NULLCHAR;
		cp = skipwhite (argv[1]);
		if (*cp)	{
			if (*cp == '.')
				cp++;
			if (*cp)
				profileExt = strdup (cp);
		}
	}
	return 0;
}



static char *
find_entry (FILE *fp, FILE *fpout, char *buf, int buflen, char *searchfor)
{
int foundit = 0;
char c;
char *cp = NULLCHAR;

	while (fgets (buf, buflen, fp) != NULLCHAR) {
		kwait (NULL);
		rip (buf);
		if (*buf && *buf != '#')	{
			cp = strpbrk (buf, " \t");
			if (cp != NULLCHAR)	{
				c = *cp;
				*cp++ = 0;
				if (!strcasecmp (searchfor, buf))	{
					foundit = 1;
					break;
				}
				*(--cp) = c;
			}
		}
		if (fpout != NULLFILE)
			fprintf (fpout, "%s\n", buf);
	}
	return ((foundit) ? cp : NULLCHAR);
}



static void
add_rest_of_file (FILE *fp, FILE *fpout, char *buf, int buflen)
{
	/* now add the rest of the file */
	while (fgets (buf, buflen, fp) != NULLCHAR) {
		kwait (NULL);
		fputs (buf, fpout);
	}
}



int
dombpasswd (int argc, char *argv[], void *p)
{
struct mbx *m;
char buf[MBXLINE], *cp = NULLCHAR;
char usrfilename[MBXLINE];
char tmpfilename[MBXLINE];
FILE *fp, *fpout;
int foundit = 0, changedit = 0;
char *searchfor;
char firstpass[60];

	m = (struct mbx *) p;
	if (argc > 1 && !(m->privs & SYSOP_CMD)) {
		/* only a sysop can change other users' passwords */
		tputs ("Sorry, but you do not have permission to change others' passwords.\n");
		tputs ("Usage: passwd\n");
		return 1;
	}

	if (m->privs & WAS_ANONY)	{
		/* anonymous users don't have defined passwords */
		tputs ("Sorry, but anonymous users are not allowed to save/change passwords.\n");
		return 1;
	}

	if (!m->authenticated)	{
		/* user has not already authenticated themself */
		tputs ("Sorry, but you have not been authenticated for this login. You must be connect via AX25.\nSorry, but you are not allowed to change your password at this time.\n");
		return 1;
	}
	
	if (!profileUsermod && !(m->privs & SYSOP_CMD))	{
		/* disabled feature - by sysop */
		tputs ("Sorry, but changing passwords is disabled by the sysop.\n");
		return 1;
	}

	if (argc > 1)
		searchfor = argv[1];
	else
		searchfor = m->name;

	sprintf (usrfilename, "%s%s%s", Userfile, (profileExt) ? "." : "",
		(profileExt) ? profileExt : "");
	if ((fp = fopen (usrfilename, READ_TEXT)) == NULLFILE)	{
		tputs ("Sorry, but there is a problem at this site. Can't change password!\n");
		return 1;
	}

	sprintf (tmpfilename, "%s.tmp", Userfile);
	if ((fpout  = fopen (tmpfilename, WRITE_TEXT)) == NULLFILE)	{
		tputs ("Sorry, but there is a problem at this site. Can't change password!\n");
		return 1;
	}

	cp = find_entry (fp, fpout, buf, MBXLINE, searchfor);
	if (cp != NULLCHAR)	{
		foundit = 1;
		cp = skipwhite (cp);	/* any leading white space */
		cp = skipnonwhite (cp);	/* skip the old password */
		/* cp now points to path/permission or security level */
		
		tprintf ("Enter new password:\n");

		m->line[0] = 0;
		if (m->quickfile != NULLFILE)	{	/* from command session */
			if (recvline (Curproc->input, (unsigned char *) m->line, MBXLINE) == 0)
				return 0;
		} else {
			if (mbxrecvline (m) == -1)
				return 0;
		}

		rip (m->line);
		strncpy (firstpass, m->line, 60);

		tprintf ("Enter new password again:\n");

		m->line[0] = 0;
		if (m->quickfile != NULLFILE)	{	/* from command session */
			if (recvline (Curproc->input, (unsigned char *) m->line, MBXLINE) == 0)
				return 0;
		} else {
			if (mbxrecvline (m) == -1)
				return 0;
		}

		rip (m->line);

		if (!strcmp (firstpass, m->line))	{
			fprintf (fpout, "%s %s %s\n", searchfor, firstpass, cp);
			changedit = 1;
			add_rest_of_file (fp, fpout, buf, MBXLINE);
		}

	}
	
	(void) fclose (fp);
	(void) fclose (fpout);

	if (changedit)	{
		unlink (usrfilename);
		(void) rename (tmpfilename, usrfilename);
		tcmdprintf ("Password changed for user '%s' by '%s'\n", searchfor, m->name);
		usercvt ();
		tputs ("Password changed successfully");
		if (argc > 1)
			tprintf (" for security profile '%s'", searchfor);
		tputc ('\n');
	} else 	{
		unlink (tmpfilename);
		if (foundit)
			tputs ("Sorry, but those two passwords are different. Password change aborted!\n");
		else
			tprintf ("Sorry, but user '%s' not found in '%s'\n", searchfor, usrfilename);
	}
	
	return 0;
}



static int
donewprofile (int argc, char *argv[], void *p OPTIONAL)
{
struct mbx m;

	m.privs = SYSOP_CMD;
	m.quickfile = (FILE *) -1;
	m.authenticated = 1;
	m.sid = 0;
	m.user = Curproc->output;
	m.mfile = NULLFILE;
	strcpy (m.name, "sysop");
	(void) dombnewprofile (argc, argv, &m);
	return 0;
}



static int
dochgprofile (int argc, char *argv[], void *p OPTIONAL)
{
struct mbx m;

	m.privs = SYSOP_CMD;
	m.quickfile = (FILE *) -1;
	m.authenticated = 1;
	m.sid = 0;
	m.user = Curproc->output;
	m.mfile = NULLFILE;
	strcpy (m.name, "sysop");
	(void) dombchgprofile (argc, argv, &m);
	return 0;
}




static int
dodelprofile (int argc, char *argv[], void *p OPTIONAL)
{
struct mbx m;

	m.privs = SYSOP_CMD;
	m.quickfile = (FILE *) -1;
	m.authenticated = 1;
	m.sid = 0;
	m.user = Curproc->output;
	m.mfile = NULLFILE;
	strcpy (m.name, "sysop");
	(void) dombdelprofile (argc, argv, &m);
	return 0;
}




static int
dolistprofile (int argc, char *argv[], void *p OPTIONAL)
{
struct mbx m;

	m.privs = SYSOP_CMD;
	m.quickfile = (FILE *) -1;
	m.authenticated = 1;
	m.sid = 0;
	m.user = Curproc->output;
	m.mfile = NULLFILE;
	strcpy (m.name, "sysop");
	(void) domblistprofile (argc, argv, &m);
	return 0;
}




/* profile subcommand table for PBBS */
static struct cmds MBProTab[] = {
	{ "add",		dombnewprofile,		0, 3, "profile add <name> (<level> | <path> <perms>)" },
	{ "change",		dombchgprofile,		0, 3, "profile change <name> (<level> | <path> <perms>)" },
	{ "delete",		dombdelprofile,		0, 2, "profile delete <name>" },
	{ "list",		domblistprofile,	0, 2, "profile list <name>" },
	{ NULLCHAR,		NULL,			0, 0, NULLCHAR }
};



int
dombprofile (int argc, char *argv[], void *p)
{
	return subcmd (MBProTab, argc, argv, p);
}





int
dombnewprofile (int argc, char *argv[], void *p)
{
struct mbx *m;
FILE *fp;
int level = 1;
char usrfilename[MBXLINE];
char buf[MBXLINE], *cp;

	m = (struct mbx *) p;
	if (!(m->privs & SYSOP_CMD)) {
		/* only a sysop can change other users' passwords */
		tputs ("Sorry, but you do not have permission to add a security profile!\n");
		return 1;
	}

	if (!m->authenticated)	{
		/* user has not already authenticated themself */
		tputs ("Sorry, but you have not been authenticated for this login. You must be connect via AX25.\nSorry, but you are not allowed to add a user profile at this time.\n");
		return 1;
	}
	
	/* first check to see if this profile already exists */
	sprintf (usrfilename, "%s%s%s", Userfile, (profileExt) ? "." : "",
		(profileExt) ? profileExt : "");
	if ((fp = fopen (usrfilename, READ_TEXT)) == NULLFILE)	{
		tprintf ("Cannot open '%s'!\n", usrfilename);
		return 1;
	}

	cp = find_entry (fp, NULLFILE, buf, MBXLINE, argv[1]);
	(void) fclose (fp);
	if (cp != NULLCHAR)	{
		tprintf ("Security profile for '%s' already exists! Add command ignored!\n", argv[1]);
		return 1;
	}
	

	/* since it doesn't exist, open to append it */
	if ((fp = fopen (usrfilename, APPEND_TEXT)) == NULLFILE)	{
		tprintf ("Cannot open '%s'!\n", usrfilename);
		return 1;
	}

	if (argc > 3)
		level = 0;

	fprintf (fp, "%s new %s%s %s\n", argv[1], (level) ? "#" : "",
		argv[2], (level) ? "" : argv[3]);
	(void) fclose (fp);

	(void) dombpasswd (2, argv, m);
	tprintf ("New security profile for '%s' added successfully\n", argv[1]);
	return 0;
}



int
dombchgprofile (int argc, char *argv[], void *p)
{
struct mbx *m;
FILE *fp, *fpout;
char buf[MBXLINE];
char usrfilename[MBXLINE];
char tmpfilename[MBXLINE];
int level = 1;
char *cp, *cp2;
int foundit = 0;

	m = (struct mbx *) p;
	if (!(m->privs & SYSOP_CMD)) {
		/* only a sysop can change other users' passwords */
		tputs ("Sorry, but you do not have permission to change a security profile!\n");
		return 1;
	}

	if (!m->authenticated)	{
		/* user has not already authenticated themself */
		tputs ("Sorry, but you have not been authenticated for this login. You must be connect via AX25.\nSorry, but you are not allowed to change a user profile at this time.\n");
		return 1;
	}
	
	sprintf (usrfilename, "%s%s%s", Userfile, (profileExt) ? "." : "",
		(profileExt) ? profileExt : "");
	if ((fp = fopen (usrfilename, READ_TEXT)) == NULLFILE)	{
		tprintf ("Cannot open '%s'!\n", usrfilename);
		return 1;
	}

	sprintf (tmpfilename, "%s.tmp", Userfile);
	if ((fpout  = fopen (tmpfilename, WRITE_TEXT)) == NULLFILE)	{
		tprintf ("Cannot create '%s'!\n", tmpfilename);
		return 1;
	}

	if (argc > 3)
		level = 0;

	cp = find_entry (fp, fpout, buf, MBXLINE, argv[1]);
	if (cp != NULLCHAR)	{
		foundit = 1;
		cp = skipwhite (cp);	/* any leading white space */
		/* cp now points to password field */
		cp2 = skipnonwhite (cp);
		if (cp2)
			*cp2 = 0;

		fprintf (fpout, "%s %s %s%s %s\n", argv[1], cp, (level) ? "#" : "",
			argv[2], (level) ? "" : argv[3]);
		add_rest_of_file (fp, fpout, buf, MBXLINE);
	}

	(void) fclose (fp);
	(void) fclose (fpout);

	if (foundit)	{
		unlink (usrfilename);
		(void) rename (tmpfilename, usrfilename);
		tprintf ("Security profile for '%s' changed successfully\n", argv[1]);
	} else	{
		unlink (tmpfilename);
		tprintf ("User '%s' not found in '%s'\n", argv[1], usrfilename);
	}
	return 0;
}


int
domblistprofile (int argc OPTIONAL, char *argv[], void *p)
{
struct mbx *m;
FILE *fp;
char buf[MBXLINE];
char usrfilename[MBXLINE];
char *cp;

	m = (struct mbx *) p;
	if (!(m->privs & SYSOP_CMD)) {
		/* only a sysop can change other users' passwords */
		tputs ("Sorry, but you do not have permission to list a security profile!\n");
		return 1;
	}

	if (!m->authenticated)	{
		/* user has not already authenticated themself */
		tputs ("Sorry, but you have not been authenticated for this login. You must be connect via AX25.\nSorry, but you are not allowed to list a user profile at this time.\n");
		return 1;
	}
	
	sprintf (usrfilename, "%s%s%s", Userfile, (profileExt) ? "." : "",
		(profileExt) ? profileExt : "");
	if ((fp = fopen (usrfilename, READ_TEXT)) == NULLFILE)	{
		tprintf ("Cannot open '%s'!\n", usrfilename);
		return 1;
	}

	cp = find_entry (fp, NULLFILE, buf, MBXLINE, argv[1]);
	(void) fclose (fp);
	if (cp != NULLCHAR)	{
		cp = skipwhite (cp);	/* any leading white space */
		cp = skipnonwhite (cp);
		/* cp now points to path/permission or security level */

		tprintf ("Security profile for '%s': %s\n", argv[1], cp);
	} else
		tprintf ("User '%s' not found in '%s'\n", argv[1], usrfilename);
	return 0;
}



int
dombdelprofile (int argc OPTIONAL, char *argv[], void *p)
{
struct mbx *m;
FILE *fp, *fpout;
char buf[MBXLINE];
char usrfilename[MBXLINE];
char tmpfilename[MBXLINE];
char *cp;

	m = (struct mbx *) p;
	if (!(m->privs & SYSOP_CMD)) {
		/* only a sysop can change other users' passwords */
		tputs ("Sorry, but you do not have permission to delete a security profile!\n");
		return 1;
	}

	if (!m->authenticated)	{
		/* user has not already authenticated themself */
		tputs ("Sorry, but you have not been authenticated for this login. You must be connect via AX25.\nSorry, but you are not allowed to delete a user profile at this time.\n");
		return 1;
	}
	
	sprintf (usrfilename, "%s%s%s", Userfile, (profileExt) ? "." : "",
		(profileExt) ? profileExt : "");
	if ((fp = fopen (usrfilename, READ_TEXT)) == NULLFILE)	{
		tprintf ("Cannot open '%s'!\n", usrfilename);
		return 1;
	}

	sprintf (tmpfilename, "%s.tmp", Userfile);
	if ((fpout  = fopen (tmpfilename, WRITE_TEXT)) == NULLFILE)	{
		tprintf ("Cannot create '%s'!\n", tmpfilename);
		return 1;
	}

	cp = find_entry (fp, fpout, buf, MBXLINE, argv[1]);

	if (cp != NULLCHAR)	{
		add_rest_of_file (fp, fpout, buf, MBXLINE);

		(void) fclose (fp);
		(void) fclose (fpout);
		unlink (usrfilename);
		(void) rename (tmpfilename, usrfilename);
		tprintf ("Security profile for '%s' deleted successfully\n", argv[1]);
	} else	{
		(void) fclose (fp);
		(void) fclose (fpout);
		unlink (tmpfilename);
		tprintf ("User '%s' not found in '%s'\n", argv[1], usrfilename);
	}
	return 0;
}



