/*
 *	Copyright 1988 by Rayan S. Zachariassen, all rights reserved.
 *	This will be free software, but only when it is finished.
 */

/* LINTLIBRARY */

#include "mailer.h"
#include "search.h"
#include "io.h"

extern struct sptree *spt_loginmap;
extern struct sptree *spt_uidmap;
extern void sp_null();

/*
 * In-core database maintenance.
 *
 * Note that the keys are stashed forever because of the symbol() lookup
 * thing; this puts a practical limitation on the usefullness of this.
 * If people start using this seriously we need to rethink the key->hashid
 * mechanism.
 */


struct sptree *
open_core(sip)
	struct search_info *sip;
{
	if (sip->subtype == NULL)
		return NULL;
	return (struct sptree *)sip->subtype;
}

/*
 * Search an incore database for a key.
 */

struct conscell *
search_core(sip)
	struct search_info *sip;
{
	struct sptree *db;
	struct spblk *spl;
	struct conscell *tmp;

	if ((db = open_core(sip)) == NULL)
		return NULL;
	if ((spl = sp_lookup(symbol(sip->key), db)) == NULL)
		return NULL;
	if (spl->data == NULL)
		return newstring((u_char *)strnsave("", 1));
	return newstring((u_char *)strsave((char *)spl->data));
}

/*
 * Free any information stored in this database.
 */

int
icfreedata(spl)
	struct spblk *spl;
{
	if (spl->data)
		free((char *)spl->data);
	return 0;
}

void
close_core(sip)
	struct search_info *sip;
{
	struct sptree *db;

	if ((db = open_core(sip)) == NULL)
		return;
	if (db != spt_loginmap)
		sp_scan(icfreedata, (struct spblk *)NULL, db);
	sp_null(db);
}

/*
 * Add the indicated key/value pair to the database.
 */

int
add_core(sip, value)
	struct search_info *sip;
	char *value;
{
	struct sptree *db;
	struct spblk *spl;
	memtypes oval;

	if ((db = open_core(sip)) == NULL)
		return EOF;

	oval = stickymem;
	stickymem = MEM_MALLOC;
	if (*value == '\0')
		value = NULL;
	else
		value = strsave(value);
	stickymem = oval;

	if ((spl = sp_lookup(symbol(sip->key), db)) == NULL)
		sp_install(symbol(sip->key), (void*)value, 0, db);
	else {
		icfreedata(spl);
		spl->data = (u_char *)value;
	}

	return 0;
}

/*
 * Remove the indicated key from the database.
 */

int
remove_core(sip)
	struct search_info *sip;
{
	struct sptree *db;
	struct spblk *spl;

	if ((db = open_core(sip)) == NULL)
		return EOF;
	if ((spl = sp_lookup(symbol(sip->key), db)) == NULL) {
		fprintf(stderr, "remove_core: no such key as \"%s\"!\n",
				sip->key);
		return EOF;
	}
	icfreedata(spl);
	sp_delete(spl, db);
	return 0;
}

/*
 * Print the database.
 */

static FILE *pcfp;

int
icprintNS(spl)
	struct spblk *spl;
{
	if (spl->data != NULL)
		fprintf(pcfp, "%d\t%s\n", (int)spl->key, (char *)spl->data);
	else
		fprintf(pcfp, "%d\n", spl->key);
	return 0;
}

int
icprintSN(spl)
	struct spblk *spl;
{
	fprintf(pcfp, "%s\t%ld\n", pname(spl->key), (long)spl->data);
	return 0;
}

int
icprintSS(spl)
	struct spblk *spl;
{
	if (spl->data != NULL)
		fprintf(pcfp, "%s\t%s\n", pname(spl->key), (char *)spl->data);
	else
		fprintf(pcfp, "%s\n", pname(spl->key));
	return 0;
}

void
print_core(sip, outfp)
	struct search_info *sip;
	FILE *outfp;
{
	struct sptree *db;

	if ((db = open_core(sip)) == NULL)
		return;
	pcfp = outfp;
	if (db == spt_loginmap)
		sp_scan(icprintSN, (struct spblk *)NULL, db);
	else if (db == spt_uidmap)
		sp_scan(icprintNS, (struct spblk *)NULL, db);
	else
		sp_scan(icprintSS, (struct spblk *)NULL, db);
	fflush(outfp);
}

/*
 * Count the database.
 */

static int pc_cnt;

static int iccount(spl)
	struct spblk *spl;
{
	++pc_cnt;
	return 0;
}

void
count_core(sip, outfp)
	struct search_info *sip;
	FILE *outfp;
{
	struct sptree *db;
	pc_cnt = 0;

	if ((db = open_core(sip)) != NULL) {
	  sp_scan(iccount, (struct spblk *)NULL, db);
	}
	fprintf(outfp,"%d\n",pc_cnt);
	fflush(outfp);
}

void
owner_core(sip, outfp)
	struct search_info *sip;
	FILE *outfp;
{
	fprintf(outfp, "%d\n", getuid());
	fflush(outfp);
}
