fbmuck-6.05/auto/
fbmuck-6.05/contrib/jresolver/
fbmuck-6.05/contrib/jresolver/org/
fbmuck-6.05/contrib/jresolver/org/fuzzball/
fbmuck-6.05/docs/devel/
fbmuck-6.05/game/
fbmuck-6.05/game/logs/
fbmuck-6.05/game/muf/
fbmuck-6.05/scripts/
fbmuck-6.05/src_docs/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "interface.h"
#include "mcp.h"
#include "mcpgui.h"
#include "externs.h"
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif /* HAVE_MALLOC_H */

typedef struct DlogValue_t {
	struct DlogValue_t *next;
	char *name;
	int lines;
	char **value;
} DlogValue;

typedef struct DlogData_t {
	struct DlogData_t *next;
	struct DlogData_t **prev;
	char *id;
	int descr;
	int dismissed;
	DlogValue *values;
	Gui_CB callback;
	GuiErr_CB error_cb;
	void *context;
} DlogData;

DlogData *dialog_list = NULL;
DlogData *dialog_last_accessed = NULL;


void gui_pkg_callback(McpFrame * mfr, McpMesg * msg, McpVer ver, void *context);


void
gui_initialize(void)
{
	McpVer minver = { 1, 0 };  /* { major, minor } */
	McpVer maxver = { 1, 3 };  /* { major, minor } */

	mcp_package_register(GUI_PACKAGE, minver, maxver, gui_pkg_callback, NULL, NULL);
}


DlogData *
gui_dlog_find(const char *dlogid)
{
	DlogData *ptr;

	ptr = dialog_last_accessed;
	if (ptr && !strcmp(ptr->id, dlogid)) {
		return ptr;
	}
	ptr = dialog_list;
	while (ptr) {
		if (!strcmp(ptr->id, dlogid)) {
			dialog_last_accessed = ptr;
			return ptr;
		}
		ptr = ptr->next;
	}
	return NULL;
}


void*
gui_dlog_get_context(const char *dlogid)
{
	DlogData *ptr = gui_dlog_find(dlogid);

	if (ptr) {
		return ptr->context;
	} else {
		return NULL;
	}
}


int
gui_dlog_get_descr(const char *dlogid)
{
	DlogData *ptr = gui_dlog_find(dlogid);

	if (ptr) {
		return ptr->descr;
	} else {
		return EGUINODLOG;
	}
}


int
GuiClosed(const char *dlogid)
{
	DlogData *ptr = gui_dlog_find(dlogid);

	if (ptr) {
		return ptr->dismissed;
	} else {
		return EGUINODLOG;
	}
}


int
gui_value_linecount(const char *dlogid, const char *id)
{
	DlogValue *ptr;
	DlogData *ddata = gui_dlog_find(dlogid);

	if (!ddata) {
		return EGUINODLOG;
	}
	ptr = ddata->values;
	while (ptr && strcmp(ptr->name, id)) {
		ptr = ptr->next;
	}
	if (!ptr) {
		return 0;
	}
	return ptr->lines;
}



const char *
GuiValueFirst(const char *dlogid)
{
	DlogData *ddata = gui_dlog_find(dlogid);

	if (!ddata || !ddata->values) {
		return NULL;
	}
	return ddata->values->name;
}


const char *
GuiValueNext(const char *dlogid, const char *id)
{
	DlogValue *ptr;
	DlogData *ddata = gui_dlog_find(dlogid);

	if (!ddata) {
		return NULL;
	}
	ptr = ddata->values;
	while (ptr && strcmp(ptr->name, id)) {
		ptr = ptr->next;
	}
	if (!ptr || !ptr->next) {
		return NULL;
	}
	return ptr->next->name;
}


const char *
gui_value_get(const char *dlogid, const char *id, int line)
{
	DlogValue *ptr;
	DlogData *ddata = gui_dlog_find(dlogid);

	if (!ddata) {
		return NULL;
	}
	ptr = ddata->values;
	while (ptr && strcmp(ptr->name, id)) {
		ptr = ptr->next;
	}
	if (!ptr || line < 0 || line >= ptr->lines) {
		return NULL;
	}
	return ptr->value[line];
}


void
gui_value_set_local(const char *dlogid, const char *id, int lines, const char **value)
{
	DlogValue *ptr;
	DlogData *ddata = gui_dlog_find(dlogid);
	int i;
	int limit = 256;

	if (!ddata) {
		return;
	}
	ptr = ddata->values;
	while (ptr && strcmp(ptr->name, id)) {
		ptr = ptr->next;
		if (!limit--) {
			return;
		}
	}
	if (ptr) {
		for (i = 0; i < ptr->lines; i++) {
			free(ptr->value[i]);
		}
		free(ptr->value);
	} else {
		ptr = (DlogValue *) malloc(sizeof(DlogValue));
		ptr->name = (char *) malloc(strlen(id) + 1);
		strcpy(ptr->name, id);
		ptr->next = ddata->values;
		ddata->values = ptr;
	}
	ptr->lines = lines;
	ptr->value = (char **) malloc(sizeof(char *) * lines);

	for (i = 0; i < lines; i++) {
		ptr->value[i] = (char *) malloc(strlen(value[i]) + 1);
		strcpy(ptr->value[i], value[i]);
	}
}


void
gui_value_free(DlogValue * ptr)
{
	int i;

	free(ptr->name);
	for (i = 0; i < ptr->lines; i++) {
		free(ptr->value[i]);
	}
	free(ptr->value);
}


void
gui_pkg_callback(McpFrame * mfr, McpMesg * msg, McpVer ver, void *context)
{
	DlogData *dat;
	const char *dlogid = mcp_mesg_arg_getline(msg, "dlogid", 0);
	const char *id = mcp_mesg_arg_getline(msg, "id", 0);

	if (!dlogid || !*dlogid) {
		show_mcp_error(mfr, msg->mesgname, "Missing dialog ID.");
		return;
	}
	dat = gui_dlog_find(dlogid);
	if (!dat) {
		show_mcp_error(mfr, msg->mesgname, "Invalid dialog ID.");
		return;
	}
	if (!string_compare(msg->mesgname, "ctrl-value")) {
		int valcount = mcp_mesg_arg_linecount(msg, "value");
		int i;
		const char **value = (const char **) malloc(sizeof(const char *) * valcount);

		if (!id || !*id) {
			show_mcp_error(mfr, msg->mesgname, "Missing control ID.");
			return;
		}
		for (i = 0; i < valcount; i++) {
			value[i] = mcp_mesg_arg_getline(msg, "value", i);
		}
		gui_value_set_local(dlogid, id, valcount, value);
		free(value);

	} else if (!string_compare(msg->mesgname, "ctrl-event")) {
		const char *evt = mcp_mesg_arg_getline(msg, "event", 0);
		const char *dismissed = mcp_mesg_arg_getline(msg, "dismissed", 0);
		int did_dismiss = 1;

		if (!id || !*id) {
			show_mcp_error(mfr, msg->mesgname, "Missing control ID.");
			return;
		}
		if (!evt || !*evt) {
			evt = "buttonpress";
		}
		if (NULL != dismissed) {
			if (!string_compare(dismissed, "false")) {
				did_dismiss = 0;
			} else if (!string_compare(dismissed, "0")) {
				did_dismiss = 0;
			}
		}
		if (did_dismiss) {
			dat->dismissed = 1;
		}
		if (dat->callback) {
			dat->callback(dat->descr, dlogid, id, evt, msg, did_dismiss, dat->context);
		}
	} else if (!string_compare(msg->mesgname, "error")) {
		const char *err  = mcp_mesg_arg_getline(msg, "errcode", 0);
		const char *text = mcp_mesg_arg_getline(msg, "errtext", 0);
		const char *id   = mcp_mesg_arg_getline(msg, "id", 0);

		if (!err) {
			err = "";
		}
		if (!text) {
			text = "";
		}
		if (dat->error_cb) {
			dat->error_cb(dat->descr, dlogid, id, err, text, dat->context);
		}
	}
}


const char *
gui_dlog_alloc(int descr, Gui_CB callback, GuiErr_CB error_cb, void *context)
{
	char tmpid[32];
	DlogData *ptr;

	while (1) {
		snprintf(tmpid, sizeof(tmpid), "%08lX", (unsigned long)RANDOM());
		if (!gui_dlog_find(tmpid)) {
			break;
		}
	}
	ptr = (DlogData *) malloc(sizeof(DlogData));
	ptr->id = (char *) malloc(strlen(tmpid) + 1);
	strcpy(ptr->id, tmpid);
	ptr->descr = descr;
	ptr->dismissed = 0;
	ptr->callback = callback;
	ptr->error_cb = error_cb;
	ptr->context = context;
	ptr->values = NULL;

	ptr->prev = &dialog_list;
	ptr->next = dialog_list;
	if (dialog_list)
		dialog_list->prev = &ptr->next;
	dialog_list = ptr;
	dialog_last_accessed = ptr;
	return ptr->id;
}


int
GuiFree(const char *id)
{
	DlogData *ptr;
	DlogValue *valptr;
	DlogValue *nextval;

	ptr = gui_dlog_find(id);
	if (!ptr) {
		return EGUINODLOG;
	}
	*ptr->prev = ptr->next;
	if (ptr->next)
		ptr->next->prev = ptr->prev;

	ptr->next = NULL;
	ptr->prev = NULL;
	free(ptr->id);

	valptr = ptr->values;
	while (valptr) {
		nextval = valptr->next;
		gui_value_free(valptr);
		valptr = nextval;
	}
	ptr->values = NULL;
	ptr->descr = 0;
	if (dialog_last_accessed == ptr) {
		dialog_last_accessed = NULL;
	}
	free(ptr);
	return 0;
}


int
gui_dlog_closeall_descr(int descr)
{
	DlogData *ptr;
	McpMesg msg;

	ptr = dialog_list;
	while (ptr) {
		while (ptr) {
			if (ptr->descr == descr) {
				break;
			}
			ptr = ptr->next;
		}
		if (!ptr) {
			return 0;
		}
		if (ptr->callback) {
			mcp_mesg_init(&msg, GUI_PACKAGE, "ctrl-event");
			mcp_mesg_arg_append(&msg, "dlogid", ptr->id);
			mcp_mesg_arg_append(&msg, "id", "_closed");
			mcp_mesg_arg_append(&msg, "dismissed", "1");
			mcp_mesg_arg_append(&msg, "event", "buttonpress");
			ptr->callback(ptr->descr, ptr->id, "_closed", "buttonpress", &msg, 1, ptr->context);
			mcp_mesg_clear(&msg);
		}
		ptr = ptr->next;
	}
	return 0;
}


int
gui_dlog_freeall_descr(int descr)
{
	DlogData *ptr;
	DlogData *next;
	DlogValue *valptr;

	ptr = dialog_list;
	while (ptr) {
		while (ptr) {
			if (ptr->descr == descr) {
				break;
			}
			ptr = ptr->next;
		}
		if (!ptr) {
			return 0;
		}
		next = ptr->next;
		*ptr->prev = next;
		if (next)
			next->prev = ptr->prev;

		ptr->next = NULL;
		ptr->prev = NULL;
		if (dialog_last_accessed == ptr) {
			dialog_last_accessed = NULL;
		}
		free(ptr->id);

		valptr = ptr->values;
		while (valptr) {
			ptr->values = valptr->next;
			gui_value_free(valptr);
			valptr = ptr->values;
		}
		ptr->values = NULL;
		ptr->descr = 0;
		free(ptr);
		ptr = next;
	}
	return 0;
}


McpVer
GuiVersion(int descr)
{
	McpVer supp = { 0, 0 };
	McpFrame *mfr;

	mfr = descr_mcpframe(descr);
	if (mfr) {
		supp = mcp_frame_package_supported(mfr, GUI_PACKAGE);
	}
	return supp;
}


int
GuiSupported(int descr)
{
	McpVer supp;
	McpFrame *mfr;

	mfr = descr_mcpframe(descr);
	if (mfr) {
		supp = mcp_frame_package_supported(mfr, GUI_PACKAGE);
		if (supp.verminor != 0 || supp.vermajor != 0) {
			return 1;
		}
	}
	return 0;
}


const char *
GuiSimple(int descr, const char *title, Gui_CB callback, GuiErr_CB error_cb, void *context)
{
	McpMesg msg;
	McpFrame *mfr = descr_mcpframe(descr);
	const char *id;

	if (!mfr) {
		return NULL;
	}
	if (GuiSupported(descr)) {
		id = gui_dlog_alloc(descr, callback, error_cb, context);
		mcp_mesg_init(&msg, GUI_PACKAGE, "dlog-create");
		mcp_mesg_arg_append(&msg, "dlogid", id);
		mcp_mesg_arg_append(&msg, "type", "simple");
		mcp_mesg_arg_append(&msg, "title", title);
		mcp_frame_output_mesg(mfr, &msg);
		mcp_mesg_clear(&msg);
		return id;
	} else {
		return NULL;
	}
}


const char *
GuiTabbed(int descr,
		  const char *title,
		  int pagecount, const char **pagenames, const char **pageids,
		  Gui_CB callback, GuiErr_CB error_cb, void *context)
{
	McpMesg msg;
	McpFrame *mfr = descr_mcpframe(descr);
	const char *id;
	int i;

	if (!mfr) {
		return NULL;
	}
	if (GuiSupported(descr)) {
		id = gui_dlog_alloc(descr, callback, error_cb, context);
		mcp_mesg_init(&msg, GUI_PACKAGE, "dlog-create");
		mcp_mesg_arg_append(&msg, "dlogid", id);
		mcp_mesg_arg_append(&msg, "type", "tabbed");
		mcp_mesg_arg_append(&msg, "title", title);
		for (i = 0; i < pagecount; i++) {
			mcp_mesg_arg_append(&msg, "panes", pageids[i]);
			mcp_mesg_arg_append(&msg, "names", pagenames[i]);
		}
		mcp_frame_output_mesg(mfr, &msg);
		mcp_mesg_clear(&msg);
		return id;
	} else {
		return NULL;
	}
}


const char *
GuiHelper(int descr,
		  const char *title,
		  int pagecount, const char **pagenames, const char **pageids,
		  Gui_CB callback, GuiErr_CB error_cb, void *context)
{
	McpMesg msg;
	McpFrame *mfr = descr_mcpframe(descr);
	const char *id;
	int i;

	if (!mfr) {
		return NULL;
	}
	if (GuiSupported(descr)) {
		id = gui_dlog_alloc(descr, callback, error_cb, context);
		mcp_mesg_init(&msg, GUI_PACKAGE, "dlog-create");
		mcp_mesg_arg_append(&msg, "dlogid", id);
		mcp_mesg_arg_append(&msg, "type", "helper");
		mcp_mesg_arg_append(&msg, "title", title);
		for (i = 0; i < pagecount; i++) {
			mcp_mesg_arg_append(&msg, "panes", pageids[i]);
			mcp_mesg_arg_append(&msg, "names", pagenames[i]);
		}
		mcp_frame_output_mesg(mfr, &msg);
		mcp_mesg_clear(&msg);
		return id;
	} else {
		return NULL;
	}
}


int
GuiShow(const char *id)
{
	McpMesg msg;
	McpFrame *mfr;
	int descr = gui_dlog_get_descr(id);

	mfr = descr_mcpframe(descr);
	if (!mfr) {
		return EGUINODLOG;
	}
	if (GuiSupported(descr)) {
		if (!GuiClosed(id)) {
			mcp_mesg_init(&msg, GUI_PACKAGE, "dlog-show");
			mcp_mesg_arg_append(&msg, "dlogid", id);
			mcp_frame_output_mesg(mfr, &msg);
			mcp_mesg_clear(&msg);
		}
		return 0;
	}
	return EGUINOSUPPORT;
}



int
GuiClose(const char *id)
{
	McpMesg msg;
	McpFrame *mfr;
	int descr = gui_dlog_get_descr(id);

	mfr = descr_mcpframe(descr);
	if (!mfr) {
		return EGUINODLOG;
	}
	if (GuiSupported(descr)) {
		if (!GuiClosed(id)) {
			mcp_mesg_init(&msg, GUI_PACKAGE, "dlog-close");
			mcp_mesg_arg_append(&msg, "dlogid", id);
			mcp_frame_output_mesg(mfr, &msg);
			mcp_mesg_clear(&msg);
		}
		return 0;
	}
	return EGUINOSUPPORT;
}



int
GuiSetVal(const char *dlogid, const char *id, int lines, const char **value)
{
	McpMesg msg;
	McpFrame *mfr;
	int i;
	int descr = gui_dlog_get_descr(dlogid);

	mfr = descr_mcpframe(descr);
	if (!mfr) {
		return EGUINODLOG;
	}
	if (GuiSupported(descr)) {
		mcp_mesg_init(&msg, GUI_PACKAGE, "ctrl-value");
		mcp_mesg_arg_append(&msg, "dlogid", dlogid);
		mcp_mesg_arg_append(&msg, "id", id);
		for (i = 0; i < lines; i++) {
			mcp_mesg_arg_append(&msg, "value", value[i]);
		}
		mcp_frame_output_mesg(mfr, &msg);
		mcp_mesg_clear(&msg);
		gui_value_set_local(dlogid, id, lines, value);
		return 0;
	}
	return EGUINOSUPPORT;
}



int
GuiListInsert(const char *dlogid, const char *id, int after, int lines, const char **value)
{
	McpMesg msg;
	McpFrame *mfr;
	char numbuf[32];
	int i;
	int descr = gui_dlog_get_descr(dlogid);

	mfr = descr_mcpframe(descr);
	if (!mfr) {
		return EGUINODLOG;
	}
	if (GuiSupported(descr)) {
		mcp_mesg_init(&msg, GUI_PACKAGE, "list-insert");
		mcp_mesg_arg_append(&msg, "dlogid", dlogid);
		mcp_mesg_arg_append(&msg, "id", id);
		if (after > 0) {
			snprintf(numbuf, sizeof(numbuf), "%d", after);
			mcp_mesg_arg_append(&msg, "after", numbuf);
		}
		for (i = 0; i < lines; i++) {
			mcp_mesg_arg_append(&msg, "values", value[i]);
		}
		mcp_frame_output_mesg(mfr, &msg);
		mcp_mesg_clear(&msg);
		return 0;
	}
	return EGUINOSUPPORT;
}



int
GuiListDel(const char *dlogid, const char *id, int from, int to)
{
	McpMesg msg;
	McpFrame *mfr;
	char numbuf[32];
	int descr = gui_dlog_get_descr(dlogid);

	mfr = descr_mcpframe(descr);
	if (!mfr) {
		return EGUINODLOG;
	}
	if (GuiSupported(descr)) {
		mcp_mesg_init(&msg, GUI_PACKAGE, "list-delete");
		mcp_mesg_arg_append(&msg, "dlogid", dlogid);
		mcp_mesg_arg_append(&msg, "id", id);
		if (from == GUI_LIST_END) {
			mcp_mesg_arg_append(&msg, "from", "end");
		} else {
			snprintf(numbuf, sizeof(numbuf), "%d", from);
			mcp_mesg_arg_append(&msg, "from", numbuf);
		}
		if (to == GUI_LIST_END) {
			mcp_mesg_arg_append(&msg, "to", "end");
		} else {
			snprintf(numbuf, sizeof(numbuf), "%d", to);
			mcp_mesg_arg_append(&msg, "to", numbuf);
		}
		mcp_frame_output_mesg(mfr, &msg);
		mcp_mesg_clear(&msg);
		return 0;
	}
	return EGUINOSUPPORT;
}



int
GuiMenuItem(const char *dlogid, const char *id, const char *type, const char *name, const char **args)
{
	McpMesg msg;
	McpFrame *mfr;
	int i;
	int descr = gui_dlog_get_descr(dlogid);

	mfr = descr_mcpframe(descr);
	if (!mfr) {
		return EGUINODLOG;
	}
	if (GuiSupported(descr)) {
		mcp_mesg_init(&msg, GUI_PACKAGE, "menu-item");
		mcp_mesg_arg_append(&msg, "dlogid", dlogid);
		mcp_mesg_arg_append(&msg, "id", id);
		mcp_mesg_arg_append(&msg, "name", name);
		mcp_mesg_arg_append(&msg, "type", name);
		i = 0;
		while (args && args[i]) {
			const char *arg = args[i];
			const char *val = args[i + 1];

			mcp_mesg_arg_append(&msg, arg, val);
			i += 2;
		}
		mcp_frame_output_mesg(mfr, &msg);
		mcp_mesg_clear(&msg);
		return 0;
	}
	return EGUINOSUPPORT;
}



int
GuiMenuCmd(const char *dlogid, const char *id, const char *name)
{
	return GuiMenuItem(dlogid, id, "command", name, NULL);
}



int
GuiMenuCheckBtn(const char *dlogid, const char *id, const char *name, const char **args)
{
	return GuiMenuItem(dlogid, id, "checkbutton", name, args);
}



void
gui_ctrl_process_layout(McpMesg * msg, int layout)
{
	char buf[32];

	buf[0] = '\0';
	if ((layout & GUI_N))
		strcatn(buf, sizeof(buf), "n");

	if ((layout & GUI_S))
		strcatn(buf, sizeof(buf), "s");

	if ((layout & GUI_E))
		strcatn(buf, sizeof(buf), "e");

	if ((layout & GUI_W))
		strcatn(buf, sizeof(buf), "w");

	if (strcmp(buf, ""))
		mcp_mesg_arg_append(msg, "sticky", buf);


	snprintf(buf, sizeof(buf), "%d", GET_COLSKIP(layout));
	if (strcmp(buf, "0"))
		mcp_mesg_arg_append(msg, "colskip", buf);


	snprintf(buf, sizeof(buf), "%d", GET_COLSPAN(layout));
	if (strcmp(buf, "1"))
		mcp_mesg_arg_append(msg, "colspan", buf);


	snprintf(buf, sizeof(buf), "%d", GET_ROWSPAN(layout));
	if (strcmp(buf, "1"))
		mcp_mesg_arg_append(msg, "rowspan", buf);


	snprintf(buf, sizeof(buf), "%d", GET_LEFTPAD(layout));
	if (strcmp(buf, "0"))
		mcp_mesg_arg_append(msg, "leftpad", buf);


	snprintf(buf, sizeof(buf), "%d", GET_TOPPAD(layout));
	if (strcmp(buf, "0"))
		mcp_mesg_arg_append(msg, "toppad", buf);


	if ((layout & GUI_NONL))
		mcp_mesg_arg_append(msg, "newline", "0");

	if ((layout & GUI_HEXP))
		mcp_mesg_arg_append(msg, "hweight", "1");

	if ((layout & GUI_VEXP))
		mcp_mesg_arg_append(msg, "vweight", "1");

	if ((layout & GUI_REPORT))
		mcp_mesg_arg_append(msg, "report", "1");

	if ((layout & GUI_REQUIRED))
		mcp_mesg_arg_append(msg, "required", "1");
}



int
gui_ctrl_make_v(const char *dlogid, const char *type, const char *pane,
		        const char *id, const char *text, const char *value,
				int layout, const char **args)
{
	McpMesg msg;
	McpFrame *mfr;
	int descr;
	int i;

	descr = gui_dlog_get_descr(dlogid);
	mfr = descr_mcpframe(descr);
	if (!mfr) {
		return EGUINODLOG;
	}
	if (GuiSupported(descr)) {
		char cmdname[64];

		snprintf(cmdname, sizeof(cmdname), "ctrl-%.55s", type);
		mcp_mesg_init(&msg, GUI_PACKAGE, cmdname);
		gui_ctrl_process_layout(&msg, layout);
		mcp_mesg_arg_append(&msg, "dlogid", dlogid);
		mcp_mesg_arg_append(&msg, "id", id);
		if (text)
			mcp_mesg_arg_append(&msg, "text", text);
		if (value) {
			mcp_mesg_arg_append(&msg, "value", value);
			if (id) {
				gui_value_set_local(dlogid, id, 1, &value);
			}
		}
		if (pane)
			mcp_mesg_arg_append(&msg, "pane", pane);
		i = 0;
		while (args && args[i]) {
			const char *arg = args[i];
			const char *val = args[i + 1];

			if (id && !string_compare(arg, "value")) {
				gui_value_set_local(dlogid, id, 1, &val);
			}
			mcp_mesg_arg_append(&msg, arg, val);
			i += 2;
		}
		mcp_frame_output_mesg(mfr, &msg);
		mcp_mesg_clear(&msg);
		return 0;
	}
	return EGUINOSUPPORT;
}



int
gui_ctrl_make_l(const char *dlogid, const char *type, const char *pane, const char *id, const char *text, const char *value,
				int layout, ...)
{
	va_list ap;
	McpMesg msg;
	McpFrame *mfr;
	int descr;

	va_start(ap, layout);

	descr = gui_dlog_get_descr(dlogid);
	mfr = descr_mcpframe(descr);
	if (!mfr) {
		va_end(ap);
		return EGUINODLOG;
	}
	if (GuiSupported(descr)) {
		char cmdname[64];

		snprintf(cmdname, sizeof(cmdname), "ctrl-%.55s", type);
		mcp_mesg_init(&msg, GUI_PACKAGE, cmdname);
		gui_ctrl_process_layout(&msg, layout);
		mcp_mesg_arg_append(&msg, "dlogid", dlogid);
		mcp_mesg_arg_append(&msg, "id", id);
		if (text)
			mcp_mesg_arg_append(&msg, "text", text);
		if (value) {
			mcp_mesg_arg_append(&msg, "value", value);
			if (id) {
				gui_value_set_local(dlogid, id, 1, &value);
			}
		}
		if (pane)
			mcp_mesg_arg_append(&msg, "pane", pane);
		while (1) {
			const char *val;
			const char *arg;

			arg = va_arg(ap, const char *);

			if (!arg)
				break;
			val = va_arg(ap, const char *);

			mcp_mesg_arg_append(&msg, arg, val);
		}
		mcp_frame_output_mesg(mfr, &msg);
		mcp_mesg_clear(&msg);
		va_end(ap);
		return 0;
	}
	va_end(ap);
	return EGUINOSUPPORT;
}



int
GuiEdit(const char *dlogid, const char *pane, const char *id, const char *text, const char *value, int width, int layout)
{
	char buf[32];

	snprintf(buf, sizeof(buf), "%d", width);
	return gui_ctrl_make_l(dlogid, "edit", pane, id, text, value, layout, "width", buf, NULL);
}


int
GuiText(const char *dlogid, const char *pane, const char *id, const char *value, int width, int layout)
{
	char widthbuf[32];

	snprintf(widthbuf, sizeof(widthbuf), "%d", width);
	return gui_ctrl_make_l(dlogid, "text", pane, id, NULL, value, layout, "width", widthbuf, NULL);
}


int
GuiSpinner(const char *dlogid, const char *pane, const char *id, const char *text, int value, int width, int min,
		   int max, int layout)
{
	char widthbuf[32];
	char valbuf[32];
	char minbuf[32];
	char maxbuf[32];

	snprintf(widthbuf, sizeof(widthbuf), "%d", width);
	snprintf(valbuf, sizeof(valbuf), "%d", value);
	snprintf(minbuf, sizeof(minbuf), "%d", min);
	snprintf(maxbuf, sizeof(maxbuf), "%d", max);
	return gui_ctrl_make_l(dlogid, "spinner", pane, id, text, valbuf, layout,
					"width", widthbuf, "min", minbuf, "max", maxbuf, NULL);
}


int
GuiCombo(const char *dlogid, const char *pane, const char *id, const char *text, const char *value, int width, int editable,
		 int layout)
{
	char buf[32];

	snprintf(buf, sizeof(buf), "%d", width);
	return gui_ctrl_make_l(dlogid, "combobox", pane, id, text, value, layout,
					"width", buf, "editable", editable ? "1" : "0", NULL);
}


int
GuiMulti(const char *dlogid, const char *pane, const char *id, const char *value, int width, int height, int fixed,
		 int layout)
{
	char widthbuf[32];
	char heightbuf[32];

	snprintf(widthbuf, sizeof(widthbuf), "%d", width);
	snprintf(heightbuf, sizeof(heightbuf), "%d", height);
	return gui_ctrl_make_l(dlogid, "multiedit", pane, id, NULL, value, layout,
					"width", widthbuf,
					"height", heightbuf, "font", (fixed ? "fixed" : "variable"), NULL);
}


int
GuiHRule(const char *dlogid, const char *pane, const char *id, int height, int layout)
{
	char heightbuf[32];

	snprintf(heightbuf, sizeof(heightbuf), "%d", height);
	return gui_ctrl_make_l(dlogid, "hrule", pane, id, NULL, NULL, layout, "height", heightbuf, NULL);
}


int
GuiVRule(const char *dlogid, const char *pane, const char *id, int thickness, int layout)
{
	char widthbuf[32];

	snprintf(widthbuf, sizeof(widthbuf), "%d", thickness);
	return gui_ctrl_make_l(dlogid, "vrule", pane, id, NULL, NULL, layout, "width", widthbuf, NULL);
}


int
GuiFrame(const char *dlogid, const char *pane, const char *id, int layout)
{
	return gui_ctrl_make_l(dlogid, "frame", pane, id, NULL, NULL, layout, NULL);
}


int
GuiGroupBox(const char *dlogid, const char *pane, const char *id, const char *text, int collapsible, int collapsed,
			int layout)
{
	return gui_ctrl_make_l(dlogid, "frame", pane, id, text, NULL, layout,
					"visible", "1",
					"collapsible", collapsible ? "1" : "0",
					"collapsed", collapsed ? "1" : "0", NULL);
}


int
GuiButton(const char *dlogid, const char *pane, const char *id, const char *text, int width, int dismiss, int layout)
{
	char widthbuf[32];

	snprintf(widthbuf, sizeof(widthbuf), "%d", width);
	return gui_ctrl_make_l(dlogid, "button", pane, id, text, NULL, layout,
					"width", widthbuf, "dismiss", dismiss ? "1" : "0", NULL);
}






/******************************************************************************************/
/* MUF gui functions
 **********************/


void
muf_dlog_add(struct frame *fr, const char *dlogid)
{
	struct dlogidlist *item = (struct dlogidlist *) malloc(sizeof(struct dlogidlist));

	strcpy(item->dlogid, dlogid);
	item->next = fr->dlogids;
	fr->dlogids = item;
}


void
muf_dlog_remove(struct frame *fr, const char *dlogid)
{
	struct dlogidlist **prev = &fr->dlogids;

	while (*prev) {
		if (!string_compare(dlogid, (*prev)->dlogid)) {
			struct dlogidlist *tmp = *prev;

			*prev = (*prev)->next;
			free(tmp);
		} else {
			prev = &((*prev)->next);
		}
	}
	GuiFree(dlogid);
}


void
muf_dlog_purge(struct frame *fr)
{
	while (fr->dlogids) {
		struct dlogidlist *tmp = fr->dlogids;

		GuiClose(fr->dlogids->dlogid);
		GuiFree(fr->dlogids->dlogid);
		fr->dlogids = fr->dlogids->next;
		free(tmp);
	}
}



/***************************************************************************
 ***************************************************************************
 ***************************************************************************/

void
post_dlog_cb(GUI_EVENT_CB_ARGS)
{
	if (!string_compare(id, "post")) {
		char buf[BUFFER_LEN];
		const char *subject = gui_value_get(dlogid, "subj", 0);
		const char *keywords = gui_value_get(dlogid, "keywd", 0);
		/* int bodycnt = gui_value_linecount(dlogid, "body"); */

		snprintf(buf, sizeof(buf), "Subject: %s", subject);
		pnotify(pdescrcon(descr), buf);
		snprintf(buf, sizeof(buf), "Keywords: %s", keywords);
		pnotify(pdescrcon(descr), buf);
	} else if (!string_compare(id, "cancel")) {
		pnotify(pdescrcon(descr), "Posting cancelled.");
	} else {
		pnotify(pdescrcon(descr), "Invalid event!");
	}
	if (did_dismiss) {
		GuiFree(dlogid);
	}
}


void
do_post_dlog(int descr, const char *text)
{
	const char *keywords[] = { "Misc.", "Wedding", "Party", "Toading", "New MUCK" };
	const char *dlg = GuiSimple(descr, "A demonstration dialog", post_dlog_cb, NULL, NULL);

	GuiEdit(dlg, NULL, "subj", "Subject", text, 60, GUI_EW);
	GuiCombo(dlg, NULL, "keywd", "Keywords", "Misc.", 60, 1, GUI_EW | GUI_HEXP);
	GuiListInsert(dlg, "keywd", GUI_LIST_END, 5, keywords);

	GuiMulti(dlg, NULL, "body", NULL, 80, 12, 1, GUI_NSEW | GUI_VEXP | COLSPAN(2));
	GuiHRule(dlg, NULL, NULL, 2, COLSPAN(2));
	GuiFrame(dlg, NULL, "bfr", GUI_EW | COLSPAN(2) | TOPPAD(0));
	GuiFrame(dlg, "bfr", NULL, GUI_EW | GUI_HEXP | GUI_NONL);
	GuiVRule(dlg, NULL, NULL, 2, GUI_NONL);
	GuiButton(dlg, NULL, "post", "Post", 8, 1, GUI_E | GUI_NONL);
	GuiButton(dlg, NULL, "cancel", "Cancel", 8, 1, GUI_E | TOPPAD(0));

	GuiShow(dlg);
}