
/* 
 * main.c: The main program for sula.   */

/* 
 * Author: Tano Fotang 1997, 1998
 * (fotang@techie.com)
 * 
 * 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.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program; see the file COPYING.  If not, write to the Free
 * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 * 
 */

#include <forms.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/wait.h>
#include <time.h>
#include <sys/resource.h>
#include <ctype.h>
#include "config.h"
#include "aux.h"
#include "nicks.h"
#include "sula.h"
#include "servers.h"
#include "chanwin.h"
#include "script_gui.h"
#include "script.h"
#include "global.h"
#include "dcc_gui.h"
#include "dcc.h"
#include "setting.h"
#include "parser.h"
#include "ignore.h"
#include "cmd.h"
#include "etc.h"
#include "lag.h"
#include "idle_cb.h"
#include "attribs.h"


#include "server_tool.xpm"
#include  "exit.xpm"
#include  "win.xpm"
#include  "userguide.xpm"
#include  "setup.xpm"
#include  "script.xpm"

FD_main_form   *main_form;
extern FD_scriptcontrol *script_form;
extern FD_serverlist *server_tool;
extern ActiveDCC *aActiveDCC;
static void sig_handler(int);
extern int load_bi_cmds(void);
extern int load_serverlist(const char *);
static int main_brow_col, main_brow_text_col,main_brow_fontstyle,
	main_brow_fontsize,main_brow_selected_col;

int     main(int argc, char **argv)
{
	
	char    ddir[MAXPATHLEN];		/* e.g. /usr/local/lib/sula*/ 
	static void check_cpw(const char *ddir);
	static int main_posthandler(FL_OBJECT *, int, FL_Coord, FL_Coord,
 		int, void *);
	int     n, revision;
	FL_EditKeymap ekm;
	
	static void read_object_attribs(Display *d, Colormap cm);
	
	static void read_res_string(void);
	static void read_res_flags(void);
	char Cmdchar[3];
	char Ml_nl[32];
			
	FL_resource res[]= {
	/* the rest will be read in later */
       	{"ConnectTimeout", "NumCLASS",FL_INT, &connect_timeout, "20"}, /* secs*/
	{"MaxNicknameLength","NumCLASS",FL_INT,&MaxNickLen,"20"},
	{"MaxChannelNameLength","NumCLASS",FL_INT,&MaxChanLen,"20"},
	{"DccTimeout", "NumCLASS", FL_INT, &dcc_timeout,"4"},	/* 4 mins */
	{"LagFrequency","NumCLASS", FL_INT, &lag_tmout,"120"},	/* seconds*/
	{"TooltipTimeout","NumCLASS",FL_INT, &tips_tmout,"1000"},/* tmout for tipper in millisecs */
	{"GetValueTimeout","NumCLASS",FL_INT,&timeout, "120"},	/* 120 sec */
	{"MaxChannelGoto","NumCLASS",FL_INT, &max_go, "5"},
	{"CommandCharacter","charCLASS",FL_STRING, Cmdchar, "/",2},
	{"MultilineStart","charCLASS",FL_STRING, Ml_nl, "@i\t", 31},
	{"MaxSendBuffer","NumCLASS",FL_INT, &max_sendbuf,"2048"},

	{"Directory.Libraries","stringClass", FL_STRING,ddir,
	#ifdef LIB_DIR
		LIB_DIR
	#else
		"/usr/local/lib/sula"
	#endif
	 ,MAXPATHLEN}
	};


	/* -DDUMP_CORE if u want core dump */
	#ifndef DUMP_CORE
	struct rlimit rl;
	rl.rlim_cur=0;
	rl.rlim_max=0;
	if(setrlimit(RLIMIT_CORE,&rl)) err_ret("setrlimit error");
	#endif
		/* make sure the distribution is consistent wrt version numbers */
    if (FL_INCLUDE_VERSION != fl_library_version(&n, &revision))
    /* version: n */
    {
        fprintf(stderr, "header/library version mismatch\n");
        fprintf(stderr, "   Header: %d.%d\n", FL_VERSION, FL_REVISION);
        fprintf(stderr, "  Library: %d.%d\n", n, revision);
        exit(1);
    }

	#ifndef SA_RESTART
	fprintf(stderr,"Warning: SA_RESTART not defined- interrupted sys calls\n");
	#endif
	if ( 
	Signal(SIGCHLD, sig_handler) == SIG_ERR ||
	Signal(SIGSEGV, sig_handler) == SIG_ERR ||
	Signal(SIGPIPE, sig_handler) == SIG_ERR
	) err_sys("signal error");
	server_tool=NULL;
	numTree=NULL;
	script_form=NULL;
	ignore_form = NULL;

	fl_set_border_width(-1);
	fl_setpup_default_fontsize(12);
	fl_setpup_default_fontstyle(FL_BOLD_STYLE);
	fl_initialize(&argc, argv, "sula", 0,0/*cmdopt, sizeof(cmdopt)/sizeof(FL_CMD_OPT)*/);
	fl_get_app_resources(res, sizeof(res)/sizeof(FL_resource));
	memset(&ekm, 0, sizeof(ekm));
	ekm.moveto_eol = 5;	/* ctrl-E; */
	ekm.del_prev_char = 8;	/*  ctrl-H*/
	ekm.del_next_char = 127;	/* delete*/
	fl_set_input_editkeymap(&ekm);

	Name = (char *) fl_whoami();
	if (!Name) Name = sula_NAME;
	sula_lib =ddir/*strdup(sula_DIR)*/;
	tmp_win = NULL;
	no_of_cmds = 0;
	win_count=0;	/* no of chnnael wins*/
	winstruct =NULL;
	s_pipe=NULL;
	sp_count=0;
	aNickList=NULL;
	iNickListCount=0;
	aActiveDCC=NULL;
	iActiveDCC_count=0;

	event_setup();
	fprintf(stderr,"test.. %s? lag freq %d secs.\n", 
		sula_lib, lag_tmout/*,fl_setpup_maxpup(0)*/);
	
	dccchatwinStart = dccchatwinEnd =  malloc(sizeof(DCCChatWin));
	if (dccchatwinEnd == NULL) err_sys("%s %d error", __FILE__, __LINE__);

	chat_id = 0;		/*  chat in progress*/
	dcc_file_id = 0;	/* * file transfers in progress */
	dcc_get_id = 0;
	chatsentStart = chatsentEnd = malloc(sizeof(ChatReqSent));
	if (chatsentEnd == NULL)  err_sys("%s %d error", __FILE__, __LINE__);
	chatreqStart = chatreqEnd =  malloc(sizeof(ChatReqRecvd));
	if (chatreqEnd == NULL) err_sys("%s %d error", __FILE__, __LINE__);
	filegetStart = filegetEnd =  malloc(sizeof(DCCFileR));
	if (filegetEnd == NULL) err_sys("%s %d error", __FILE__, __LINE__);
	filesendStart = filesendEnd =  malloc(sizeof(DCCFileS));
	if (filesendEnd == NULL) err_sys("%s %d error", __FILE__, __LINE__);
	DCCfileStart = DCCfileEnd =  malloc(sizeof(DCCFile));
	if (DCCfileEnd == NULL) err_sys("%s %d error", __FILE__, __LINE__);
	cmdsentStart = cmdsentEnd = (CmdSent *) malloc(sizeof(CmdSent));
	if (!cmdsentStart) err_sys("%s %d error", __FILE__, __LINE__);
	cmdonconStart = cmdonconEnd = cmdonconEnd =malloc(sizeof(CmdOnCon));
	if (!cmdonconStart) err_sys("%s %d error", __FILE__, __LINE__);
	ignoreEnd = ignoreStart =  malloc(sizeof(Ignore));
	if (ignoreStart == NULL) err_sys("%s %d error", __FILE__, __LINE__);
	servWin=NULL;
	servTree = servFdTree = NULL;
	cmdTree = NULL;
	bmTree = NULL;		
	bm_id = 0;
	keys=NULL;

	senderStart=malloc(sizeof(Sender));
	if(senderStart==NULL) err_sys("%s %d error", __FILE__, __LINE__);
	senderStart->left = senderStart->right=senderCur = senderStart;
	chanStart = chanEnd = malloc(sizeof(gChannel));
	if (chanEnd == NULL) err_sys("%s %d error", __FILE__, __LINE__);

	histStart = (History *) malloc(sizeof(History));
	if (histStart == NULL) 	err_sys("%s %d error", __FILE__, __LINE__);
	histStart->left = histStart->right = histCur = histStart;
	HistSize = 0;
	mainhistStart = (History *) malloc(sizeof(History));
	if (mainhistStart == NULL)  err_sys("%s %d error", __FILE__, __LINE__);
	mainhistStart->left = mainhistStart->right = mainhistCur = mainhistStart;
	mainHistSize = 0;
	
	check_cpw(sula_lib);
	
	/* read X resource files----------------- */
	cmdchar = Cmdchar[0];
	if(isspace(cmdchar)) cmdchar='/';
	ml_nl	= Ml_nl;
	read_object_attribs(fl_display, DefaultColormap(
	 fl_display, DefaultScreen(fl_display)) );
	read_res_string();
	gflags=ALL_GFLAGS;
	sflags = S_ALL;
	read_res_flags();

	if (access(gethostbynameprogram, X_OK) < 0){
	 	fprintf(stdout,
		"\nNotice \E[1mThe specified program \E[4m%s\E[m\E[1m "
		"is not executable. "
		"Please Type \"/help set force_connection\" for more info.\E[m\n",
		gethostbynameprogram);
		
	}

	/*---------------------------------*/
	main_form = create_form_main_form();
	fl_set_browser_fontsize(main_form->browser,main_brow_fontsize);
	fl_set_browser_fontstyle(main_form->browser,main_brow_fontstyle);
	fl_set_object_color(main_form->browser,main_brow_col,
		main_brow_selected_col);
	fl_set_object_lcolor(main_form->browser,main_brow_text_col);

	fl_set_pixmapbutton_data(main_form->servers, server_tool_xpm);
	fl_set_pixmapbutton_data(main_form->quit, exit_xpm);
	fl_set_pixmapbutton_data(main_form->newwin, win_xpm);
	fl_set_pixmapbutton_data(main_form->setup, setup_xpm);
	fl_set_pixmapbutton_data(main_form->uguide, userguide_xpm);
	fl_set_pixmapbutton_data(main_form->script,script_xpm);

	fl_set_object_bw(main_form->browser, -2);
	fl_set_input_return(main_form->main_input, FL_RETURN_END);
	main_form->main_input->u_ldata = (long) XC_xterm;
	fl_set_object_prehandler(main_form->main_input, set_cursor);
	fl_set_object_bw(main_form->main_box, -2);
	
	fl_set_object_posthandler(main_form->servers,main_posthandler);
	fl_set_object_posthandler(main_form->quit,main_posthandler);
	fl_set_object_posthandler(main_form->newwin,main_posthandler);
	fl_set_object_posthandler(main_form->setup,main_posthandler);
	fl_set_object_posthandler(main_form->uguide,main_posthandler);
	fl_set_object_posthandler(main_form->script,main_posthandler);
	
	if (load_ctcp_cmds()!=0) {
		err_sys("cant load ctcp commands");
	}
	if (load_bi_cmds()) {
		err_sys("cant load commands");
	}
	if (1) {
		/* try loading servers and bookmarks from ~/.sula/.
		if this fails, try directory specified in X resource file.
		read history from ~/.sula/.
		*/
		char   *path;
		char    buf[512];/* MAXPATHLEN + 1];*/
		
		if (!(path = getenv("HOME")))
			path = strdup(".");
		sprintf(buf, "%s/%s", path, P_HOME);
		if (access(buf, F_OK) < 0){
			if(errno==ENOENT){
			   fprintf(stderr," creating %s...", buf);
			   if (mkdir(buf, DIR_MODE) < 0) {
				fl_show_alert(sula_NAME sula_VERSION ": Error", 
				buf, strerror(errno), 1);
				exit(-1);
			   }
			   fprintf(stderr,"ok\n");
			}else{
			      fl_show_alert(sula_NAME sula_VERSION ": Error", 
			      buf, strerror(errno), 1);
				exit(-1);
			}

		}
		path = strdup(buf);
		sprintf(buf, "%s/%s", path, P_NICKNAMES);
		#if DEBUG
		fprintf(stderr,"loading nicknames from \E[4m%s\E[m."
		 " Use /ln to list\n",buf);
		#endif
	 if(load_nicks(buf)){
	 	err_ret("error getting nicks");
		if(iNickListCount==0){
			Nickcount i=new_nicklist("default");
			if(i<0) err_sys("error");
			aNickList[i].current=add_nick_to_list(i, Name);
		}
	 }
	 	#if DEBUG>2
		n=0;
	 	while(n<iNickListCount){
	 	  if(aNickList[n].label){
			 Nicks *p=aNickList[n].start->left;
			 fprintf(stderr,"\E[4m%s\E[m:\n",aNickList[n].label);
			 while(p!=aNickList[n].start){
			 	fprintf(stderr,"\t%s\n",p->nick);
				p=p->left;
			}
		  }
		  n++;
	  	}
		#endif
		sprintf(buf, "%s/%s", path, P_HISTORY);
		if(load_history(buf)) err_ret("%s", buf);
		sprintf(buf, "%s/%s", path, P_SERVERS);
		if (access(buf, R_OK) < 0){
			perror(buf);
			sprintf(buf, "%s/%s", sula_lib, P_SERVERS);
			fprintf(stderr,"Will try %s\n", buf);
		}
		#if DEBUG
		fprintf(stderr,"loading servers from \E[4m%s\E[m\n",buf);
		#endif
		if ((n = load_serverlist(buf))){
			fl_show_alert(sula_NAME sula_VERSION ": Server list", 
			buf, strerror(n), 1);
		}
		sprintf(buf, "%s/%s", path, P_BOOKMARKS);
		if (access(buf, R_OK) < 0){
			perror(buf);
			sprintf(buf, "%s/%s", sula_lib, P_BOOKMARKS);
		}
		#if DEBUG
		fprintf(stderr,"loading bookmarks from \E[4m%s\E[m\n",buf);
		#endif
		if (load_bookmarks(buf, &bmTree))
			fl_show_alert(sula_NAME sula_VERSION ": Bookmarks", 
			buf, strerror(errno), 1);
		free(path);
		
	}

	/*------------------------------------*/
	main_form->FwdHist->u_ldata = (long) 0L;
	fl_set_idle_callback(idle_cb, 0);
	fl_set_form_minsize(main_form->main_form, 475, 455);
	fl_set_form_maxsize(main_form->main_form, 675, 455);
	fl_show_form(main_form->main_form, FL_PLACE_FREE, FL_FULLBORDER, 
		sula_NAME sula_VERSION ": Control");
	gflags |= CTRL_WIN_SHOWN;
	n = strlen(ddir);
	if (*(ddir + n - 1) == '/')
		*(ddir + --n) = '\0';
	if (n == 0)
		n = 1;
	warranty_file = (char *) malloc(sizeof(char) * (n + 16));
	sprintf(warranty_file, "%s/Bugs", *ddir ? ddir : ".");
	if (access(warranty_file, R_OK) != 0){
		fl_show_alert(sula_NAME " Error",warranty_file, 
		strerror(errno), 1);
		/*exit(-1);*/
	}
	else
		fl_load_browser(main_form->browser, warranty_file);
	
	bzero((char *) &me, sizeof(me));
	if (gethostname(host, sizeof(host)) < 0){ 
		err_ret("Unable to get your host name. DCC may not work.");
		me.sin_addr.s_addr=0;
	}else
		if ((me.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE){ 
			struct hostent *hp;
			if (!(hp=gethostbyname(host))){
				herror("unable to get your host by name.");
				fprintf(stderr," DCC may not work.\n");
				me.sin_addr.s_addr=0;
			}
			else{
				bcopy(hp->h_addr, (char *) &me.sin_addr, hp->h_length);
				#if DEBUG
				fprintf(stderr, "You are %s (%s)\n",
				host, inet_ntoa(me.sin_addr));
				#endif
			}
	   	}
	while (fl_do_forms() != main_form->quit);
	return 0;

}

static void read_object_attribs(Display *disp, Colormap cmap){
#define BROW_COL	FL_FREE_COL2
#define BROW2_COL	(FL_FREE_COL2+1)
#define SEL_COL		(FL_FREE_COL2+2)
#define SEL2_COL	(FL_FREE_COL2+3)
#define TEXT_COL	(FL_FREE_COL2+4)
#define TEXT2_COL	(FL_FREE_COL2+5)
#define INPUT_COL	(FL_FREE_COL2+6)
#define MAIN_BROW_COL	(FL_FREE_COL2+7)
#define MAIN_BROW_TEXT_COL	(FL_FREE_COL2+8)
#define MAIN_BROW_SEL_COL	(FL_FREE_COL2+9)
#define TARGET_COL		(FL_FREE_COL2+10)
#define TARGET_LABEL_COL	(FL_FREE_COL2+11)
typedef struct TRes{
	int type;	/* color, style.. */
	int *var;
	int (*func)(const char *);	/* conversion function */
	char *name;
	char *defval;
	union{
	int int_defval;
	FL_COLOR index;	/* FL_COLOR if colormap index has to be changed */
	}spec;
	int nbytes;
}Res;
#define COLOR	0
Res vars[]={
	 {COLOR+1, &browser_fontsyle,  &str2fontstyle,  "Fontstyle.Browser", "times",
	 	{FL_TIMES_STYLE}, 127},
	 {COLOR+1, &browser_fontsize, &str2fontsize, "Fontsize.Browser","normal",
	 	{FL_NORMAL_SIZE}, 31},
	 {COLOR+1, &browser2_fontsyle, &str2fontstyle,"Fontstyle.Browser2","times",
	 	{FL_TIMES_STYLE}, 127},
	 {COLOR+1, &input_fontstyle, &str2fontstyle,"Fontstyle.Input","times",
	 	{FL_TIMES_STYLE}, 127},
	 {COLOR+1, &browser2_fontsize, &str2fontsize,"Fontsize.Browser2","normal",
	 	{FL_NORMAL_SIZE}, 31},
	{COLOR, &browser_colour, &str2color,"Color.Browser", "slateblue",
		{BROW_COL}, 31},
	{COLOR, &browser2_colour, &str2color,"Color.Browser2","bottom_bcol",
		{BROW2_COL}, 31},
	{COLOR, &browser_selected_colour, &str2color,"Color.Selection", "yellow",
		{SEL_COL},31},
	{COLOR, &browser2_selected_colour,&str2color,"Color.Selection2","blue",
		{SEL2_COL},31},
	{COLOR, &browser_textcolour, &str2color,"Color.BrowserText", "black",
		{TEXT_COL}, 31},
	{COLOR, &browser2_textcolour, &str2color,"Color.Browser2Text","white",
		{TEXT2_COL}, 31},
	{COLOR, &input_colour,&str2color,"Color.Input","black",
		{INPUT_COL},31},
	{COLOR, &main_brow_selected_col, &str2color,
		"Color.Selection.MainBrowser", "yellow",
		{MAIN_BROW_SEL_COL},31},
	{COLOR, &main_brow_col, &str2color,"Color.MainBrowser", "slateblue",
		{MAIN_BROW_COL}, 31},
	{COLOR, &main_brow_text_col, &str2color,"Color.MainBrowserText",
		"black",	{MAIN_BROW_TEXT_COL}, 31},
	{COLOR+1, &main_brow_fontstyle,  &str2fontstyle,  "Fontstyle.MainBrowser",
	  	"times", {FL_TIMES_STYLE}, 127},
	{COLOR+1, &main_brow_fontsize, &str2fontsize, "Fontsize.MainBrowser","normal",
	 	{FL_NORMAL_SIZE}, 31},

	{COLOR, &target_colour, &str2color,"Color.Target", "slateblue",
		{TARGET_COL}, 31},
	{COLOR, &target_colour2, &str2color,"Color.TargetLabel",
		"white",	{TARGET_LABEL_COL}, 31},
	{COLOR+1, &target_fontsyle,  &str2fontstyle,  "Fontstyle.Target",
	  	"normal", {FL_TIMES_STYLE}, 127},
	{COLOR+1, &target_fontsize, &str2fontsize, "Fontsize.Target","normal",
	 	{FL_NORMAL_SIZE}, 31},
	
	{0,NULL,NULL,NULL,0,{0},0}
};
Res *p=vars;
char *name;
  while(p->var){
	name=(char *)fl_get_resource(p->name,"AttributeCLASS",FL_NONE,
		p->defval, NULL, p->nbytes);
	*(p->var)=(p->func)(name);
	if(*(p->var) <0)  
		if(p->type==COLOR){/* it isnt an xforms (FL_XXx) colour */
			if(!new_str2color(disp, cmap, p->spec.index, name)){ /* failed */
			    fl_show_alert(sula_NAME "Colour Error",name,
			   "Not found or bad RGB format. Using black.", 1);
			    *(p->var)=FL_BLACK;
			}
			else *(p->var)=p->spec.index;
		}
		else *(p->var)=p->spec.int_defval;
	p++;
  }
}

static void read_res_flags(void){
typedef struct TSula_set{
	char *name;
	u_long *flag ;	/* s|gflags*/
	int val;	/* e.g. AUTO_CHAT*/
	char *defval;	/* "1" or "0" */
}Sula_set;
Sula_set sula_set[]={
{"autochat", &gflags,AUTO_CHAT,"1"},
{"autochecklag", &gflags, AUTO_CHECKLAG, "1"},
{"autoget",&gflags, AUTO_GETFILE,"1"},
{"autoinvite",&gflags, AUTO_INVITE,"1"},
{"autorejoin",&gflags, AUTO_REJOIN,"1"},
{"beep_away",&gflags, BEEP_AWAY ,"1"},
{"beep_on_dcc",&gflags, BEEP_DCC,"1"},
{"beepOnClientError",&gflags,BEEP_ERR,"1"},
{"beepOnServerError",&gflags, BEEP_SERVER_ERR,"0"},
{"beepOnMessage",&gflags,BEEP_MSG,"0"},
{"encrypt",&gflags, ENCRYPT_MSG,"1"},
{"finger",&gflags,FINGER ,"1"},
{"finger_utmp",&gflags, FINGER_UTMP,"1"},
{"history",&gflags,HISTORY ,"1"},
{"ignoreBookmarkServer",&gflags, BKMRK_IG_SERVER,"1"},
{"inform_ignored",&gflags, INFORM_IGNORED,"1"},
{"match_caseless", &gflags,MATCH_CASELESS,"1"},
{"show_numeric",&gflags,SHOW_NUMERIC,"1"},
{"quote_multiline",&gflags,QUOTE_ML,"0"},
{"remove_on_forward",&gflags,RM_ON_FWD,"1"},
{"save_bookmarks",&gflags,SAVE_BOOKMARKS,"1"},
{"save_history",&gflags,SAVE_HISTORY,"1"},
{"show_raw_message",&gflags,SHOW_RAW_MSG,"0"},
{"show_tips",&gflags, SHOW_TIPS,"1"},
{"verbose_client",&gflags,VERBOSE_CLIENT,"1"},
{"verbose_ctcp",&gflags,VERBOSE_CTCP,"1"},
{"force_connection",&sflags,FORCE_CONNECTION,"0"},
{"extended_DCC",&sflags,EXTENDED_DCC,"1"},
{"external_gethost",&sflags, EXTERNALGETHOST, "1"},
/*{"s_action",&sflags, S_ACTION,"0"}, -->S_MSG */
{"s_chat",&sflags,S_CHAT,"0"},
{"s_ctcp_other",&sflags,S_CTCP_OTHER,"0"},
{"s_finger",&sflags,S_FINGER,"0"},
{"s_get",&sflags,S_FILEGET,"0"},
{"s_invite",&sflags,S_INVITE,"0"},
{"s_msg",&sflags,S_MSG,"1"},
{"s_notice",&sflags,S_NOTICE,"1"},
{"s_ping",&sflags, S_PING,"0"},
{"s_send",&sflags,S_FILESEND,"0"},
{"suppress_motd", &sflags, SUPPRESS_MOTD, "1"},
{NULL,NULL,0,NULL}
};
int flag_val;
Sula_set *p=sula_set;
	while(p->name){
		fl_get_resource(p->name,"BoolCLASS",FL_BOOL,
		p->defval, &flag_val,0);
		if(!flag_val)
			*(p->flag) &= ~p->val;
		p++;
	}

}

static void read_res_string(void){
typedef struct TRes{
	char **var;
	char *name;
	char *defval;
	int nbytes;
}Res;
Res vars[]={
	{&gethostbynameprogram,"Aux.GethostnameProgram","sulahp",255},
	{&quit_text,"QuitText", "See ya!", 127},
	{&chat_quit_text ,"ChatQuitText", "have to go. bye bye", 127},
	{&away_text ,"AwayText", "be back l8r..", 127},
	#if 0
	{&away2_text ,"AwayText2",  "what did i miss?",127},
	#endif
	{&finger_reply,"FingerReply","",255},
	{&userinfo ,"Userinfo",  "Running " sula_NAME "version " sula_VERSION, 255},
	{&fmt_priv_msg ,"Format.PrivateMessage","@C7[%H:%M.%S] <%n> %p", 127},
	{&fmt_pub_msg ,"Format.PublicMessage","@C7<%n> %p (%Z)", 127},
	{&fmt_pub_msg2, "Format.PublicMessage2","@C7<%n:%c> %p", 127},
	{&fmt_pub_msg3 ,"Format.PublicMessage3", "@C7(%n/%c) %p", 127},
	{&fmt_you_pub_msg ,"Format.Your.PublicMessage","<%n> %p", 127},
	{&fmt_you_priv_msg ,"Format.Your.PrivateMessage","->%c: %p", 127},
	{&fmt_pub_notice ,"Format.PublicNotice",  "@C7-%n- %p", 127},
	{&fmt_pub_notice2 ,"Format.PublicNotice2","@C7-%n:%c- %p", 127},
	{&fmt_pub_notice3 ,"Format.PublicNotice3","@C7(-%n/%c-) %p", 127},
	{&fmt_priv_notice ,"Format.PrivateNotice","@C7[%H:%M.%S] -%n- %p", 127},
	{&fmt_you_pub_notice ,"Format.Your.PublicNotice","-%n- %p", 127},
	{&fmt_you_priv_notice ,"Format.Your.PrivateNotice","->%c- %p", 127},
	{&fmt_pub_action ,"Format.PublicAction","Action: %n %p", 127},
	{&fmt_you_pub_action ,"Format.Your.PublicAction","Action: %n %p", 127},
	{&fmt_priv_action ,"Format.PrivateAction","@C7>Action: %n %p", 127},
	{&fmt_you_priv_action ,"Format.Your.PrivateAction","-> %c: Action: %n %p", 127},
	{&fmt_you_dccchat ,"Format.Your.ChatMessage","-> = %c = %p", 127},
	{&fmt_other_dccchat ,"Format.ChatMessage","@C7= %n = %p", 127},	
	{&fmt_topic ,"Format.Topic","%n has changed the topic on channel %c to %p", 127},
	{&fmt_chanmode ,"Format.ChannelMode","Mode change \"%p\" on channel %c by %n", 127},
	{&fmt_usermode ,"Format.UserMode","Mode change \"%p\" for %f by %n", 127},
	{&fmt_you_kick ,"Format.Your.Kick","@C3[%H:%M] %n has kicked you off %c (%p)", 127},
	{&fmt_other_kick ,"Format.Kick","@C2%f has been kicked off channel %c by %n (%p)", 127},
	{&fmt_you_join ,"Format.Your.Join","You have joined channel %c", 127},
	{&fmt_other_join ,"Format.Join","%n has just come into %c", 127},
	{&fmt_you_part ,"Format.Your.LeaveChannel","You have left channel %c", 127},
	{&fmt_other_part ,"Format.LeaveChannel","[%H:%M] %n has left channel %c", 127},
	{&fmt_signoff ,"Format.Signoff","%n has left IRC (%p)", 127},
	{&fmt_you_nick ,"Format.Your.Nickname","You are now known as %p", 127},
	{&fmt_other_nick ,"Format.Nickname","%n has transformed into %p of %h.", 127},
	{&fmt_invite ,"Format.Invite","%n is inviting you to channel %c.", 127},
	{&fmt_ignored ,"Format.Ignored","%p: You are being ignored.", 127},
	{&fmt_sed_pub,"Format.SED.Public", "@i@C2<%n> %p", 127},
	{&fmt_sed_priv,"Format.SED.Private", "@i@C2[%H:%M.%S]<%n> %p", 127},
	{&fmt_sed_your,"Format.SED.Your.Public", "E<%n> %p", 127},
	{&fmt_sed_nokey,"Format.SED.NoKey", "@i@C1<%n> %p [encrypted]", 127},
	{NULL, NULL, NULL,0}
};
Res *p=vars;
       while(p->var){
	*(p->var)=(char *)fl_get_resource(p->name,"FormatCLASS",FL_NONE,
		p->defval, NULL, p->nbytes);
	p++;
	}

	/*
	 
	 * for invites: same as fmt_invite;
	 * p=type of ignore, n=nick, h=emailaddr
	 * not used for IG_MISC !
	 */

}

static void check_cpw(const char *ddir)
{
/* 
 * detrmine the name of the copyrite file  */
	size_t  ll = strlen(ddir);
	if (ll == 0)
		ll = 1;
	copyright_file = (char *) malloc(sizeof(char) * (ll + 16));

	if (!copyright_file)
		err_sys("%s %d", __FILE__, __LINE__);
	sprintf(copyright_file, "%s/COPYING", *ddir ? ddir : ".");
	if (access(copyright_file, R_OK) < 0) {
		fl_show_alert(sula_NAME " Error", 
		copyright_file, strerror(errno), 1);
	}
}
static Ph ph;

static int main_posthandler(FL_OBJECT * ob, int event, FL_Coord mx, FL_Coord my,
 int key, void *xev)
{
	if ((gflags & SHOW_TIPS))
	{
	ph.ob = ob;
	ph.s = NULL;
	if (ob ==main_form->servers)
		ph.s="server tool";
	else if(ob==main_form->newwin)
		ph.s="open new channel window";
	else if(ob==main_form->script)
		ph.s="script/event tool";
	else if(ob==main_form->setup)
		ph.s="setup utility";
	else if(ob==main_form->uguide)
		ph.s="help utility";
	else if	(ob==main_form->quit)
		ph.s="quit | emergency exit";
	else return 0;
	if (event == FL_ENTER)
		timeoutID = fl_add_timeout((double) tips_tmout,
		 do_tips, (void *) &ph);
	else if (event == FL_LEAVE || event == FL_PUSH) {
		fl_hide_oneliner();
		if (timeoutID) {
			fl_remove_timeout(timeoutID);
			timeoutID = 0;
		}
	  }
	}
	return 0;
}


static void sig_handler(int signo)
{
	switch(signo){
	case SIGCHLD:
	{
		int status;
		pid_t  pid;
		char buf[80];
		 buf[0]='\0';

#warning 21/02/98 TODO check for non-reentrant functions! -ft22
		 /* Note: not only scripts are exiting! */
		 pid=waitpid(0, &status,WUNTRACED/*NOHANG*/);
		 if(pid<0) err_ret("waitpid");
		if(WIFEXITED(status))
		sprintf(buf,"process %d exited. Status= %d", pid, WEXITSTATUS(status));
		else
		if(WIFSIGNALED(status))
		sprintf(buf,"process %d killed. Signal %d", pid, WTERMSIG(status));
		else
		if(WIFSTOPPED(status)){
			int i;
			for(i=0;i<sp_count;i++)
			if(s_pipe[i].pid==pid){
			 s_pipe[i].status|=SCR_STOPPED;
			 break;
			 }
			 if(script_form){
				sprintf(buf, "process %d stopped. Signal:%d",
				pid, WSTOPSIG(status));
				#if 0
				/* reentrant! */
				if(script_form)
					{list_hooks(1);list_hooks(0);}
				#endif
			}
		
		}
		#if 0
		/* reentrant!!!!!*/
		if(script_form)	fit_object_label(script_form->status,buf);
		#endif
		#if DEBUG
			fprintf(stderr,PROMPT"%s\n",buf);
		#endif
		if (Signal(SIGCHLD, sig_handler) == SIG_ERR)/* reset */ 
			err_sys("Signal error");
	}
	break;
	case SIGSEGV:
		fprintf(stderr,"\n" sula_NAME sula_VERSION ": A bug."
		" Please inform "sula_EMAIL);
		/*cleanup();*//* may result in another SIGSEGV-->core dump now!*/
		exit(1);
	case SIGPIPE:
		#if DEBUG
		fprintf(stderr,PROMPT"Broken pipe\n");
		#endif
		break;
	default:
		break;
	}/* switch*/
}

