/****************************************************************/
/**                                                            **/
/**   Direct Communication Chat and Conferencing System        **/
/**   Created May 1993 out of complete boredom.                **/
/**   (c) 1993 Takoyaki Software Ltd.                          **/
/**                                                            **/
/**   Will only run in conjunction with Desqview/X.            **/
/**                                                            **/
/**   File:    CHATDATA.C                                      **/
/**   Purpose: Data used by CHATHOST.EXE                       **/
/**   Usage:   Should be linked with chathost.c                **/
/**                                                            **/
/****************************************************************/

#include	<stdio.h>
#include	<stdlib.h>
#include	<stdarg.h>
#include	"chatvars.h"

extern int sysmsgflag;
extern char indent;


struct staticuser *staticlist=NULL;
struct emote *emotes=NULL;
struct category *categorylist=NULL;
struct mail *maillist=NULL;
struct user *userlist=NULL;


/**** flag list definitions ****/


struct flagdef userflagdef[] =
	{
	"SYSOP",   U_SYSOP,   F_SYSOP,
	"MODEM",   U_MODEM,   F_SYSOP,
	"FEMALE",  U_SEX,     0,

	NULL, 0,0
	};

struct flagdef emoteflagdef[] =
	{
	"PRIVATE", E_PRIVATE, 0,

	NULL, 0,0
	};


/**** structure definitions ****/

struct itemdef userdef[] =
	{
		"USERNAME", T_WORD,   offsetof(struct staticuser,username),    0,           F_UNIQUE|F_SYSOP,
		"PASSWORD", T_WORD,   offsetof(struct staticuser,password),    0,           F_INVIS,
		"DESC",     T_STRING, offsetof(struct staticuser,description), 0,           0,
		"LOGINS",   T_UINT,   offsetof(struct staticuser,logins),      0,           F_SYSOP,
		"MAIL",     T_ULONG,  offsetof(struct staticuser,mail),        0,           F_SYSOP,
		"TW",       T_UINT,   offsetof(struct staticuser,termwidth),   0,           0,
		"TH",       T_UINT,   offsetof(struct staticuser,termheight),  0,           0,
		"FLAGS",    T_FLAGS,  offsetof(struct staticuser,flags),       userflagdef, 0,

		NULL,0,0,0,0
	};

struct itemdef onlineuserdef[] =
	{
		"USERNAME",     T_WORD,   offsetof(struct user,username),    0,           F_UNIQUE|F_SYSOP,
		"LASTREADMAIL", T_ULONG,  offsetof(struct user,mailid),      0,           F_SYSOP,

		NULL,0,0,0,0
	};

struct itemdef emotedef[] =
	{
		"CMD",      T_WORD,   offsetof(struct emote,cmd),         0,            F_UNIQUE,
		"EM",       T_STRING, offsetof(struct emote,emote),       0,            0,
		"USER",     T_WORD,   offsetof(struct emote,user),        0,            F_SYSOP,
		"USE",      T_ULONG,  offsetof(struct emote,usage),       0,            F_SYSOP,
		"CAT",      T_WORD,   offsetof(struct emote,category),    0,            0,
		"FLAGS",    T_FLAGS,  offsetof(struct emote,flags),       emoteflagdef, 0,

		NULL, 0, 0, 0, 0
	};


struct flagdef mailflagdef[] =
	{
	"UNREAD", M_UNREAD, F_SYSOP,
	"UNSENT", M_UNSENT, F_SYSOP,
	"MARKED", M_MARKED, 0,
	"EXTERNAL", M_EXTERNAL, F_SYSOP,

	NULL, 0, 0
	};


struct itemdef maildef[] =
	{
		"ID",       T_ULONG,  offsetof(struct mail,id),           0,            F_UNIQUE|F_SYSOP,
		"TO",       T_WORD,   offsetof(struct mail,whoto),        0,            F_SYSOP,
		"FROM",     T_WORD,   offsetof(struct mail,whofrom),      0,            F_SYSOP,
		"NEXT",     T_ULONG,  offsetof(struct mail,nextmail),     0,            F_SYSOP,
		"PREV",     T_ULONG,  offsetof(struct mail,prevmail),     0,            F_SYSOP,
		"SUBJ",     T_STRING, offsetof(struct mail,subject),      0,            0,
		"BODY",     T_STRING, offsetof(struct mail,body),         0,            0,
		"TIME",     T_ULONG,  offsetof(struct mail,time),         0,            0,
		"NUM",      T_ULONG,  offsetof(struct mail,num),          0,            F_SYSOP,
		"FLAGS",    T_FLAGS,  offsetof(struct mail,flags),        mailflagdef,  0,

		NULL, 0, 0, 0, 0
	};

struct itemdef categorydef[] =
	{
		"NAME",  T_WORD, offsetof(struct category,name), 0, F_UNIQUE,
		NULL, 0, 0, 0, 0
	};


struct items itemlist[] =
	{
		"EMOTE",    emotedef,    (struct item **)&emotes,      F_PRIVATE,  sizeof(struct emote),      offsetof(struct emote,user),          IT_EMOTE,
		"USER",     userdef,     (struct item **)&staticlist,  F_PRIVATE,  sizeof(struct staticuser), offsetof(struct staticuser,username), IT_USER,
		"CATEGORY", categorydef, (struct item **)&categorylist,F_SYSOP,    sizeof(struct category),   0,                                    IT_CATEGORY,
		"MAIL",     maildef,     (struct item **)&maillist,    F_PRIVATE,  sizeof(struct mail),       offsetof(struct mail,whofrom),        IT_MAIL,
		"USER",     onlineuserdef, (struct item **)&userlist,  F_SYSOP|F_NOSAVE, sizeof(struct user), 0,                                    IT_ONLINEUSER,
		NULL, NULL, NULL, 0, 0, 0, 0
	};

/******************************************************************/
/************ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿***************/
/**          ³ Code to access the above structures ³             **/
/************ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ***************/
/******************************************************************/

/*----------------------------------------------------------------*/
/* Get a structure type ptr by item type's name                   */

struct items *gettypedefbyname(char *s)
	{
	struct items *i=itemlist;

	while (i->name)
		{
		if (strcmpl(i->name,s)==0) return i;
		i++;
		}

	return NULL;
	}

/*----------------------------------------------------------------*/
/* Get a structure type ptr by item type's number                 */

struct items *gettypedef(int t)
	{
	struct items *i=itemlist;

	while (i->name)
		{
		if (i->type == t) return i;
		i++;
		}

	return NULL;
	}

/*----------------------------------------------------------------*/
/* Get list header ptr for specified type (IT_ type)              */

struct item **getheader(int t)
	{
	struct items *i=itemlist;

	while (i->name != NULL)
		{
		if (i->type == t) return i->header;
		i++;
		}

	return NULL;
	}

/*----------------------------------------------------------------*/
/* Find an item of a specified type with a specified name         */

struct item *finditem(char *t,char *s)
	{
	struct items *i;
	struct item *n;

	if (!(i = gettypedefbyname(t))) return NULL;

	n = *i->header;

	while (n)
		{
		if (strcmpl(n->name,s)==0) return n;
		n = n->next;
		}

	return NULL;
	}

/*----------------------------------------------------------------*/
/* Find an item with the specified name                           */
/* beginning from the item after the one specifed                 */

struct item *finditemnext(struct item *n)
	{

	char *s=n->name;

	if (!n) return;

	while (n=n->next)
		{
		if (strcmpl(n->name,s)==0) return n;
		}

	return NULL;
	}


/**************************************************************/
/* this finds the record definition for the named record type */

struct itemdef *findrecordtype(struct itemdef *i,char *s)
	{
	while (i->name)
		{
		if (strcmpl(i->name,s)==0) return i;
		i++;
		}

	return NULL;
	}

/**************************************************************/
/* this finds the flag definition for the named flag          */

struct flagdef *findflagdef(struct flagdef *fd,char *s)
	{
	while (fd->name)
		{
		if (strcmpl(fd->name,s)==0) return fd;
		fd++;
		}

	return NULL;
	}

/*****************************************************************/
/* this sets the record type specified to the data in the string */

setrecord(struct item *i,struct itemdef *d, char *s)
	{
	char *p;
	struct flagdef *fd;

	switch(d->datatype)
		{
		case T_STRING:
			if (geto_sptr(i,d->offset)) free(geto_sptr(i,d->offset));
			geto_sptr(i,d->offset) = strdup(s);
			break;

		case T_WORD:
			if (geto_sptr(i,d->offset)) free(geto_sptr(i,d->offset));
			if ((p = strchr(s,' '))) *p = '\0';
			geto_sptr(i,d->offset) = strdup(s);
			break;

		case T_INT:
			geto_int(i,d->offset) = (int)strtol(s,NULL,0);
			break;

		case T_UINT:
			geto_uint(i,d->offset) = (unsigned int)strtol(s,NULL,0);
			break;

		case T_LONG:
			geto_long(i,d->offset) = (long)strtol(s,NULL,0);
			break;

		case T_ULONG:
			geto_ulong(i,d->offset) = (unsigned long)strtol(s,NULL,0);
			break;

		case T_FLAGS:
			if ((fd = findflagdef(d->flagdefs,s)))
				geto_ulong(i,d->offset) |= fd->mask;
			else printf("Unknown flag [%s].\n",s);
			break;

		default:
			break;
		}
/*
	printf("[%s] = [%s]\n",d->name,s);
*/
	}


/*****************************************************************/
/* This displays an item to the user                             */

showitem(char *mailbox,struct item *i)
	{
	struct items *it;
	struct itemdef *id;
	char *p;
	struct flagdef *fd;
	char tempbuf[512];

	if (!(it = gettypedef(i->type))) return;

	id = it->itemdef;
	newsection();
	sysmsg(mailbox,"Item: %s [%s]",i->name,it->name);

	while (id->name)
		{
		indentmsg(13);
		switch(id->datatype)
			{
			case T_STRING:
				if (geto_sptr(i,id->offset)) 
					{
					sysmsg(mailbox,"%-10s = %s",id->name,geto_sptr(i,id->offset));
					}
				break;

			case T_WORD:
				if (geto_sptr(i,id->offset)) 
					{
					sysmsg(mailbox,"%-10s = %s",id->name,geto_sptr(i,id->offset));
					}
				break;

			case T_INT:
				sysmsg(mailbox,"%-10s = %d",id->name,geto_int(i,id->offset));
				break;

			case T_UINT:
				sysmsg(mailbox,"%-10s = %u",id->name,geto_int(i,id->offset));
				break;

			case T_LONG:
				sysmsg(mailbox,"%-10s = %D",id->name,geto_long(i,id->offset));
				break;

			case T_ULONG:
				sysmsg(mailbox,"%-10s = %U",id->name,geto_ulong(i,id->offset));
				break;

			case T_FLAGS:
				if (fd = id->flagdefs)
					{
					tempbuf[0] = '\0';
					while (fd->name)
						{
						sprintf(tempbuf+strlen(tempbuf),"%s%s ",(geto_ulong(i,id->offset) & fd->mask)?"":"!",fd->name);
						fd++;
						}
					sysmsg(mailbox,"%-10s = %s",id->name,tempbuf);
					}
				break;

			default:
				sysmsg(mailbox,"Unknown record type %s->%s.",it->name,id->name);
				break;
			}
		id++;
		}
	}

