/
teeny/db/
teeny/dbm/
teeny/doc/
teeny/includes/
#include	<sys/types.h>
#include	<ctype.h>
#include	<sys/time.h>
#include	<strings.h>

#include	"teeny.h"
#include	"io.h"

/*
Copyright(C) 1990, Andrew Molitor, All Rights Reserved.
This software may be freely used, modified, and redistributed,
as long as this copyright message is left intact, and this
software is not used to develop any commercial product, or used
in any product that is provided on a pay-for-use basis.

No warranties whatsoever. This is not guaranteed to compile, nor,
in the event that it does compile to binaries, are these binaries
guaranteed to perform any function whatsoever.
*/

/*
#define IODEBUG
*/

/*
	The messages we write out when a create/connect attempt fails.
*/

#define BAD_CONNECT "Wrong password, or no such player.\n"
#define BAD_CREATE "A player with that name already exists.\n"

/* The WHO list. Surprise. */
Iob	*wholist = (Iob *)0;

/* Time last time timers() was called. */

struct timeval last;

/* Last time we did a dump */
int lastdump;

init_timers()
{
	(void)gettimeofday(&last,(struct timezone *)0);
	lastdump = last.tv_sec;
}

/*
	This checks the current time and resets quotas if the current timeslice
has elapsed, and does a dump if the current dump interval has elapsed.

*/

timers()
{
	struct timeval now;
	int delta;
	Iob *curr;

	(void)gettimeofday(&now,(struct timezone *)0);

	/* How many tenths of seconds have elapsed since last time */

	delta = (now.tv_sec - last.tv_sec) * 10
			+ (now.tv_usec - last.tv_usec) / 100000;

	if(delta >= TIME_SLICE){
		/* Update all the quotas */

		curr = wholist;
		if(curr != (Iob *)0){
			do{
				curr->quota = SLICE_QUOTA;
				curr = curr->whofwd;
			} while(curr != wholist);
		}
		last.tv_sec = now.tv_sec; last.tv_usec = now.tv_usec;
	}

	if(now.tv_sec - lastdump > DUMP_INTERVAL){
		lastdump = now.tv_sec;

		/* Dump the DB */

		dump_db();
	}
}


/*
	The network code calls this with Iob's with pending goo to process.
Process it.

*/

dispatch(bp)
Iob	*bp;

{
	char	*buff,*cmd,*p;
	int	count;
	int	player;
	int	fullbuff;

	bp->lastcmd = last.tv_sec;

	if(bp->quota < 0){
		bp->inputcnt = 0;
		if(bp->typ == INPUT_NEWCONN){
			iobflush(bp);
			iobdrop(bp);
		}
		return(0);
	}

	buff = bp->inputbuf;
	count = bp->inputcnt;

	/* Slide along, chopping it up into commands. */

	fullbuff = (count == (MUDBUFSIZ-1));  /* One for terminating \0 */
	while(1){
		cmd = buff;
		while(*buff != '\n' && count > 0 && *buff != '\r'){
			buff++; count--;
		}
		if(count <= 0 && !fullbuff)
			break;

		(bp->quota)--;
		if(bp->quota < 0){  /* Fuck this guy */
			(bp->blown)++;
			buff = cmd; /* Fake an empty buffer */
			break;
		}
		fullbuff = 0;
		*buff++ = '\0'; count--;

		while(isspace(*cmd) && *cmd) cmd++;
		if(*cmd == '\0')
			continue;

		/* Check special commands. */

		if(strcmp(cmd,"WHO") == 0){
			do_wholist(bp);
			continue;
		} else if(strcmp(cmd,"QUIT") == 0){
			iobput(bp,"Bye!\n");
			iobflush(bp);
			iobdrop(bp);
			if(bp->typ != INPUT_NEWCONN){
				disconnect_player(bp->player);
			}
			continue;
		}

		switch(bp->typ){
		case INPUT_NEWCONN:

			/* We grok two commands, create and connect. */

			for(p = cmd ; !isspace(*p) && *p ; p++);
			if(*p == '\0'){
				greet(bp);
				break;
			}
			*p++ = '\0';

			if(strcmp(cmd,"connect") == 0){
				player = connect_player(p);
				if(player == -1){
					iobput(bp,BAD_CONNECT);
				} else {
					bp->typ = INPUT_PLAY;
					bp->player = player;
					spit_file(player,"motd.txt");
					do_look(player,(char *)0);
					newwho(bp);
				}
			} else if(strcmp(cmd,"create") == 0){
				player = create_player(p);
				if(player == -1){
					iobput(bp,BAD_CREATE);
				} else {
					bp->typ = INPUT_PLAY;
					bp->player = player;
					do_look(player,(char *)0);
					newwho(bp);
				}
			} else {
				/* Re-greet this idiot.  */
				greet(bp);
			}
			break;
		case INPUT_PLAY:
			handle_cmd(bp->player,cmd);
			break;
		}
	}
	/* OK We banged into the end of the buffer. */


	if(cmd != buff){ /* Is there anything left in the buffer? */
		bp->inputcnt = buff - cmd;
		bcopy(cmd,bp->inputbuf,bp->inputcnt);
#ifdef IODEBUG
		printf("Read buffer ends with partial line of %d chars.\n"
			,bp->inputcnt);
#endif
	} else {
		bp->inputcnt = 0;
#ifdef IODEBUG
		printf("Read buffer ended cleanly.\n");
#endif
	}

	return(0); /* We always succeed, being Way Studly. */
}

newwho(bp)
Iob *bp;
{
	if(wholist == (Iob *)0){
		wholist = bp->whofwd = bp->whoback = bp;
	} else {
		bp->whoback = wholist;
		bp->whofwd = wholist->whofwd;
		(wholist->whofwd)->whoback = bp;
		wholist->whofwd = bp;
	}
}

dropwho(bp)
Iob *bp;
{
#ifdef IODEBUG
	printf("Dropping Iob for fd %d from the WHO list\n",bp->fd);
#endif
	if(bp->whofwd == bp){
		wholist = (Iob *)0;
	} else {
		if(wholist == bp){
			wholist = bp->whoback;
		}
		(bp->whoback)->whofwd = bp->whofwd;
		(bp->whofwd)->whoback = bp->whoback;
	}
}

greet(bp)
Iob *bp;
{
	/* Yeah. I know I should open a file. Tough, I'm stingy w/my fds */

	iobput(bp,"Welcome to TeenyMUD alpha-test.\n\n");
	iobput(bp,"Use create <name> <password> or connect <name> <password>\n");
	iobput(bp,"If you find a bug, don't whine. Report it well and without\n");
	iobput(bp,"whining or I *will* hunt you down and break your fingers.\n\n");
}

/*
	Matches against the list of active players.

	returns -1 if no match, -2 if ambiguous, or the object number.

	This lives here, 'cause it needs to screw around with the network's
notion of the who list.

*/

int match_who(name)
char *name;

{
	Iob *curr;
	char *player_name,*p;
	int matched;

	matched = -1;

	curr = wholist;

	do {
		if(get_str_elt(curr->player,NAME,&player_name) == -1){
			warning("match_who","bad name reference on WHO list");
			return(-1);
		}
		if(player_name == (char *)0){
			warning("match_who","active player with NULL name");
			curr=curr->whofwd;
			continue;
		}
		for(p = name; DOWNCASE(*p) == DOWNCASE(*player_name) && *p && !isspace(*player_name) && *player_name;p++)
			player_name++;
		if(isspace(*player_name)){
			return(curr->player);
		}
		curr = curr->whofwd;;
	} while(curr != wholist);

	return(matched);
}

/*
	Display the WHO list to a bp.
*/
/* 25 spaces */

char spaces[] = "                         ";

do_wholist(bp)
Iob *bp;
{
	Iob *who;
	char *whonm,*p,ch;
	char work[16];
	int len;

	iobput(bp,"Players             Idle     Connected\n");
	if((who = wholist) == (Iob *)0)
		return;

	do {
		if(get_str_elt(who->player,NAME,&whonm)	!= -1){
			for(p = whonm, len = 0;!isspace(*p) && *p;len++)
				p++;
			ch = *p;
			*p = '\0';
			iobput(bp,whonm);
			*p = ch;
			if(len > 24)
				len = 24;
			p = ty_itoa(work,(int)(last.tv_sec - who->lastcmd));
			*p = '\0';
			iobput(bp,spaces+len+(p - work)+1);
			iobput(bp,work);


			p = ty_itoa(work,(int)(last.tv_sec - who->connect));
			*p++ = '\n';*p = '\0';
			iobput(bp,spaces+(p - work)+10);
			iobput(bp,work);
		}
		who = who->whoback;
	} while(who != wholist);
}

/*

	Writes a console WHO list out. To stdout.

*/
#define CONS_WHO "Name                Idle       Connected    Blown Quotas\n"

console_wholist()
{
	Iob *who;
	char *whonm,*p;
	char work[16];
	int len,len2;

	write(1,CONS_WHO,sizeof(CONS_WHO)-1);
	if((who = wholist) == (Iob *)0)
		return;

	do {
		/* Player number and name. */

		work[0] = '#';
		p = ty_itoa(work+1,who->player);
		*p++ = ' ';
		len2 = p-work;
		write(1,work,len2);
		if(get_str_elt(who->player,NAME,&whonm)	!= -1){
			for(p = whonm, len = 0;!isspace(*p) && *p;len++)
				p++;
			write(1,whonm,len);
		} else {
			write(1,"<bad name>",10);
			len = 10;
		}
		len += len2;

		/* Idle time */

		p = ty_itoa(work,(int)(last.tv_sec - who->lastcmd));
		len = len + (p-work) + 1;
		if(len > 24) len = 24;
		write(1,spaces+len,25-len);
		write(1,work,p-work);

		/* Connect time */

		p = ty_itoa(work,(int)(last.tv_sec - who->connect));
		len = (p-work) + 9;
		write(1,spaces+len,25-len);
		write(1,work,p-work);

		/* Number of quotas blown. */

		p = ty_itoa(work,who->blown);
		len = (p-work) + 9;
		*p++ = '\n';
		write(1,spaces+len,25-len);
		write(1,work,p-work);

		who = who->whoback;
	} while(who != wholist);
}