/* set.c        -functions and stuff dealing with client setup
 * distributed as part of _ s u l a _
 * 
 * Author: Tano Fotang, 1997
 * 
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free 
 * Software Foundation; either version 2 of the License , or (at your option) 
 * any later version.
 * 
 * See the file COPYING for more details.
 * 
 */

#include <forms.h>
#include <errno.h>
#include <limits.h>
#include "aux.h"
#include "sula.h"
#include "chanwin.h"
#include "global.h"
#include "setting.h"
#include "setup.h"
#include "cmd.h"
#include "dcc.h"

#define SET_BOOL	(0)
#define SET_USHORT	(3)
#define	SET_UCHAR	(4)
#define SET_UINT	(5)
#define	SET_INT		(1)
#define SET_STR		(2)
#define	SET_USMALL	(6)

typedef struct TSetVars {
	char   *name;
	int     type;
	void   *val;
	int     flag;
} SetVars;


static SetVars setvars[] =
{
/* KEEP SORTED ! KEEP SORTED! KEEP SORTED ! KEEP SORTED ! KEEP SORTED ! */

	{"autochat", SET_BOOL, (void *) &gflags, AUTO_CHAT},
	{"autochecklag", SET_BOOL, (void *) &gflags, AUTO_CHECKLAG},
	{"autoget", SET_BOOL, (void *) &gflags, AUTO_GETFILE},
	{"autoinvite", SET_BOOL, (void *) &gflags, AUTO_INVITE},
	{"autorejoin", SET_BOOL, (void *) &gflags, AUTO_REJOIN},
	{"away_text", SET_STR, (void *) &away_text, 0},
	#if 0
	{"back_text", SET_STR, (void *) &away2_text, 0},	/* no longer away */
	#endif
	{"beep_away",SET_BOOL, (void *)&gflags,BEEP_AWAY},	/* private msg/notice/invite*/
	{"beep_dcc",SET_BOOL, (void *)&gflags,BEEP_DCC},	/* when dcc request arrives*/
	{"beep_on_errcli",SET_BOOL, (void *)&gflags,BEEP_ERR}, /* */
	{"beep_on_errserv",SET_BOOL, (void *)&gflags,BEEP_SERVER_ERR},/* bad command to server*/	
	{"beep_on_msg",SET_BOOL, (void *)&gflags,BEEP_MSG},	/* when a msg ie received*/
	{"cmdchar", SET_UCHAR, (void *) &cmdchar, 0},
	{"encryption", SET_BOOL, (void *) &gflags, ENCRYPT_MSG},
	{"extended_dcc", SET_BOOL, (void *) &sflags,EXTENDED_DCC},
	{"externalgethost", SET_BOOL, (void *)&sflags,EXTERNALGETHOST},
	{"finger", SET_BOOL, (void *) &gflags, FINGER},
	{"finger_reply", SET_STR, (void *) &finger_reply, 0},
	{"finger_utmp", SET_BOOL, (void *) &gflags, FINGER_UTMP},
	
	{"fmt_chanmode", SET_STR, (void *) &fmt_chanmode, 0},
	{"fmt_ignored", SET_STR, (void *) &fmt_ignored, 0},
	{"fmt_invite", SET_STR, (void *) &fmt_invite, 0},
	
	{"fmt_other_dccchat", SET_STR, (void *) &fmt_other_dccchat, 0},
	{"fmt_other_join", SET_STR, (void *) &fmt_other_join, 0},
	{"fmt_other_kick", SET_STR, (void *) &fmt_other_kick, 0},
	{"fmt_other_nick", SET_STR, (void *) &fmt_other_nick, 0},
	{"fmt_other_part", SET_STR, (void *) &fmt_other_part, 0},
	{"fmt_priv_action", SET_STR, (void *) &fmt_priv_action, 0},
	{"fmt_priv_msg", SET_STR, (void *) &fmt_priv_msg, 0},
	{"fmt_priv_notice", SET_STR, (void *) &fmt_priv_notice, 0},
	
	{"fmt_pub_action", SET_STR, (void *) &fmt_pub_action, 0},
	{"fmt_pub_msg", SET_STR, (void *) &fmt_pub_msg, 0},
	{"fmt_pub_msg2", SET_STR, (void *) &fmt_pub_msg2, 0},
	{"fmt_pub_msg3", SET_STR, (void *) &fmt_pub_msg3, 0},
	{"fmt_pub_notice", SET_STR, (void *) &fmt_pub_notice, 0},
	{"fmt_pub_notice2", SET_STR, (void *) &fmt_pub_notice2, 0},
	{"fmt_pub_notice3", SET_STR, (void *) &fmt_pub_notice3, 0},
	
	{"fmt_sed_nokey", SET_STR, (void *) &fmt_sed_nokey, 0},
	{"fmt_sed_priv", SET_STR, (void *) &fmt_sed_priv, 0},
	{"fmt_sed_pub", SET_STR, (void *) &fmt_sed_pub, 0},
	{"fmt_sed_your", SET_STR, (void *) &fmt_sed_your, 0},
	{"fmt_signoff", SET_STR, (void *) &fmt_signoff, 0},
	{"fmt_topic", SET_STR, (void *) &fmt_topic, 0},
	{"fmt_usermode", SET_STR, (void *) &fmt_usermode, 0},
	{"fmt_you_dccchat", SET_STR, (void *) &fmt_you_dccchat, 0},
	{"fmt_you_join", SET_STR, (void *) &fmt_you_join, 0},
	{"fmt_you_kick", SET_STR, (void *) &fmt_you_kick, 0},
	{"fmt_you_nick", SET_STR, (void *) &fmt_you_nick, 0},
	{"fmt_you_part", SET_STR, (void *) &fmt_you_part, 0},
	{"fmt_you_priv_action", SET_STR, (void *) &fmt_you_priv_action, 0},
	{"fmt_you_priv_msg", SET_STR, (void *) &fmt_you_priv_msg, 0},
	{"fmt_you_priv_notice", SET_STR, (void *) &fmt_you_priv_notice, 0},
	{"fmt_you_pub_action", SET_STR, (void *) &fmt_you_pub_action, 0},
	{"fmt_you_pub_msg", SET_STR, (void *) &fmt_you_pub_msg, 0},
	{"fmt_you_pub_notice", SET_STR, (void *) &fmt_you_pub_notice, 0},
	{"force_connection", SET_BOOL, (void *) &sflags, FORCE_CONNECTION},
	{"gethostbynameprogram", SET_STR, (void *) &gethostbynameprogram,0},
	{"history", SET_BOOL, (void *) &gflags, HISTORY},
	{"ig_bm_server", SET_BOOL, (void *) &gflags, BKMRK_IG_SERVER},
	{"inform_ignored", SET_BOOL, (void *) &gflags, INFORM_IGNORED},
	{"lag_frequency", SET_USHORT, (void *) &lag_tmout, 0},	/* lag check frequency*/
	{"match_caseless",SET_BOOL, (void *) &gflags,MATCH_CASELESS},
	{"max_go", SET_USMALL, (void *) &max_go, 0},
	{"max_sendbuf", SET_USHORT, (void *) &max_sendbuf, 0},
	{"maxchanlen", SET_USMALL, (void *) &MaxChanLen, 0},
	{"maxnicklen", SET_USMALL, (void *) &MaxNickLen, 0},
	{"ml_nl", SET_STR, (void *) &ml_nl, 0},
	{"numeric", SET_BOOL, (void *) &gflags, SHOW_NUMERIC},
	{"quit_text", SET_STR, (void *) &quit_text, 0},
	{"quit_textc", SET_STR, (void *) &chat_quit_text, 0},
	{"quote_ml", SET_BOOL, (void *) &gflags, QUOTE_ML},
	{"rm_on_fwd", SET_BOOL, (void *) &gflags, RM_ON_FWD},

	/*{"s_action", SET_BOOL, (void *) &sflags, S_ACTION},*/
	{"s_chat", SET_BOOL, (void *) &sflags, S_CHAT},
	{"s_ctcp_other", SET_BOOL, (void *) &sflags, S_CTCP_OTHER},
	{"s_finger", SET_BOOL, (void *) &sflags, S_FINGER},
	{"s_get", SET_BOOL, (void *) &sflags, S_FILEGET},
	{"s_invite", SET_BOOL, (void *) &sflags, S_INVITE},
	{"s_msg", SET_BOOL, (void *) &sflags, S_MSG},
	{"s_notice", SET_BOOL, (void *) &sflags, S_NOTICE},
	{"s_ping", SET_BOOL, (void *) &sflags, S_PING},
	/*{"s_sed", SET_BOOL, (void *) &sflags, S_SED},*/

	{"s_send", SET_BOOL, (void *) &sflags, S_FILESEND},
	/*{"s_version", SET_BOOL, (void *) &sflags, S_VERSION},*/

	{"save_bookmarks", SET_BOOL, (void *) &gflags, SAVE_BOOKMARKS},
	{"save_history", SET_BOOL, (void *) &gflags, SAVE_HISTORY},
	{"show_raw_msg", SET_BOOL, (void *) &gflags, SHOW_RAW_MSG},
	{"show_tips", SET_BOOL, (void *) &gflags, SHOW_TIPS},
	{"suppress_motd", SET_BOOL, (void *) &sflags, SUPPRESS_MOTD},
	{"tmout_connect", SET_USHORT, (void *) &connect_timeout, 0},
	{"tmout_dcc", SET_USHORT, (void *) &dcc_timeout, 0},
	{"tmout_getstr", SET_USHORT, (void *) &timeout, 0}, /* for getstr dialog*/
	
	{"tmout_tips", SET_USHORT, (void *) &tips_tmout, 0},
	{"userinfo", SET_STR, (void *) &userinfo, 0},
	{"verbose_client", SET_BOOL, (void *) &gflags, VERBOSE_CLIENT},
	{"verbose_ctcp", SET_BOOL, (void *) &gflags, VERBOSE_CTCP}
};

extern void set(int argc, char **argv, Winstruct * win)
{

	SetVars *svar;
	static int set_binary( /*SetVars *setvars, */ char *var, int n);
	int     nvars = sizeof(setvars) / sizeof(SetVars);
	register int i;

	if (argc == 1) {   /* list all */
		char   *buf=NULL;
		if (!win)
			return;
		i = -1;
		fl_freeze_form(win->chanwin->chanwin);
		while (++i < nvars) {
			svar = &setvars[i];
			switch (svar->type) {
			    case SET_BOOL:{
					    buf = (char *) malloc(sizeof(char) * (strlen(PROMPT) + strlen(svar->name) + 56));
					    sprintf(buf, PROMPT "Current value of %s: %s", svar->name, 
					    *((u_long *) svar->val) & svar->flag ? "on" : "off");
					    fl_addto_browser(win->chanwin->browser, buf);
					    break;
				    }
			    case SET_UCHAR:{
					    buf = (u_char *) malloc(sizeof(u_char) * (strlen(PROMPT) + strlen(svar->name) + 56));
					    sprintf(buf, PROMPT "Current value of %s: %c", svar->name, *((u_char *) svar->val));
					    fl_addto_browser(win->chanwin->browser, buf);
					    break;
				    }
			    case SET_USMALL:{
					/* u_char */
					    buf = (u_char *) malloc(sizeof(u_char) * (strlen(PROMPT) + strlen(svar->name) + 56));
					    sprintf(buf, PROMPT "Current value of %s: %d", svar->name, *((u_char *) svar->val));
					    fl_addto_browser(win->chanwin->browser, buf);
					    break;
				    }

			    case SET_USHORT:{
					    buf = (char *) malloc(sizeof(char) * (strlen(PROMPT) + strlen(svar->name) + 56));

					    sprintf(buf, PROMPT "Current value of %s: %d", svar->name, *((u_short *) svar->val));
					    fl_addto_browser(win->chanwin->browser, buf);
					    break;
				    }
			    case SET_INT:{
					    buf = (char *) malloc(sizeof(char) * (strlen(PROMPT) + strlen(svar->name) + 56));

					    sprintf(buf, PROMPT "Current value of %s: %d", svar->name, *((int *) svar->val));
					    fl_addto_browser(win->chanwin->browser, buf);
					    break;
				    }

			    case SET_STR:{
					    char  **flag = (char **) svar->val;
					    buf = (char *) malloc(sizeof(char) * (strlen(PROMPT) + strlen(svar->name) +
						     strlen  (*flag) + 30));
					    if (!buf) {
						    err_ret("%s %s", __FILE__, __LINE__);
						    break;
					    }
					    sprintf(buf, PROMPT "Current value of %s: \"%s\"",
						    svar->name, *flag);
					    fl_addto_browser(win->chanwin->browser, buf);
					    break;
				    }
			    default:
				    fprintf(stderr, "data type not implemented\n");
				    break;
			}	/* switch */
			free(buf);
		}		/*while */
		fl_unfreeze_form(win->chanwin->chanwin);
		return;
	}
	if (!strncasecmp(argv[1], "-help", 2)) {
		int i;
		if (argc < 3)
			i=show_std_help(uppercase(argv[0]), NULL, win->chanwin);
		else{
			i=show_std_help(uppercase(argv[0]),
			uppercase(argv[2]),
			 win->chanwin);
		}
		if (i) {
		/* dont remove otherwise junk appears on the screen */
			#if 1
			char    buf[225];
			sprintf(buf, PROMPT "Cant read any help for %s %s",
			 argv[0], argc > 2 ? argv[2] : "");
			#endif
		}
		return;
	}
	i = set_binary(argv[1], nvars);
	if (i < 0) {
		char   *buf = (char *) malloc(sizeof(char) * (
		strlen(PROMPT) + strlen(argv[1]) + 56));

		if (!buf) {
			err_ret("%s %s", __FILE__, __LINE__);
			return;
		}
		if (gflags & BEEP_ERR) fl_ringbell(0);
		sprintf(buf, PROMPT "set: No such variable \"%s\"", argv[1]);
		fl_addto_browser(win->chanwin->brow2, buf);
		free(buf);return;
	}
	argv += 2;
	svar = &setvars[i];
	switch (svar->type) {
	    case SET_BOOL:{
			    char   *buf=NULL;

			    if (!(*argv)) {
				    if (!win)
					    return;
				    buf = (char *) malloc(sizeof(char) * (strlen(PROMPT) + strlen(svar->name) + 56));
				    sprintf(buf, PROMPT "%s currently set %s",
					    svar->name, *((u_long *) svar->val) & svar->flag ? "on" : "off");
				    fl_addto_browser(win->chanwin->brow2, buf);
				     free(buf);
				    return;
			    }
			    if (!strncasecmp(*argv, "off", 2))
				    *((u_long *) svar->val) &= ~svar->flag;
			    else if (!strncasecmp(*argv, "on", 2))
				    *((u_long *) svar->val) |= svar->flag;
			    else if (!strncasecmp(*argv, "toggle", 1))
				    *((u_long *) svar->val) = (*((u_long *) svar->val) & svar->flag) ? *((int *) svar->val) & ~svar->flag : *((int *) svar->val) | svar->flag;
			    else {
				    if (!win)
					    return;
				    buf = (char *) malloc(sizeof(char) * (strlen(PROMPT) + 56));
				    if (gflags & BEEP_ERR) fl_ringbell(0);
				    sprintf(buf, PROMPT "set: value must be on, off, or toggle");
				    fl_addto_browser(win->chanwin->brow2, buf);
				    free(buf);
				    return;
			    }
			    if (!win)
				    return;
			    buf = (char *) malloc(sizeof(char) * (strlen(PROMPT) + 
			    strlen(svar->name) + 20));
			    sprintf(buf, PROMPT "%s now set %s", svar->name, 
			    *((u_long *) svar->val) & svar->flag ? "on" : "off");
			    fl_addto_browser(win->chanwin->brow2, buf);
			     free(buf);
			    return;
		    }
	    case SET_UCHAR:{
			    char   *buf=NULL;
			    char   *flag = (u_char *) svar->val;

			    if (!(*argv) || sscanf(*argv, "%c", flag) < 1) {
				    if (!win)
					    return;
				    buf = (u_char *) malloc(sizeof(u_char) * (strlen(PROMPT) + 
				    strlen(svar->name) + 56));
				    sprintf(buf, PROMPT "%s currently set to %c", svar->name, *flag);
				    fl_addto_browser(win->chanwin->brow2, buf);
				    free(buf);
				    return;
			    }
			    if (!win)
				    return;
			    buf = (u_char *) malloc(sizeof(u_char) * (strlen(PROMPT) + strlen(svar->name) + 56));
			    sprintf(buf, PROMPT "%s now set to %c", svar->name, *flag);
			    fl_addto_browser(win->chanwin->brow2, buf);
			     free(buf);
			    return;
		    }
	    case SET_USMALL:{	/* u_char */
			    char   *buf=NULL;
			    u_short *flag = (u_short *) svar->val;
			    int ff;
			    if (!win)   return;
			    *flag = (u_char) (*flag);
			    
			    if (!(*argv) || sscanf(*argv, "%i", &ff) < 1) {
				    
				    buf = (char *) malloc(sizeof(char) * (strlen(PROMPT) + strlen(svar->name) + 56));
				    *flag=(u_char)ff;
				    sprintf(buf, PROMPT "%s currently set to %d", svar->name, *flag);
				    fl_addto_browser(win->chanwin->brow2, buf);
				     free(buf);
				     return;
			    }
			    *flag=(u_char)ff;
			    *flag = (u_char) (*flag);
			    buf = (char *) malloc(sizeof(char) * (strlen(PROMPT) + 
			    strlen(svar->name) + 56));
			    sprintf(buf, PROMPT "%s now set to %d", svar->name, *flag);
			    fl_addto_browser(win->chanwin->brow2, buf);
			     free(buf);
			    return;
		    }

	    case SET_USHORT:{
			    char   *buf=NULL;
			    u_short *flag = (u_short *) svar->val;
			    if (!win)
					   return;
			    if (!(*argv) || sscanf(*argv, "%hu", flag) < 1) {
				    buf = (char *) malloc(sizeof(char) * (strlen(PROMPT) + strlen(svar->name) + 56));
				    sprintf(buf, PROMPT "%s currently set to %d", svar->name, *flag);
				    fl_addto_browser(win->chanwin->brow2, buf);
				    free(buf);return;
			    }else{
			    buf = (char *) malloc(sizeof(char) * (strlen(PROMPT) + strlen(svar->name) + 56));
			    sprintf(buf, PROMPT "%s now set to %d", svar->name, *flag);
			    fl_addto_browser(win->chanwin->brow2, buf);
			    }
			     free(buf);
			    return;
		    }
	    case SET_INT:{
			    char   *buf=NULL;
			    int    *flag = (int *) svar->val;
			    if (!win)
				    return;
			    if (!(*argv) || sscanf(*argv, "%d", flag) < 1) {
				    buf = (char *) malloc(sizeof(char) * (strlen(PROMPT) + strlen(svar->name) + 56));

				    sprintf(buf, PROMPT "%s currently set to %d", svar->name, *flag);
				    fl_addto_browser(win->chanwin->brow2, buf);
				    free(buf);
				    return;
			    }else{
			    buf = (char *) malloc(sizeof(char) * (strlen(PROMPT) + strlen(svar->name) + 56));
			    sprintf(buf, PROMPT "%s now set to %d", svar->name, *flag);
			    fl_addto_browser(win->chanwin->brow2, buf);
			    }
			     free(buf);
			    return;
		    }

	    case SET_STR:{
			    char   *buf;
			    size_t  ll;
			    char  **flag = (char **) svar->val;

			    buf = (char *) malloc(sizeof(char) * MAXLINE);

			    if (!buf) {
				    err_ret("%s %s", __FILE__, __LINE__);
				    return;
			    }
			    if (!(*argv)) {
				    if (!win)
					    {free(buf);return;}
				    sprintf(buf, PROMPT "%s currently set to \"%s\"", svar->name, *flag);
				    fl_addto_browser(win->chanwin->brow2, buf);
			    } else{
			     	char *ptr;
				*buf = '\0';
			    	strcat(buf, *argv);
			    	while (*++argv) {
				    strcat(buf, " ");
				    strcat(buf, *argv);
			    	}
			    	
				ll = strlen(buf) - 1;
			    	ptr=buf;
				if (*buf == '"' && *(buf + ll) == '"')	/* "bla bla bla" or "" */
				    *(ptr++ + ll) = '\0';
			    	*flag = *ptr == '\0' ? "" : strdup(ptr);
			    	if (!win)
				    {free(buf);return;}
				else{
			    	sprintf(buf, PROMPT "%s now set to \"%s\"",
				    svar->name, *flag);
			    	fl_addto_browser(win->chanwin->brow2, ptr);
				}
			    }/* else*/
			    free(buf);
			    return;
		    }

	    default:{
		fprintf(stderr, "%s (%d) Not implemented %d\n", 
		__FILE__, __LINE__,svar->type);
		 break;
		    }
	}	/*switch */
	return;
}
static int set_binary( /*SetVars *stvars, */ char *var, int n)
{
	register int low, high, mid, cond;
	size_t ll=strlen(var);
	low = 0;
	high = n - 1;
	while (low <= high) {
		mid = (low + high) / 2;
		if ((cond = strncasecmp(var, setvars[mid].name,ll)) < 0)
			high = mid - 1;
		else if (cond > 0)
			low = mid + 1;
		else
			return mid;
	}
	return -1;
}

static const char *counter_int_filter(FL_OBJECT * ob, double val, int prec)
{
	static char buf[32];

	sprintf(buf, "%d", (int) val);
	return buf;
}

static void make_folder(FL_OBJECT * folder)
{
	FD_strings *stringform = create_form_strings();
	FD_flags *flagform = create_form_flags();
	FD_numbers *numberform = create_form_numbers();
	int     nvars = sizeof(setvars) / sizeof(SetVars);
	register int i;

	fl_hide_object(flagform->stat);
	for (i = 0; i < nvars; i++)
		switch (setvars[i].type) {
		    case SET_BOOL:
			    fl_add_browser_line(flagform->browser, setvars[i].name);
			    break;
		    case SET_USHORT:
		    case SET_USMALL:
		    case SET_INT:
		    case SET_UINT:
			    fl_add_browser_line(numberform->browser, setvars[i].name);
			    break;
		    case SET_UCHAR:
		    case SET_STR:
			    fl_add_browser_line(stringform->browser, setvars[i].name);
			    break;
		    default:
			    fprintf(stderr, "%s (%d) Unimplemented?\n", __FILE__, __LINE__);
			    break;
		}
	numberform->input->u_ldata = (long) XC_xterm;
	fl_set_input_return(numberform->input, FL_RETURN_END);
	fl_set_object_prehandler(numberform->input, set_cursor);
	numberform->input->u_vdata = (void *) folder;
	fl_set_browser_fontsize(numberform->browser, FL_NORMAL_SIZE);
	fl_set_browser_fontstyle(numberform->browser, FL_TIMES_STYLE);
	fl_set_counter_step(numberform->counter, 1, 5);
	fl_set_counter_filter(numberform->counter, counter_int_filter);

	flagform->input->u_ldata = (long) XC_xterm;
	flagform->input->u_vdata = (void *) folder;
	fl_set_input_return(flagform->input, FL_RETURN_END);
	fl_set_object_prehandler(flagform->input, set_cursor);

	fl_set_browser_fontsize(flagform->browser, FL_NORMAL_SIZE);
	fl_set_browser_fontstyle(flagform->browser, FL_TIMES_STYLE);

	stringform->input->u_ldata = (long) XC_xterm;
	stringform->input->u_vdata = (void *) folder;
	fl_set_input_return(stringform->input, FL_RETURN_END);
	fl_set_object_prehandler(stringform->input, set_cursor);
	fl_set_browser_fontsize(stringform->browser, FL_NORMAL_SIZE);
	fl_set_browser_fontstyle(stringform->browser, FL_TIMES_STYLE);

	fl_addto_tabfolder(folder, "Strings", stringform->strings);
	fl_addto_tabfolder(folder, "Flags", flagform->flags);
	fl_addto_tabfolder(folder, "Numeral", numberform->numbers);
}

void    do_setup(void)
{

	static int busy = 0;

	if (busy)
		return;
	else {
		FD_setup *form = create_form_setup();

		busy = 1;
		make_folder(form->folder);
		fl_set_object_bw(form->folder, -2);
		form->done->u_ldata = (long) &busy;
		fl_set_form_atclose(form->setup, atclose_dec_count, (void *) &busy);
		fl_show_form(form->setup, FL_PLACE_GEOMETRY, FL_FULLBORDER,
			     sula_NAME sula_VERSION ": Setup options");
		fl_do_forms();
	}
	return;
}

void    set_cb(FL_OBJECT * ob, long data)
{
	static SetVars *svar = NULL;	/* static! */
	static int i = -1;	/*static! */
	static int previous = -1;
	union {
		FD_strings *stringform;
		FD_flags *flagform;
		FD_numbers *numberform;
		FD_setup *setup;
	} u_form;

	if (data > 9 && data < 20)
		u_form.stringform = (FD_strings *) ob->form->fdui;
	else if (data > 19 && data < 30)
		u_form.flagform = (FD_flags *) ob->form->fdui;
	else if (data > 29 && data < 40)
		u_form.numberform = (FD_numbers *) ob->form->fdui;
	else if (data < 10)  /*if(data!=0) -->done */
		u_form.setup = (FD_setup *) ob->form->fdui;
	else 
		return;
	switch (data) {

/*----------------------------------------------*/
/* (flag) light button                          */
/*----------------------------------------------*/
	    case 22:{
			    char   *s;

			    if (i < 1)
				    return;	/* bug? */
			    previous = fl_get_active_folder_number((FL_OBJECT *) u_form.flagform->input->u_vdata);
			    svar = &setvars[i];
			    if (fl_get_button(u_form.flagform->stat))
				    *((int *) svar->val) |= svar->flag;
			    else
				    *((int *) svar->val) &= ~svar->flag;
			    s = *((int *) svar->val) & svar->flag ? "now set on" : "now set off";
			    fl_set_object_label(u_form.flagform->stat, *((int *) svar->val) & svar->flag ? "on" : "off");
			    fl_set_object_label(u_form.flagform->status, s);
			    break;
		    }
	    case 31:{		/* counter */
			    char    buf[15];

			    sprintf(buf, "%d", (int) fl_get_counter_value(ob));
			    fl_set_input(u_form.numberform->input, buf);
			    break;
		    }
	    case 32:		/* numberform, ok */
		    fl_trigger_object(u_form.numberform->input);
		    break;
	    case 11:		/* clear input */
		    fl_set_input(u_form.stringform->input, "");
	    case 0:/* done*/
	    #warning (1/3/1998)forms on folder not freed!!
		    fl_hide_form(u_form.setup->setup);
		    fl_free_form(u_form.setup->setup);
		    *((int *) ob->u_ldata) = 0;
		    break;
	    default:
		    break;
/*----------------------------------------------*/
/*      browser selection                       */
/*----------------------------------------------*/

	    case 15:
	    case 25:
	    case 35:
		    {
			    char   *var;
			    int     n;
			    int     nvars = sizeof(setvars) / sizeof(SetVars);
			    char   *buf = NULL;

			    n = fl_get_browser(ob);
			    if (n < 1)
				    return;
			    var = (char *) fl_get_browser_line(ob, n);
			    i = set_binary(var, nvars);
			    if (i < 0) {	/*impossible; bug! */
				    buf = (char *) malloc(sizeof(char) * (strlen(var) + 27));

				    if (!buf) {
					    err_ret("%s %s", __FILE__, __LINE__);
					    return;
				    }
				    if (gflags & BEEP_ERR) fl_ringbell(0);
				    sprintf(buf, "No such variable \"%s\"", var);	/* bug */
			    }
			    if (data == 25) {
				    fl_hide_object(u_form.flagform->stat);
				    previous = fl_get_active_folder_number((FL_OBJECT *) u_form.flagform->input->u_vdata);
				    if (buf) {
					    fit_object_label(u_form.flagform->status, buf);
					    return;
				    }

			    }
			    else if (data == 15) {
				    previous = fl_get_active_folder_number((FL_OBJECT *) u_form.stringform->input->u_vdata);
				    if (buf) {	/*impossible; bug! */
					    fit_object_label(u_form.stringform->status, buf);
					    return;
				    }
			    }
			    else {
				    previous = fl_get_active_folder_number((FL_OBJECT *) u_form.numberform->input->u_vdata);
				    if (buf) {	/*impossible; bug! */
					    fit_object_label(u_form.numberform->status, buf);
					    return;
				    }
			    }
			    svar = &setvars[i];
			    switch (svar->type) {
				case SET_BOOL:{
						char   *s = 0;

						fl_set_object_label(u_form.flagform->status, "on/off");
						fl_show_object(u_form.flagform->stat);
						fl_set_button(u_form.flagform->stat, *((u_long *) svar->val) & svar->flag);
						s = *((u_long *) svar->val) & svar->flag ? "on" : "off";
						fl_set_object_label(u_form.flagform->stat, s);
						fl_set_input(u_form.flagform->input, s);

						return;
					}
				case SET_UCHAR:{
						char    buf[10];

						sprintf(buf, "%c", *((u_char *) svar->val));
						fl_set_input(u_form.stringform->input, buf);
						fl_set_object_label(u_form.stringform->status, "character");
						return;
					}
				case SET_USMALL:{
						/* u_char */
						char    buf[10];

						u_short *flag = (u_short *) svar->val;

						*flag = (u_char) (*flag);
						sprintf(buf, "%d", *flag);
						fl_set_input(u_form.numberform->input, buf);
						fl_set_object_label(u_form.numberform->status, "small positive number");
						fl_set_counter_bounds(u_form.numberform->counter, 0, 255);
						fl_set_counter_value(u_form.numberform->counter, *flag);
						return;
					}

				case SET_USHORT:{
						char    buf[10];

						sprintf(buf, "%d", *((u_short *) svar->val));
						fl_set_input(u_form.numberform->input, buf);
						fl_set_object_label(u_form.numberform->status, "short positive number");
						fl_set_counter_bounds(u_form.numberform->counter, 0, USHRT_MAX);
						fl_set_counter_value(u_form.numberform->counter, *((u_short *) svar->val));
						return;
					}
				case SET_INT:{
						char    buf[13];

						sprintf(buf, "%d", *((u_int *) svar->val));
						fl_set_input(u_form.numberform->input, buf);
						fl_set_object_label(u_form.numberform->status, "positive number");
						fl_set_counter_bounds(u_form.numberform->counter, 0, UINT_MAX);
						fl_set_counter_value(u_form.numberform->counter, *((u_int *) svar->val));
						return;
					}
				case SET_STR:{
						char  **flag = (char **) svar->val;

						fl_set_input(u_form.stringform->input, *flag);
						fl_set_object_label(u_form.stringform->status, "string");
						return;
					}
				default:
					fprintf(stderr, "unknown type!");
					break;
			    }	/*switch */
			    break;
		    }		/* case 5 */

/*----------------------------------------------*/
/*      input  line                             */
/*----------------------------------------------*/
	    case 10:
	    case 20:
	    case 30:{
			    char   *val;

			    if (previous != fl_get_active_folder_number((FL_OBJECT *) ob->u_vdata)) {
				    fl_set_input(ob, "");
				    svar = NULL;
			    }
			    if (svar == NULL)
				    return;
			    val = (char *) fl_get_input(ob);
			    /*if(!(*val)) return; */

			    switch (svar->type) {
				case SET_BOOL:{
						char    buf[20];

						if (!val || !(val = clean(val)))
							break;
						if (!strncasecmp(val, "off", 2))
							*((u_long *) svar->val) &= ~svar->flag;
						else if (!strncasecmp(val, "on", 2))
							*((u_long *) svar->val) |= svar->flag;
						else if (!strncasecmp(val, "toggle", 1))
							*((u_long *) svar->val) = (*((u_long *) svar->val) & svar->flag) ?
							 *((u_long *) svar->val) & ~svar->flag : *((u_long *) svar->val) | svar->flag;
						else {
							if (gflags & BEEP_ERR) fl_ringbell(0);
							fl_set_object_label(u_form.flagform->status, "set: value must be on, off, or toggle");
							fl_set_input(ob, "");
							break;
						}
						fl_set_button(u_form.flagform->stat, *((u_long *) svar->val) & svar->flag);
						sprintf(buf, "now set %s", *((u_long *) svar->val) & svar->flag ? "on" : "off");
						fl_set_object_label(u_form.flagform->status, buf);
						fl_set_object_label(u_form.flagform->stat,*((u_long *) svar->val) & svar->flag ? "on" : "off");
						fl_set_input(ob, "");
						break;
					}
				case SET_UCHAR:{
						/* any char , no numbers<0 */
						char    buf[20];
						char   *flag;

						if (!val || !(val = clean(val)))
							break;
						flag = (u_char *) svar->val;	/* must be >0 */
						sscanf(val, "%c", flag);
						sprintf(buf, "now set to %c", *flag);
						fl_set_object_label(u_form.stringform->status, buf);
						fl_set_input(ob, "");
						break;
					}
				case SET_USMALL:{
						/* u_char */
						char    buf[20];
						unsigned short *flag;
						unsigned ff;
						if (!val)
							break;
						flag = (u_short *) svar->val;
						*flag = (u_char) (*flag);
						sscanf(val, "%u", &ff);
						*flag = (u_char) ff;
						sprintf(buf, "now set to %d", *flag);
						fl_set_object_label(u_form.numberform->status, buf);
						fl_set_counter_bounds(u_form.numberform->counter, 0, (double) UCHAR_MAX);
						fl_set_counter_value(u_form.numberform->counter, *flag);
						fl_set_input(ob, "");
						break;
					}

				case SET_USHORT:{
						char    buf[25];
						unsigned ff;
						u_short *flag;

						if (!val /* || !(val=clean(val)) */ )
							break;
						flag = (u_short *) svar->val;
						sscanf(val, "%u", &ff);
						*flag = (u_short) ff;
						sprintf(buf, "now set to %d", *flag);
						fl_set_object_label(u_form.numberform->status, buf);
						fl_set_counter_bounds(u_form.numberform->counter, 0, (double) USHRT_MAX);
						fl_set_counter_value(u_form.numberform->counter, *flag);
						fl_set_input(ob, "");
						break;
					}
				case SET_INT:{
						char    buf[30];
						int    *flag;

						if (!val)
							break;
						flag = (int *) svar->val;
						sscanf(val, "%d", flag);
						sprintf(buf, "now set to %d", *flag);
						fl_set_object_label(u_form.numberform->status, buf);
						fl_set_counter_bounds(u_form.numberform->counter, 0, UINT_MAX);
						fl_set_counter_value(u_form.numberform->counter, *flag);
						fl_set_input(ob, "");
						break;
					}

				case SET_STR:{
						char   *buf;
						char  **flag = (char **) svar->val;

						if (!val)
							*flag = "";
						else
							*flag = strdup(val);
						buf = (char *) malloc(sizeof(char) * (strlen(*flag) + 20));
						if (!buf) {
							err_ret("%s %s", __FILE__, __LINE__);
							break;
						}
						sprintf(buf, "now set to \"%s\"", *flag);
						fit_object_label(u_form.stringform->status, buf);
						fl_set_input(ob, "");
						break;
					}
				default:	/*fl_set_object_label(form->status,"unknown type"); break; */
					fprintf(stderr, "unknoen type %d", svar->type);
					break;
			    }	/*switch(svar->type) */

		    }		/* case 0 */

	}			/* swicth data */

}
