/* cmd_def.c	- more client commands

    (c) 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 details.

*/


#include <forms.h>
#include <errno.h>
#include "config.h"
#include "aux.h"
#include "nicks.h"
#include "sula.h"
#include "chanwin.h"
#include "global.h"
#include "parser.h"
#include "setting.h"
#include "dcc.h"
#include "cmd_def.h"
#include "cmd.h"
#if !defined(DONT_HAVE_GETOPT)
#include <getopt.h>
#endif

void nick(int argc,char **argv, Winstruct *win){
/* nick [+|-] | [<nick>] | [<help>] */
	char prev=1, buf[128];

	buf[0]=0;
	if(argc==1){
		if(!win->server) return;
		sprintf(buf,"Your nickname is %s",win->server->nick);
		fl_addto_browser(win->chanwin->brow2,buf);
		return;
	} else
	if( !strncasecmp(argv[1], "-help", 2) ){ 
		show_std_help(uppercase(argv[0]), NULL, win->chanwin);
		return;
	} else
	if( !strcmp(argv[1], "-") || !(prev=strcmp(argv[1], "+")) ){
		NickList *nl;
  		assert(win->server->iNick>=0);
  		nl=&aNickList[win->server->iNick];
  		if(nl->start!=nl->start->left){ /* list not empty */
  			Nicks *n;
			if(nl->start->left==nl->start->right)/*just 1 nick entry*/
				{fl_ringbell(0);return;}
			n=prev?nl->current->left:nl->current->right;
			if(n==nl->start) n=prev?n->left:n->right;
			#if 0
			nl->current= prev?nl->current->left:nl->current->right;
			if(nl->current==nl->start)
				nl->current= prev?nl->current->left:nl->current->right;
			#endif
			sprintf(buf,"NICK %s\n", n->nick);
		}
		else return;
	}else sprintf(buf,"NICK %s\n", argv[1]);
	sendto_server(win,buf);
}

static void save_browser(Winstruct * win, char *ptr,int save_all, int which)
{
	int     total, i;
	FILE   *fp = fopen(ptr, "w");
	FL_OBJECT *browser;

	if (fp == NULL) {
		char *pp=strerror(errno);
		char   *buf = (char *)malloc(sizeof(char)*(
				strlen(ptr) + strlen(pp)+3));
				sprintf(buf, PROMPT "%s %s", ptr, pp);
		fl_addto_browser(win->chanwin->brow2, buf);
		free(buf);
		if(gflags&BEEP_ERR) fl_ringbell(0);
		return;
	}
	browser= which==2? win->chanwin->brow2:win->chanwin->browser;
	total = fl_get_browser_maxline(browser);
	if (save_all)
		for (i = 1; i <= total; i++) {
			fputs(fl_get_browser_line(browser, i), fp);
			fputs("\n", fp);
		}
	else
		for (i = 1; i <= total; i++)
			if (fl_isselected_browser_line(browser, i)) {
				fputs(fl_get_browser_line(browser, i), fp);
				fputs("\n", fp);
			}
	fclose(fp);
}
static void load_file(Winstruct * win, char *ptr, int which)
{
#define BUFF	2048			
	int     n;
	char    buf[BUFF + 1];
	int     fd = open(ptr, O_RDONLY);
	FL_OBJECT *browser;

	if (fd < 0) {
		sprintf(buf, PROMPT "%s: %s", ptr, strerror(errno));
		fl_addto_browser(win->chanwin->brow2, buf);
		if(gflags&BEEP_ERR) fl_ringbell(0);
		return;
	}
	browser= which==2? win->chanwin->brow2:win->chanwin->browser;
	fl_freeze_form(win->chanwin->chanwin);
	while ((n = read(fd, buf, BUFF)) > 0) {
		buf[n - 1] = '\0';
		fl_addto_browser_chars(browser, buf);
	}
	close(fd);
	fl_unfreeze_form(win->chanwin->chanwin);
	if (n < 0) {
		sprintf(buf, PROMPT "%s: %s", ptr, strerror(errno));
		fl_addto_browser(win->chanwin->brow2, buf);
	}
}


void window(int argc,char **argv, Winstruct *win){
/*
	window [--clear 1|2]
	window --save 1|2 --filename <file> [--marked]
	window --load 1|2 --filename <f>
	window --radio 1|2|3|4|5   (quote|query|channel|dcc|echo)
	window --help
*/
	char *fname=NULL;
	int  radio=-1;
	char selected=0;
	int save=0, load=0;
	
	while(1){
		register int i;
		#if !defined(DONT_HAVE_GETOPT)
		int  option_index = 0; 
		static struct option long_options[] = {
			{"clear", 1,0, 'c'},
			{"save",1,0,'s'},
			{"load",1,0,'l'},
			{"filename",1,0,'f'},
			{"radio",1,0,'r'},
			{"marked",0,0,'m'},
			{"Selected",0,0,'m'},
			{"help",0,0,'h'},
			{"systemcomandlog",0,0,'L'},
			{0, 0, 0, 0}
		};
		i = getopt_long(argc, argv,"c:s:l:f:LSmh",
				long_options, &option_index);
		#else	
		i=getopt(argc, argv,"c:s:l:f:Lmh");
		#endif
		if (i == -1)
			break;
		
		switch (i) {
			case 'c':{
			   int brow=atoi(optarg);
			   if(brow==1) fl_clear_browser(win->chanwin->browser);
			   else if(brow==2) fl_clear_browser(win->chanwin->brow2);
			   else fputs("error", stderr);
			   break;
			}
			case 's':save=atoi(optarg); break;
			case 'l':load=atoi(optarg); break;
			case 'f':fname=optarg;break;
			case 'r':radio=atoi(optarg); break;
			case 'S':case 'm':selected=1; break;
			case 'L':fl_show_command_log(FL_FULLBORDER);break;
			case 'h':{
			      show_std_help(uppercase(*argv), NULL, win->chanwin);
			      return;
			      }
			default:break;
		}
	}
	optind=0;
	if(radio>0)
	switch(radio-1){
	case 0:
		fl_trigger_object(win->chanwin->r_quote);
		break;
	case 1:
		fl_trigger_object(win->chanwin->r_query);
		break;
	case 2: 
		fl_trigger_object(win->chanwin->r_channel);
		break;
	case 3: 
		fl_trigger_object(win->chanwin->r_dcc_chat);
		break;
	case 4:
		
		fl_trigger_object(win->chanwin->r_echo);

		break;
	default:break;
	}
	if(fname){
		if(load) load_file(win, fname, load);
		if(save) save_browser(win, fname, selected, save);
	}

}

void history(int argc,char **argv, Winstruct *win){
/*
	history -help
	history -clear
	history -load [filename]
	hist -reload
	histo -save [filname]
*/
	char *fname=NULL;
	char buf[512];
	static void clear_history(void);

	if(argc==1) return;
	if( !strncasecmp(argv[1], "-help", 2) ){ 
		show_std_help(uppercase(argv[0]), NULL, win->chanwin);
		return ;
	}
	if(!strncasecmp(argv[1], "-clear",2)){
		clear_history();
		return;

	}
	if(!strncasecmp(argv[1], "-load",2)) {
		fname=argv[2];
		if(!fname){
			if(! (fname=getenv("HOME")) ) fname=".";
			sprintf(buf,"%s/%s/%s", fname , P_HOME, P_HISTORY);
			fname=strdup(buf);
		}
		if(load_history(fname)) goto err;
		return;
	}
	if(!strncasecmp(argv[1], "-reload",2)){
			
		if(! (fname=getenv("HOME")) ) fname=".";
		 sprintf(buf,"%s/%s/%s", fname , P_HOME, P_HISTORY);
		fname=strdup(buf);
		
		clear_history();
#warning: to fix: what if cant load, but already cleared?
		if(load_history(fname)) goto err;
		return;
	}

	if(!strncasecmp(argv[1], "-save",2)){
		fname=argv[2];
		if(!fname){
			if(! (fname=getenv("HOME")) ) fname=".";
			sprintf(buf,"%s/%s/%s", fname , P_HOME, P_HISTORY);
			fname=strdup(buf);
		}
		sprintf(buf, "%s.bak", fname);
	       	rename(fname,buf);
		if(save_history(fname)) goto err;
		return;
	}
	fl_addto_browser(win->chanwin->brow2, PROMPT"history:"
	" unknown option (whatever it was that you typed");
	return;
err:
/* laziness rules*/
		{
		    sprintf(buf,"%s%s: %s",PROMPT, fname,strerror(errno));
		    fl_addto_browser(win->chanwin->brow2, buf);
		    if(gflags&BEEP_ERR) fl_ringbell(0);
		}
		return;
}

static void clear_history(void){
	History *p=histStart->right;
	int i;
	while(p!=histStart){
		p->left->right =p->right;
		p->right->left =p->left;
		free(p->line);
		p=p->right;
	}
	histStart->left=histStart->right=histCur=histStart;
	for(i=0;i<win_count;i++)
		if(winstruct[i].chanwin)
		    winstruct[i].chanwin->cmd_fwd->u_ldata=0L;
}

extern  int on_channel(const Server *s, const char *chan){
/* we're on this channel*/
	gChannel *p=chanStart;
	if(s->fd<0) return 0;
	while(p!=chanEnd)
		if( 
			 !strcasecmp( p->server, s->servname) &&
			 s->port==p->port && !strcasecmp(p->name, chan)
		)
			return 1;
		else p=p->next;
	return 0;
}

void join(int argc,char **argv, Winstruct *win){
/*
	/join		:get channel names using a form
	/join channel [password]
*/
	

if(argc==1){
		jjoin(win);
		return ;
}else{
	char *channame, buf[256];

	if( !strncasecmp(argv[1], "-help", 2) ){ 
		show_std_help(uppercase(argv[0]), NULL, win->chanwin);
		return ;
	}
	if(!win->server){
		fl_ringbell(0);
		fl_set_object_label(win->chanwin->WinStatusLine,
		   "You are not connected to a server");
		return;
	}
	if(!strncasecmp(argv[1], "-last", 2) ){
		if(win->lastPart->name){
		sprintf(buf, "JOIN %s %s\n", win->lastPart->name,
		        win->lastPart->key?win->lastPart->key:"");
	       	sendto_server(win,buf);
		}
		return;
	}
	
	if(!strncasecmp(argv[1], "-invited", 2)){
		if(win->server->lastInvite){
	       sprintf(buf, "JOIN %s\n", win->server->lastInvite);
	       sendto_server(win,buf);
	       }
	       return;
	}
	argv++;
	if(**argv!='#' && **argv!='&'){
		channame=(char *)malloc( sizeof(char)*(strlen(*argv)+3));
		if(!channame){err_ret("errur");return ;} 
		sprintf(channame,"#%s", *argv);
	}else
		channame=strdup(*argv);

	 if(on_channel(win->server, channame))
	 	fl_addto_browser(win->chanwin->brow2, PROMPT"already on channel");
	else{

	 	sprintf(buf,"JOIN %s %s\n", channame, *++argv?*argv:"");
	 	addto_cmd_sent(win, "JOIN", channame);
	 	sendto_server(win,buf);
	 }

}
}

void part(int argc,char **argv, Winstruct *win){
	char *channame, buf[256];

	if(argc==1){
		sprintf(buf,PROMPT"%s: which channel?", argv[0]);
		fl_addto_browser(win->chanwin->brow2,buf);
		return;
	}
	if( !strncasecmp(argv[1], "-help", 2) ){ 
		show_std_help(uppercase(argv[0]), NULL, win->chanwin);
		return;
	} else
	if(!strncasecmp(argv[1], "-last", 2) ){

		if(win->lastJoin->name){
		sprintf(buf,"PART %s\n", win->lastJoin->name);
		sendto_server(win,buf);
		}
		return;
	}else
	if(!strncasecmp(argv[1], "-all", 2) ){
	    Channel *current;
	    int errur=0;
	    current=win->chanStart->right;
	    while(current!=win->chanStart && !errur){
		sprintf(buf,"PART %s\n", current->name);
		errur=sendto_server(win,buf);
		current=current->right;
		delay(500);
	   }
	   return;
	}
	argv++;
	if(!strcmp(*argv, "*")){
		if( win->chanCur==win->chanStart) return;
		else channame=win->chanCur->name;
	}else
	if(**argv!='#' && **argv!='&'){
		channame=(char *)malloc( sizeof(char)*(strlen(*argv)+3));
		if(!channame){err_ret("errur");return ;} 
		sprintf(channame,"#%s", *argv);
	}else
		channame=strdup(*argv);
	 sprintf(buf,"PART %s\n", channame);
	 sendto_server(win,buf);
}

void invite(int argc, char **argv, Winstruct *win){
/* invite nick1 nick 2 nick3 ... [to channel]
 invite -help
*/
	int i,j=0;
	char *channel=NULL;
	if(argc==1){
		fl_addto_browser(win->chanwin->brow2,PROMPT"invite who?");
		return;
	}
	if( !strncasecmp(argv[1], "-help", 2) ){ 
		show_std_help(uppercase(argv[0]), NULL, win->chanwin);
		return;
	}
	if(win->chanCur==win->chanStart) return;/* no channels; dont invite! */
	#if 1
	i=1;
	while(++i<argc) if(!strcasecmp( argv[i], "to") && (i+2)==argc){
		j=i;i++;
		if(!strcmp(argv[i], "*")) channel=win->chanCur->name;
		else{
			channel= (char *)malloc(sizeof(char)*(strlen(argv[i])+3));
			if(argv[i][0]!='#' && argv[i][0]!='&')
				 sprintf(channel,"#%s", argv[i]);
			else strcpy(channel,argv[i]);
		}
		break;
	}
	#endif
	if(j==0) j=argc;
	if(!channel || !strcmp(channel, "*")) channel=win->chanCur->name;
	while(--j>0){
		char *buf=malloc(sizeof(char)*(strlen(channel)+strlen(argv[j])+16));
		sprintf(buf,"INVITE %s %s\n", argv[j], channel);
		if(sendto_server(win, buf)) break;
		free(buf);
	}

}
void topic(int argc,char **argv, Winstruct *win){
/*
	/topic -clear  channel	- remove topic 
	/topic -clear		- remove topic current channel
	/topic channel newtopic	- set topic
	/topic			- request for topic
	* = current channel
*/
	char *channame, buf[512];
	int clear=0;

	if(argc==1){	/* /topic */
		if(win->chanCur!=win->chanStart ){
			sprintf(buf,"TOPIC %s\r\n", win->chanCur->name);
			sendto_server(win,buf);
		}
		return;
	}
	if( !strncasecmp(argv[1], "-help", 2) ){ 
		show_std_help(uppercase(argv[0]), NULL, win->chanwin);
		return ;
	}
	if( !strncasecmp(argv[1], "-clear", 2) ){
		clear=1;
		argv+=2;
		if(!(*argv)){		/* topic -clear */
			if( win->chanCur==win->chanStart) return;
			sprintf(buf,"TOPIC %s :\r\n", win->chanCur->name);
			sendto_server(win,buf);
			return;
		}
	}
	if(!clear) argv++;
	if(!strcmp(*argv, "*")){
		if( win->chanCur==win->chanStart) return;
		else channame=win->chanCur->name;
	}else
	if(**argv!='#' && **argv!='&'){
		channame=(char *)malloc( sizeof(char)*(strlen(*argv)+3));
		sprintf(channame,"#%s", *argv);
	}else
		channame=strdup(*argv);
	 sprintf(buf,"TOPIC %s ", channame);	/* just in case empty input line */
	 clear=1;
	 while(*++argv){			/* input line not empty */
	 	if(clear){ strcat(buf,":");  clear=0; }
		strcat(buf,*argv);
		strcat(buf," ");
	}
	strcat(buf,"\n");
	sendto_server(win,buf);
}

void kick(int argc,char **argv, Winstruct *win){
/*
	/kick channel user [reasonn]
	* = current channel
*/
	char *channame, buf[256];

	if(argc>1)
	   if( !strncasecmp(argv[1], "-help", 2) ){ 
		show_std_help(uppercase(argv[0]), NULL, win->chanwin);
		return ;
	   }
	if(argc==1 || argc<3){	
		sprintf(buf,PROMPT"%s: channel and user name?", argv[0]);
		fl_addto_browser(win->chanwin->brow2,buf);
		return;
	}
	argv++;
	if(!strcmp(*argv, "*")){
		if( win->chanCur==win->chanStart){
		 	fl_addto_browser(win->chanwin->brow2,PROMPT"No channel here");
			fl_ringbell(0);
			return;
		} 
		else channame=win->chanCur->name;
	}else
	if(**argv!='#' && **argv!='&'){
		channame=(char *)malloc( sizeof(char)*(strlen(*argv)+3));
		if(!channame){err_ret("errur");return ;} 
		sprintf(channame,"#%s", *argv);
	}else
		channame=strdup(*argv);
	sprintf(buf,"KICK %s %s :", channame, *++argv);
	 while(*++argv && strlen(buf)<225){
	 	strcat(buf,*argv);
		strcat(buf," ");
	}
	strcat(buf,"\r\n");
	sendto_server(win,buf);
}
#if 0
void do_exit(int argc,char **argv, Winstruct *win){
/*
	/exit -f	emrgency , no cleanup
	/exit		confirm exit
*/
	fprintf(stderr,"%s %s %d\n",argv[0],argv[1],strlen(argv[1]));
	if(argc==1){
	 fl_trigger_object(main_form->quit);
	 return;
	 }
	 fprintf(stderr,"%s %s\n",argv[0],argv[1]);
	 if( !strncasecmp(argv[1], "-help", 2) ){ 
		show_std_help(uppercase(argv[0]), NULL, win->chanwin);
		return ;
	}
	fprintf(stderr,"%s %s\n",argv[0],argv[1]);
	PRINT;
	if( !strncasecmp(argv[1], "-f", 2) ) 
		fl_finish();
	fprintf(stderr,"%s %s\n",argv[0],argv[1]);
}
#endif

void quit(int argc,char **argv, Winstruct *win){
/*
  	/quit or /exit	:close connecton to server
	/quit <reason> or /exit <reason>	:ask server to close connection
	/quit -help
*/
	

	if( argc>1 && !strncasecmp(argv[1], "-help", 2) ) 
		show_std_help(uppercase(argv[0]), NULL, win->chanwin);
	else{
		char buf[512];
		WinList *p;
		buf[0]='\0';
		if(argc==1) sprintf(buf,"QUIT :%s\n",quit_text);
		else{
	 		strcat(buf,"QUIT :");
	 		while(*++argv){
	 			strcat(buf,*argv);
				strcat(buf," ");
			}
			strcat(buf,"\n");
		}
		if(sendto_server(win,buf)) return;
		build_winlistbyfd(win->server->fd);
		p=servWin;
		while (p) {
			ClearWinChanList(p->win);
			UpdateStatus(p->win);
			p=p->next;
		}
		close_server_connection(&win->server->fd);
   		
	}

}

void op(int argc,char **argv, Winstruct *win){
/* e.g.:	/op nick1 nick2 nick3 
		/deop nick1 nick2 nick3
*/
	if(!win) return;
	if(argc==1){
		fl_addto_browser(win->chanwin->brow2,PROMPT"missing nicks for cmd..");
		return;
	}
	if( !strncasecmp(argv[1], "-help", 2) ){ 
		show_std_help(uppercase(argv[0]), NULL, win->chanwin);
		  return;
		}
	if(win->chanCur==win->chanStart){
		if(gflags &VERBOSE_CLIENT) 
			fl_addto_browser(win->chanwin->brow2,PROMPT"No channels here");
	 	return;	
	}
	if(argc<2){
		fl_addto_browser(win->chanwin->brow2,PROMPT"missing nicknames");
		return;
	}else{
	 	char flag='+';
		if(strcasecmp(argv[0],"op")) flag='-';
		while(*++argv){
			/*char *buf=malloc(sizeof(char)*(strlen(*argv)+strlen(
			win->chanCur->name)+16));*/
			char buf[256];
			sprintf(buf,"MODE %s %co %s\r\n", win->chanCur->name,
			 flag, *argv);
			if(sendto_server(win, buf)) break;
			else delay(500);
			/*free(buf);*/
		}
	}

}

void server(int argc,char **argv, Winstruct *win){
/* server <number>|<servname> [port]  [-pas passwd] [-nick nickname]*/
	static void server_list(Server *p, FL_OBJECT *brow, int *i);	
	
	if(argc==1){
		int i=0;
		server_list(servTree, win->chanwin->browser, &i);
		return;
	}
	if( !strncasecmp(argv[1], "-save", 2) ){
		char *fname=argv[2];
		int status= save_servers(fname);
		if(status){
			char buf[128];
			sprintf("Error saving server list: %s", strerror(status));
			fl_addto_browser(win->chanwin->brow2, buf);
		}
		return;
	}

	if( !strncasecmp(argv[1], "-help", 2) ){ 
		show_std_help(uppercase(argv[0]), NULL, win->chanwin);
		return ;
	}else
	{	
		static void get_server_bynumber(Server *p,
		 Server **,int n, int *i,char *);
		char *server=0,  *nick=NULL, *password=NULL;
		u_short port=0;
		Server *s=NULL;
		int found=0;
		
		char *buf;
		int n;

		
		argv++;
		server=strdup(*argv);
		n=strtol(server, &buf,0);
		/*n=atoi(server);*/
		if(*buf==0){
			int i=0;
			char gotit=0;
			s=malloc(sizeof(Server));
			
			if(n>0) get_server_bynumber(servTree, &s,n, &i, &gotit);
			if(n<=0 || !gotit){
				fprintf(stderr, "invalid server number %d\n",n);
				if(gflags & BEEP_ERR) fl_ringbell(0);
				free(s);
				return;
			}
			found=1;
		}
		while((*++argv)!=NULL){
			if(!strncasecmp(*argv, "-pass", 3))
				if(!(*++argv)){
					 fl_addto_browser(win->chanwin->brow2, 
					 PROMPT"-pass: password?");
					 return;
				}else
				password=strdup(*argv);
			else 
			if(!strncasecmp(*argv, "-nick", 2))
				if(!(*++argv)){
					 fl_addto_browser(win->chanwin->brow2, 
					 PROMPT"-nick: specify one");
					 return;
				}else
				nick=strdup(*argv);
			else
				 if(port<=0) port=atoi(*argv);
		}
		if(!found){
		    port= port?port: 
		    win->server && win->server->fd<0? win->server->port:DEFAULT_PORT;
		    s=search_server_tree_byname(server,port);
		    if(!s){
			found=0;
			s=(Server*)malloc(sizeof(Server));
			if(!s){	err_ret("%s %d",__FILE__,__LINE__); return;}

		    }else found=1;
		}/* if (!s) */
		if(found && s->fd>0){
			fl_addto_browser(win->chanwin->brow2, 
			PROMPT"You are already connected to that server/port."
			" Open new window.");
			fl_ringbell(0);
			return;
		}
		if(win->server && (win->server->connecting
		 /*||win->chanwin->close_con->u_vdata*/)){
			 fl_ringbell(0);
			 if(win->server->connecting>0)
			 fl_addto_browser(win->chanwin->brow2,
			 PROMPT" connecting."" Wait or try different window");
			 else /*if( win->chanwin->close_con->u_vdata)*/{
				fl_addto_browser(win->chanwin->brow2,
			PROMPT"already resolving server name(?). Wait.");
			}
			return;
		}
		/*else no_of_wins=old_fd=0;*/
		
		if(nick) s->nick=strdup(nick);
		else if(!found) s->nick=strdup(Name);
		if(password) s->password=strdup(password);
		else if(!found) s->password=NULL;
		if(!found){
			s->email=(char *)malloc(sizeof(char)*(strlen(Name)+strlen(host)+3));
			s->ircname=(char *)malloc(sizeof(char)*(strlen(sula_NAME sula_VERSION)+8));
			sprintf(s->email, "%s@%s", Name, host);
			s->ircname= sula_NAME sula_VERSION" Tester";
			s->mode=NULL;
			s->flag =SERVER_FLAG_RESET;
			s->read=0;
			s->lag=NULL;
			s->lastInvite=NULL;
			s->port=port;
			s->servname=server;
			s->fd= -1;
			s->state=-1;
			s->iNick=-1;
		}
		connect_to_server(s, win, NULL, 0);
	}/* else */
}

static void get_server_bynumber(Server *p, Server **s, int n, int *i, char *gotit){
/* return server # n */
	if(*gotit) return;
	if(p){
		get_server_bynumber(p->left,s, n, i,gotit);
		if(n== ++(*i)){*gotit=1; *s=p;return;}
		get_server_bynumber(p->right,s, n, i,gotit);
	}
}


static void server_list(Server *p, FL_OBJECT *brow, int *i){
	if(p){
		char *buf;
		server_list(p->left, brow, i);
		buf=(char *)malloc(sizeof(char)*(strlen(p->servname)
			+strlen(p->email) +strlen(p->ircname)+strlen(p->nick)+30));
		sprintf(buf,"%s\t%d. %s %d %s %s (%s)",p->fd>0?"*":"", ++(*i),
		   p->servname, p->port, p->nick, p->email, p->ircname);
		fl_addto_browser(brow, buf);
		free(buf);
		server_list(p->right, brow, i);
	}
}


void quoted_cmd(int argc, char **argv, Winstruct *win){
/* whois nick1 nick 2 nick3 ..
userhost,ison,whowas likewise
 whois -help
*/
char *cmd;
char buf[256];
/*char cmds[]={"WHOIS", "WHOWAS", "USERHOST","ISON"};*/

	if(!win 
	#if 0
	|| cmd>(sizeof(cmds)/sizeof(char *))
	#endif
	) return;
	if(argc==1){
		sprintf(buf,PROMPT"%30s: nicknames needed", argv[0]);
		fl_addto_browser(win->chanwin->brow2, buf);
		return;
	}
	cmd=strdup(uppercase(argv[0]));
	if( !strncasecmp(argv[1], "-help", 2) ){ 
		show_std_help(cmd, NULL, win->chanwin);
		return;
	}
	if(!win->server || win->server->fd<1){
		fl_addto_browser(win->chanwin->brow2,PROMPT"You are not connected to a server");
		fl_ringbell(0);
		return;
	}
	argv++;
	while(*argv){
		sprintf(buf,"%s %s\n", cmd, *argv);
		addto_cmd_sent(win, cmd, *argv);
		if(sendto_server(win, buf)){
			getwinbycmd(win->server,cmd, *argv,1);
			break;
		}
		argv++;
	}

}

void who(int argc,char **argv, Winstruct *win){
	char *buf=NULL;
	if(argc>1 && !strncasecmp(argv[1], "-help", 2) ){ 
		show_std_help(uppercase(argv[0]), NULL, win->chanwin);
		return;
	}
	if(!win->server){
		fl_ringbell(0); return;
		}
	if(argc==1 || !strcmp(argv[1], "*")){
		if( win->chanCur!=win->chanStart) {
			buf=malloc(sizeof(char)*(strlen(win->chanCur->name)+8));
		 	sprintf(buf,"WHO %s\n",win->chanCur->name);
		 	addto_cmd_sent(win, "WHO", win->chanCur->name);
			if(sendto_server(win, buf)) 
				getwinbycmd(win->server,"WHO",win->chanCur->name,1);
			free(buf);
		}
		return;
	}
	if( !strncasecmp(argv[1], "-update", 2) ){
		char *chan=NULL;
		if(argv[2]) chan=argv[2];
		else if(win->chanCur!=win->chanStart){chan=win->chanCur->name;}
		else return;
		 buf=malloc(sizeof(char)*(strlen(chan)+8));
		 sprintf(buf,"WHO %s\n",chan);
		 addto_cmd_sent(win, "WHO_UPDATE", chan);
		 if(sendto_server(win, buf)) getwinbycmd(win->server,
		 "WHO_UPDATE", chan,1);
		 free(buf);
	}
	else
	{
		 buf=malloc(sizeof(char)*(strlen(argv[1])+8));
		 sprintf(buf,"WHO %s\n", argv[1]);
		#if not_correct_if_wildcards_used
		 addto_cmd_sent(win, "WHO", argv[1]);
		 if(sendto_server(win, buf))
		  getwinbycmd(win,"WHO", argv[1],1);
		 #endif
		 sendto_server(win, buf);
		 free(buf);
		 return;
	}
}

