/* codelib.c - Module for loading offline softcode */
/* $Id: codelib.c,v 1.5 2002/08/20 17:30:33 dpassmor Exp $ */

#include "../../api.h"

#define MOD_CODELIB_CREATE	1

CF_HAND(cf_hash)
{
	char *key, *value, *p, *tokst;

	key = strtok_r(str, " \t=,", &tokst);
	value = strtok_r(NULL, " \t=,", &tokst);
	if (value) {
		if (((HASHTAB *)vp)->flags & HT_KEYREF) {
			/* hashadd won't copy it, so we do that here */
			p = key;
			key = XSTRDUP(p, "cf_hash");
		}
		p = value;
		value = XSTRDUP(p, "cf_hash");
		
		return hashadd(key, (int *)value, (HASHTAB *) vp, 0);
	} else {
		cf_log_syntax(player, cmd, "No value specified for key %s",
			      key);
		return -1;
	}
}

/* Conf table */

struct mod_codelib_confstorage {
	HASHTAB libraries;
	char *pathname;
} mod_codelib_config;

MODHASHES mod_codelib_hashtable[] = {
{ "libraries",	&mod_codelib_config.libraries,	5,	8},
{ NULL,		NULL,				0,	0}};

CONF mod_codelib_conftable[] = {
{(char *)"codelib",		cf_hash,	CA_GOD,	CA_GOD,	(int *)&mod_codelib_config.libraries,	(long)"Codelib library"},
{(char *)"codelib_path",	cf_string,	CA_GOD,	CA_GOD,	(int *)&mod_codelib_config.pathname,	MBUF_SIZE},
{ NULL,			NULL,		0,	0,		NULL,					0}};


void mod_codelib_upload_file(char *file, dbref object, dbref player) {
	FILE *f;
	char *attrtxt, *attrnam, *buf, *nam, *s, *p, *q, *tokst;
	int anum, type;
	dbref *np;
	FLAGENT *fp;
	POWERENT *pp;
	
	nam = alloc_mbuf("mod_codelib.upload_file.nam");
	buf = alloc_mbuf("mod_codelib.upload_file.buf");
	p = attrtxt = alloc_lbuf("mod_codelib.upload_file.attrtxt");
	attrnam = alloc_sbuf("mod_codelib.upload_file.attrnam");

	/* Do not allow code uploads to GOD */
	
	if (object == GOD) {
		notify(player, "Permission denied.");
		return;
	}

	/* Prepend the pathname and open the file */

	snprintf(nam, MBUF_SIZE, "%s/%s", mod_codelib_config.pathname,
		file);

 	if ((f = fopen(nam, "r")) == NULL) {
		STARTLOG(LOG_ALWAYS, "MOD", "CODELIB")
			log_printf("%s could not be opened for reading", s);
		ENDLOG
		if (player != NOTHING)
			notify(player, tprintf("%s could not be opened for reading.", s));
		return;
	}

	/* Preserve the object name */
	
	strncpy(nam, Name(object), MBUF_SIZE);

	/* Clear the old attributes from the object */

	atr_free(object);

	/* Set the name of the object */

	s_Name(object, nam);

	/* Preserve the type of the object */
	
	type = Typeof(object);
	
	/* Clear the object's flags */
	
	s_Flags(object, 0);
	s_Flags2(object, 0);
	s_Flags3(object, 0);

	/* Clear the object's powers */
	
	s_Powers(object, 0);
	s_Powers2(object, 0);
	
	/* Set the object's type */
	
	s_Flags(object, type);
	
	/* Add the CODELIB attribute containing the filename */

	strcpy(attrnam, "CODELIB");
	anum = mkattr(attrnam);
	atr_add(object, anum, file, player, AF_GOD);

	/* Add an Nref for this object */

	snprintf(nam, MBUF_SIZE, "_%s", file);
	np = (int *) hashfind(nam, &mudstate.nref_htab);
	if (np) {
		XFREE(np, "nref");
		np = (int *) XMALLOC(sizeof(int), "nref");
		*np = object;
		hashrepl(nam, np, &mudstate.nref_htab);
	} else {
		np = (int *) XMALLOC(sizeof(int), "nref");
		*np = object;
		hashadd(nam, np, &mudstate.nref_htab, 0);
	}

	while (fgets(buf, MBUF_SIZE, f) != NULL) {
		s = buf;
		
		/* Skip over comments and blank lines*/
		
		if ((*buf == '#') || (*buf == '\n') || (*buf == '\0'))
			continue;
		
		/* If we see 'flags', set flags on the object */
		
		if ((*buf == 'f') || (*buf == 'F')) {
			/* Cut through to the first space, tab, or NULL */
			while ((*s != ' ') && (*s != '\t') && (*s != '\0')) s++;
			*s = buf[SBUF_SIZE - 1] = '\0';
			
			if (!strcasecmp("flags", buf)) {
				/* Skip over white space */
			
				s++;
				while (((*s == ' ') || (*s == '\t')) && (*s != '\0')) s++;
		
				for (q = s; *q; q++)
					*q = toupper(*q);

				/* Skip over to the newline, and nix it */
			
				q = s;
				while (*q != '\n') q++;
				*q = '\0';
				
				/* Iterate through the list of flags */
				
				q = strtok_r(s, " \t", &tokst);
				
				while (q != NULL) {
					/* Set the appropriate bit */
					
					fp = (FLAGENT *)hashfind(q, &mudstate.flags_htab); 
					if (fp != NULL) {
						if (fp->flagflag & FLAG_WORD3) {
							s_Flags3(object, Flags3(object) | fp->flagvalue);
						} else if (fp->flagflag & FLAG_WORD2) {
							s_Flags2(object, Flags2(object) | fp->flagvalue);
						} else {
							s_Flags(object, Flags(object) | fp->flagvalue);
						}
					}
                                	q = strtok_r(NULL, " \t", &tokst);
                                }
			}
			continue;
		}

		/* If we see 'powers', set powers on the object */
		
		if ((*buf == 'p') || (*buf == 'P')) {
			/* Cut through to the first space, tab, or NULL */
			while ((*s != ' ') && (*s != '\t') && (*s != '\0')) s++;
			*s = buf[SBUF_SIZE - 1] = '\0';
			
			if (!strcasecmp("powers", buf)) {
				/* Skip over white space */
			
				s++;
				while (((*s == ' ') || (*s == '\t')) && (*s != '\0')) s++;
		
				for (q = s; *q; q++)
					*q = tolower(*q);

				/* Skip over to the newline, and nix it */
			
				q = s;
				while (*q != '\n') q++;
				*q = '\0';
				
				/* Iterate through the list of powers */
				
				q = strtok_r(s, " \t", &tokst);
				
				while (q != NULL) {
					/* Set the appropriate bit */
					
					pp = (POWERENT *)hashfind(q, &mudstate.powers_htab); 
					if (pp != NULL) {
						if (pp->powerpower & POWER_EXT) {
							s_Powers2(object, Powers2(object) | pp->powervalue);
						} else {
							s_Powers(object, Powers(object) | pp->powervalue);
						}
					}
                                	q = strtok_r(NULL, " \t", &tokst);
                                }
			}
			continue;
		}

		/* If we see 'name', set name on the object */
		
		if ((*buf == 'n') || (*buf == 'N')) {
			/* Cut through to the first space, tab, or NULL */
			while ((*s != ' ') && (*s != '\t') && (*s != '\0')) s++;
			*s = buf[SBUF_SIZE - 1] = '\0';
			
			if (!strcasecmp("name", buf)) {
				/* Skip over white space */
			
				s++;
				while (((*s == ' ') || (*s == '\t')) && (*s != '\0')) s++;
		
				/* Skip over to the newline, and nix it */
			
				q = s;
				while (*q != '\n') q++;
				*q = '\0';

				/* Set the name on the object */
				
				s_Name(object, s);
			}
			continue;
		}

		/* If we see a '-', end the attribute */
		
		if (*buf == '-') {
			*p = '\0';
			
			if (*attrnam == '@') {
				/* Execute a command */
				(void)process_command(object, player, 1,
					attrtxt, (char **)NULL, 0);
				*attrnam = '\0';
				p = attrtxt;
			} else {
				/* Create the attribute name and set it */
			
				anum = mkattr(attrnam + 1);
				*attrnam = '\0';
	
				/* Check for a good attribute number */
	
				if (anum > 0)
					atr_add(object, anum, attrtxt, player, 0);
				p = attrtxt;
			}

			continue;
		}
		
		/* If we see a '&' or '@', it's the beginning of an
		   attribute or command */
		
		if ((*buf == '&') || (*buf == '@')) {
			/* Cut through to the first space, tab, \n, or NULL */

			while ((*s != ' ') && (*s != '\t') && (*s != '\0')
			       && (*s != '\n')) s++;
			*s = buf[SBUF_SIZE - 1] = '\0';
			strncpy(attrnam, buf, SBUF_SIZE);

			/* Skip over white space */
			
			s++;
			while (((*s == ' ') || (*s == '\t')) && (*s != '\0')) s++;

			/* Skip over to the newline, and nix it */
			
			q = s;
			while (*q != '\n') q++;
			*q = '\0';

			/* Copy the rest of the line to attribute text */
			
			if (*s) {
				if (*attrnam == '@') {
					safe_str(attrnam, attrtxt, &p);
					safe_chr(' ', attrtxt, &p);
				}
				safe_str(s, attrtxt, &p);
			}

			continue;
		}
			
		/* If we are in the middle of setting an attribute, copy
		 * any strings to attribute text */
		
		if (*attrnam) {
			/* Skip over to the newline, and nix it */
			
			q = s;
			while (*q != '\n') q++;
			*q = '\0';

			/* Strip leading white space */
		
			while (((*s == ' ') || (*s == '\t')) && (*s != '\0')) s++;
		
			/* Copy the rest of the line to attribute text */
		
			if (*s)
				safe_str(s, attrtxt, &p);
		}
		
		/* The line didn't match anything, discard it */
	}

	if (player != NOTHING)
		notify(player, "Code library uploaded.");
	fclose(f);
	
	free_mbuf(nam);
	free_lbuf(attrtxt);
	free_sbuf(attrnam);
	free_mbuf(buf);
}

void mod_codelib_cleanup_startup()
{
	char *p, *s, *dbrefstr;
	dbref thing;
	FILE *f;
	int i;
	
	/* Go through the hash table read from the config file and load 
	 * up the code */
	
	s = alloc_mbuf("mod_codelib_cleanup_startup");

	for (p = hash_firstkey(&mod_codelib_config.libraries); p;
	     p = hash_nextkey(&mod_codelib_config.libraries)) {
		dbrefstr = (char *)hashfind(p, &mod_codelib_config.libraries);

		if (dbrefstr)
			thing = atoi(dbrefstr);
		else
			thing = -1;

			
		if (!Good_obj(thing) || isGarbage(thing)) {
			STARTLOG(LOG_ALWAYS, "MOD", "CODELIB")
				log_printf("#%d is not a valid object", thing);
			ENDLOG
			continue;
		}

		
		/* Upload the softcode */
						
		mod_codelib_upload_file(p, thing, NOTHING);
	}
	free_mbuf(s);
}

DO_CMD_TWO_ARG(mod_codelib_do_codelib)
{
	dbref object;
	char *s;

	s = alloc_mbuf("mod_codelib_do_codelib");
	
	if (arg1 && *arg1) {
		snprintf(s, MBUF_SIZE, "Codelib: %s", arg1);
	} else {
		notify(player, "You must specify a library name.");
		return;
	}
		
	if (key & MOD_CODELIB_CREATE) {
		object = create_obj(player, TYPE_THING, s, 0);
		if (object == NOTHING)
			return;
			
		move_via_generic(object, player, NOTHING, 0);
		s_Home(object, new_home(player));
		notify(player, tprintf("Object created as #%d.", object));
	} else {
		if (!arg2 || !*arg2) {
			notify(player, "You must specify an object.");
		}

		/* Look for the object */
        
		init_match(player, arg2, NOTYPE);
		match_everything(MAT_EXIT_PARENTS);
		object = match_result();

		if (!Good_obj(object)) {
			notify(player, "No such object.");
			return;
		}
	}
	
	/* Upload the softcode */
						
	mod_codelib_upload_file(arg1, object, player);
}

NAMETAB mod_codelib_codelib_sw[] = {
{(char *)"create",	2,	CA_WIZARD,	MOD_CODELIB_CREATE},
{ NULL,                 0,              0,              0}};

CMDENT mod_codelib_cmdtable[] = {
{(char *)"@codelib",	mod_codelib_codelib_sw,	CA_WIZARD,
	0,		CS_TWO_ARG,
	NULL,		NULL,	NULL,	mod_codelib_do_codelib},
{(char *)NULL,		NULL,		0,
	0,		0,
	NULL,		NULL,	NULL,	{NULL}}};
                

void mod_codelib_init()
{
	mod_codelib_config.pathname = XSTRDUP(".", "cf_string");
	register_hashtables(mod_codelib_hashtable, NULL);
	register_commands(mod_codelib_cmdtable);
}