/* Internet Finger server */
/* Mods by KO4KS */
#include "global.h"
#include "commands.h"
#include "files.h"
#include "mbuf.h"
#include "socket.h"
#include "session.h"
#include "mailbox.h"

#if !defined(_lint)
static char rcsid[] OPTIONAL = "$Id: fingerd.c,v 1.21 1997/07/31 00:44:20 root Exp $";
#endif

static int Sfinger = -1;    /* Prototype socket for service */
static void fingerd (int s,void *unused,void *p);
#if defined(CALLBOOK) || defined(CALLSERVER) || defined(SAMCALLB) || defined(QRZCALLB)
extern int Scallbook;
#endif

extern int Sconv;
extern int Sftp;	/* Prototype socket for service */
extern int BbsUsers, FtpUsers;
#if defined(SCREENSAVER) || defined(TUTOR)
extern int Tutored;
#endif

extern int cb_lookup (int, char *, FILE *);

#ifdef MBFWD
extern void forwardingSummary (void);
#endif
extern int donrroute (int argc,char *argv[],void *p);
extern int dotcpview (int argc,char *argv[],void *p);
extern int donrstatus (int argc,char *argv[],void *p);
extern int dombpast (int argc,char *argv[],void *p);
extern int domflist (int argc,char *argv[],void *p);
extern int dombmailstats (int argc,char *argv[],void *p);
extern int dombstatus (int argc,char *argv[],void *p);
#if !defined(UNIX) && !defined(TNOS_68K)
extern int domemstat (int argc,char *argv[],void *p);
#endif
#ifdef FOQ_CMDS
extern int dombfinger (int argc,char *argv[],void *p);
#endif

/* Start up finger service */
int
finstart(argc,argv,p)
int argc;
char *argv[];
void *p OPTIONAL;
{
	return (installserver (argc, argv, &Sfinger, "Finger listener", IPPORT_FINGER,
		INADDR_ANY, "fingerd", fingerd, 1024, NULL));
}


#define FLINE 128
#define FPT int (*)(int argc,char *argv[],void *p)

static struct finger_cmds {
	const char *name;		/* Name of command */
	const char *description;	/* Brief description of command */
	int (*func) (int argc,char *argv[],void *p);
				/* Function to execute command */
	int savestate;		/* Whether to save state and send null args */
	int arg;		/* numberic value to pass if non-savestate */
} fingercmds[] = {
#ifdef AX25
	{ "aheard",	"AX25 heard data",	doaxheard,	1,	0},
#endif
#ifdef ASY
	{ "asystat",	"Async port data",	doasystat,	1,	0},
#endif
#ifdef AX25
	{ "ax25",	"AX25 status",		doaxstat,	1,	0},
#endif
#ifdef MAILBOX
	{ "bbs",	"BBS users and status",	0,		0,	0},
#endif
#ifdef CONVERS
	{ "conf",	"Conference users",	0,		0,	0},
#endif
#ifdef STATS_MSG
	{ "daily_msg",	"Daily Message stats",	STATdaily_msg,	1,	0},
#endif
#ifdef STATS_TFC
	{ "daily_tfc",	"Daily Traffic stats",	STATdaily_tfc,	1,	0},
#endif
#ifdef STATS_USE
	{ "daily_use",	"Daily Usage stats",	STATdaily_use,	1,	0},
#endif
#ifdef MBFWD
	{ "fwd_queue",	"Forwarding Queue", (FPT)forwardingSummary,1,	0},
#endif
#ifdef STATS_MSG
	{ "general_msg","General Message stats",STATgeneral_msg,1,	0},
#endif
#ifdef STATS_TFC
	{ "general_tfc","General Traffic stats",STATgeneral_tfc,1,	0},
#endif
#ifdef STATS_USE
	{ "general_use","General Usage stats",	STATgeneral_use,1,	0},
#endif
	{ "iheard",	"IP heard data",	doipheard,	1,	0},
	{ "info",	"TNOS info",		doversion,	1,	0},
#ifdef AX25
	{ "jheard",	"AX25 heard data",	doaxheard,	1,	0},
#endif
#ifdef CONVERS
	{ "links",	"Conference Links", (FPT)ShowConfLinks,	0,	1},
#endif
#if defined(MAILFOR) && defined(AX25) && defined(MAILBOX)
	{ "mailfor",	"BBS mailfor data",	domflist,	1,	0},
#endif
#if !defined(UNIX) && !defined(TNOS_68K)
	{ "memstat",	"TNOS memory data",	domemstat,	1,	0},
#endif
#ifdef STATS_MSG
	{ "monthly_msg","Monthly Message stats",STATmonthly_msg,1,	0},
#endif
#ifdef STATS_TFC
	{ "monthly_tfc","Monthly Traffic stats",STATmonthly_tfc,1,	0},
#endif
#ifdef STATS_USE
	{ "monthly_use","Monthly Usage stats",	STATmonthly_use,1,	0},
#endif
#ifdef MAILBOX
	{ "mpast",	"BBS past users",	dombpast,	1,	0},
	{ "mstat",	"BBS mailbox stats",	dombmailstats,	1,	0},
#endif
#ifdef NETROM
	{ "netrom",	"Netrom status",	donrstatus,	1,	0},
	{ "nodes",	"Netrom nodes",		donrroute,	1,	0},
#endif
#ifdef GATECMDS
	{ "ports",	"Available ports",	dombports,	1,	0},
#endif
#ifdef RIP
	{ "ripstat",	"RIP status data",	doripstat,	1,	0},
#endif
	{ "socket",	"TNOS active sockets",	dosock,		1,	0},
#if defined(MAILBOX) || defined (CONVERS)
	{ "stat",	"BBS/Conference status",0,		0,	0},
#endif
	{ "tcpview",	"TCP view of bytes",	dotcpview,	1,	0},
#ifdef MAILBOX
	{ "users",	"BBS users online",	dombstatus,	1,	0},
#endif
	{ "uptime",	"System Uptime",	douptime,	1,	0},
	{ "version",	"TNOS version info",	doversion,	1,	0},
#ifdef STATS_MSG
	{ "weekly_msg",	"Weekly Message stats",	STATweekly_msg,	1,	0},
#endif
#ifdef STATS_TFC
	{ "weekly_tfc",	"Weekly Traffic stats",	STATweekly_tfc,	1,	0},
#endif
#ifdef STATS_USE
	{ "weekly_use",	"Weekly Usage stats",	STATweekly_use,	1,	0},
#endif
#ifdef STATS_MSG
	{ "yearly_msg",	"Yearly Message stats",	STATyearly_msg,1,	0},
#endif
#ifdef STATS_TFC
	{ "yearly_tfc",	"Yearly Traffic stats",	STATyearly_tfc,1,	0},
#endif
#ifdef STATS_USE
	{ "yearly_use",	"Yearly Usage stats",	STATyearly_use,1,	0},
#endif
	{ NULLCHAR,	"",			NULL,		0,	0}
};


static void
fingerd(s,unused,p)
int s;
void *unused OPTIONAL;
void *p OPTIONAL;
{
char user[80], *uptr;
int ulen,found;
FILE *fp;
char *file,*cp;
char line[FLINE+1];
int dotheconf = 0, dothebbs = 0;
int outsave;
#ifdef USERLOG
char *newargv[2];
#endif
struct finger_cmds *cmd;

	(void) sockmode(s,SOCK_ASCII);
	(void) sockowner(s,Curproc);
	log(s,"open Finger");
	if (recvline(s, (unsigned char *) user,80) == -1)
		return;
	rip(user);
	uptr = skipwhite(user);
	ulen = (int) strlen(uptr);
	if (ulen)	{
#ifdef MSDOS
    		if (!strcmp (uptr, "con") || !strcmp (uptr, "aux"))	{
    			usprintf (s, "Can't finger '%s'... DOS Reserved Device Name\n", uptr);
			goto done;
		}
#endif
#ifdef CONVERS
    		if (!stricmp (uptr, "conf") || !stricmp (uptr, "stat"))
    			dotheconf = 1;
#endif
	    	if (!stricmp (uptr, "bbs") || !stricmp (uptr, "stat"))
    			dothebbs = 1;
	}

#ifdef FOQ_CMDS
	/* handle a user%host request */
	if ((cp = strrchr(uptr, '%')) != NULLCHAR)	{
		struct mbx m;
		char *myargv[2];
		int old;
		*cp = '@';
		myargv[1] = uptr;
		strcpy(m.name, "fingerd");
		m.user = s;
		m.privs = TELNET_CMD + AMPR_CMD + NO_ESCAPE + SYS_CHAT + ALL_AREAS;
		old = Curproc->output;
		Curproc->output = s;
		(void) dombfinger(2, myargv, &m);
		Curproc->output = old;
		goto done;
	}
#endif

	/* handle the pseudo users */
	for (cmd = fingercmds; cmd->name; cmd++)	{
		if (ulen && !strcmp(uptr, cmd->name))
			break;
	}
	if (cmd->name && cmd->func)	{
		usprintf(s, "%s at %s\n\n", cmd->description, Hostname);
		if (cmd->savestate)	{
			outsave = Curproc->output;
			Curproc->output = s;
			(void) (*cmd->func)(1,NULLCHARP,NULL);
			Curproc->output = outsave;
		} else
			(void) (*cmd->func)(s, (char **)cmd->arg, (void *)0);
	} else if (dotheconf || dothebbs)	{
		usprintf (s, "Current Status at %s\n\n", Hostname);
    		if (dothebbs)	{
	    		if (!BbsUsers)
				usputs (s, "No users currently on the BBS\n");
			else if (Listusers != NULL)	{
		    		usputs (s, "Bulletin Board ");
				(*Listusers)(s);
			}
			if (dothebbs
#ifdef CONVERS
				&& dotheconf
#endif
				)	{

				if (Sftp == -1)
					usprintf (s, "\nFTP Server not started\n");
				else
					usprintf (s, "\nThere are %d in FTP Sessions\n", FtpUsers);
#ifdef TUTOR
				usprintf (s, "There are %d in Information Server Sessions\n", Tutored);
#endif
				usputs (s, "\n");
			}
			if (dothebbs)	{
				outsave = Curproc->output;
				Curproc->output = s;
				(void) dombmailstats(0,NULLCHARP,NULL);
				Curproc->output = outsave;
			}
		}
#ifdef CONVERS
		if (dotheconf)	{
			if(Sconv == -1)
				usputs(s,"Conference not started\n");
			else	{
				usputs (s, "Conference Bridge Users:\n");
				(void) ShowConfUsers(s, NULLCHAR);
			}
		}
#endif
    	
	} else {
		if(ulen == 0){
			char buffer[128];
#ifdef MSDOS
			sprintf (buffer, "%s/*.", FingerDir);
#else
			sprintf (buffer, "%s/*", FingerDir);
#endif
			fp = dir(buffer,-1);
			if(fp == NULLFILE)
				usprintf(s,"No finger information available\n");
			else
				usprintf(s,"Known users on this system:\n");
		} else {
#ifdef SAMCALLB
			cb_lookup (s, uptr, (FILE *) 0);
#endif
#ifdef USERLOG
			outsave = Curproc->output;
			Curproc->output = s;
			newargv[1] = uptr;
			(void) dombuserinfo(0,newargv,NULL);
			Curproc->output = outsave;
#endif
			file = pathname(FingerDir,uptr);
			cp = pathname(FingerDir,"");
			/* Check for attempted security violation (e.g., somebody
			 * might be trying to finger "../ftpusers"!) */
			if(strncmp(file,cp,strlen(cp)) != 0){
				fp = NULLFILE;
				usprintf(s,"Invalid user name %s\n",uptr);
			} else if((fp = fopen(file,READ_TEXT)) == NULLFILE)	{
				/* Now search the finger database file for this user - WG7J */
				found = 0;
				if((fp = fopen(Fdbase,READ_TEXT)) != NULLFILE) {
					while(fgets(line,FLINE,fp) != NULLCHAR)
						if(!strnicmp(line,uptr,(unsigned)ulen)) {
							usprintf(s,"%s", line);
							while(fgets(line,FLINE,fp) != NULLCHAR)	{
								if (line[1] && *line != ' ' && *line != '\t')
									break;
								else
									usprintf (s, line);
							}
							found = 1;
							break;
						}
					(void) fclose(fp);
					fp = NULLFILE;
				}
				if(!found)
					usprintf(s,"No user info for %s\n",uptr);
#if defined(SAMCALLB) || defined(QRZCALLB)
				if (Scallbook != -1)	{
		                        usprintf(s,"\nThe callbook reports:");
					(void) cb_lookup (s, uptr, (FILE *) 0);
        		        }
#endif
			}
			free(cp);
			free(file);
		}
		if(fp != NULLFILE){
			(void) sendfile(fp,s,ASCII_TYPE,0);
			(void) fclose(fp);
		}
	}
	if(!ulen)	{
		usputs (s, "\n*** Additional information available by fingering:\n");
		for (cmd = fingercmds; cmd->name; cmd++)
			usprintf (s, "     %-14.14s - %s\n", cmd->name, cmd->description);

		if(Listusers != NULL)	{
    			usputs (s, "\n");
			(*Listusers)(s);
		}
	}
#if defined(FOQ_CMDS) || defined(MSDOS)
done:
#endif
	close_s(s);
	log(s,"close Finger");
}

int
fin0(argc,argv,p)
int argc OPTIONAL;
char *argv[] OPTIONAL;
void *p OPTIONAL;
{
	return (deleteserver (&Sfinger));
}


