4402 lines
		
	
	
	
		
			92 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			4402 lines
		
	
	
	
		
			92 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* X-Chat
 | 
						|
 * Copyright (C) 1998 Peter Zelezny.
 | 
						|
 *
 | 
						|
 * 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; if not, write to the Free Software
 | 
						|
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 | 
						|
 */
 | 
						|
 | 
						|
#define _GNU_SOURCE	/* for memrchr */
 | 
						|
#include <string.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <ctype.h>
 | 
						|
#include <limits.h>
 | 
						|
#include <errno.h>
 | 
						|
 | 
						|
#define WANTSOCKET
 | 
						|
#define WANTARPA
 | 
						|
#include "inet.h"
 | 
						|
 | 
						|
#ifndef WIN32
 | 
						|
#include <sys/wait.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#include <time.h>
 | 
						|
#include <signal.h>
 | 
						|
#include <sys/stat.h>
 | 
						|
#include <fcntl.h>
 | 
						|
 | 
						|
#include "xchat.h"
 | 
						|
#include "plugin.h"
 | 
						|
#include "ignore.h"
 | 
						|
#include "util.h"
 | 
						|
#include "fe.h"
 | 
						|
#include "cfgfiles.h"			  /* xchat_fopen_file() */
 | 
						|
#include "network.h"				/* net_ip() */
 | 
						|
#include "modes.h"
 | 
						|
#include "notify.h"
 | 
						|
#include "inbound.h"
 | 
						|
#include "text.h"
 | 
						|
#include "xchatc.h"
 | 
						|
#include "servlist.h"
 | 
						|
#include "server.h"
 | 
						|
#include "tree.h"
 | 
						|
#include "outbound.h"
 | 
						|
 | 
						|
 | 
						|
#ifdef USE_DEBUG
 | 
						|
extern int current_mem_usage;
 | 
						|
#endif
 | 
						|
#define TBUFSIZE 4096
 | 
						|
 | 
						|
static void help (session *sess, char *tbuf, char *helpcmd, int quiet);
 | 
						|
static int cmd_server (session *sess, char *tbuf, char *word[], char *word_eol[]);
 | 
						|
static void handle_say (session *sess, char *text, int check_spch);
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
notj_msg (struct session *sess)
 | 
						|
{
 | 
						|
	PrintText (sess, _("No channel joined. Try /join #<channel>\n"));
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
notc_msg (struct session *sess)
 | 
						|
{
 | 
						|
	PrintText (sess, _("Not connected. Try /server <host> [<port>]\n"));
 | 
						|
}
 | 
						|
 | 
						|
static char *
 | 
						|
random_line (char *file_name)
 | 
						|
{
 | 
						|
	FILE *fh;
 | 
						|
	char buf[512];
 | 
						|
	int lines, ran;
 | 
						|
 | 
						|
	if (!file_name[0])
 | 
						|
		goto nofile;
 | 
						|
 | 
						|
	fh = xchat_fopen_file (file_name, "r", 0);
 | 
						|
	if (!fh)
 | 
						|
	{
 | 
						|
	 nofile:
 | 
						|
		/* reason is not a file, an actual reason! */
 | 
						|
		return strdup (file_name);
 | 
						|
	}
 | 
						|
 | 
						|
	/* count number of lines in file */
 | 
						|
	lines = 0;
 | 
						|
	while (fgets (buf, sizeof (buf), fh))
 | 
						|
		lines++;
 | 
						|
 | 
						|
	if (lines < 1)
 | 
						|
		goto nofile;
 | 
						|
 | 
						|
	/* go down a random number */
 | 
						|
	rewind (fh);
 | 
						|
	ran = RAND_INT (lines);
 | 
						|
	do
 | 
						|
	{
 | 
						|
		fgets (buf, sizeof (buf), fh);
 | 
						|
		lines--;
 | 
						|
	}
 | 
						|
	while (lines > ran);
 | 
						|
	fclose (fh);
 | 
						|
	buf[strlen (buf) - 1] = 0;	  /* remove the trailing '\n' */
 | 
						|
	return strdup (buf);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
server_sendpart (server * serv, char *channel, char *reason)
 | 
						|
{
 | 
						|
	if (!reason)
 | 
						|
	{
 | 
						|
		reason = random_line (prefs.partreason);
 | 
						|
		serv->p_part (serv, channel, reason);
 | 
						|
		free (reason);
 | 
						|
	} else
 | 
						|
	{
 | 
						|
		/* reason set by /quit, /close argument */
 | 
						|
		serv->p_part (serv, channel, reason);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
server_sendquit (session * sess)
 | 
						|
{
 | 
						|
	char *rea, *colrea;
 | 
						|
 | 
						|
	if (!sess->quitreason)
 | 
						|
	{
 | 
						|
		colrea = strdup (prefs.quitreason);
 | 
						|
		check_special_chars (colrea, FALSE);
 | 
						|
		rea = random_line (colrea);
 | 
						|
		free (colrea);
 | 
						|
		sess->server->p_quit (sess->server, rea);
 | 
						|
		free (rea);
 | 
						|
	} else
 | 
						|
	{
 | 
						|
		/* reason set by /quit, /close argument */
 | 
						|
		sess->server->p_quit (sess->server, sess->quitreason);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
process_data_init (char *buf, char *cmd, char *word[],
 | 
						|
						 char *word_eol[], gboolean handle_quotes,
 | 
						|
						 gboolean allow_escape_quotes)
 | 
						|
{
 | 
						|
	int wordcount = 2;
 | 
						|
	int space = FALSE;
 | 
						|
	int quote = FALSE;
 | 
						|
	int j = 0;
 | 
						|
	int len;
 | 
						|
 | 
						|
	word[0] = "\000\000";
 | 
						|
	word_eol[0] = "\000\000";
 | 
						|
	word[1] = (char *)buf;
 | 
						|
	word_eol[1] = (char *)cmd;
 | 
						|
 | 
						|
	while (1)
 | 
						|
	{
 | 
						|
		switch (*cmd)
 | 
						|
		{
 | 
						|
		case 0:
 | 
						|
			buf[j] = 0;
 | 
						|
			for (j = wordcount; j < PDIWORDS; j++)
 | 
						|
			{
 | 
						|
				word[j] = "\000\000";
 | 
						|
				word_eol[j] = "\000\000";
 | 
						|
			}
 | 
						|
			return;
 | 
						|
		case '\042':
 | 
						|
			if (!handle_quotes)
 | 
						|
				goto def;
 | 
						|
			/* two quotes turn into 1 */
 | 
						|
			if (allow_escape_quotes && cmd[1] == '\042')
 | 
						|
			{
 | 
						|
				cmd++;
 | 
						|
				goto def;
 | 
						|
			}
 | 
						|
			if (quote)
 | 
						|
			{
 | 
						|
				quote = FALSE;
 | 
						|
				space = FALSE;
 | 
						|
			} else
 | 
						|
				quote = TRUE;
 | 
						|
			cmd++;
 | 
						|
			break;
 | 
						|
		case ' ':
 | 
						|
			if (!quote)
 | 
						|
			{
 | 
						|
				if (!space)
 | 
						|
				{
 | 
						|
					buf[j] = 0;
 | 
						|
					j++;
 | 
						|
 | 
						|
					if (wordcount < PDIWORDS)
 | 
						|
					{
 | 
						|
						word[wordcount] = &buf[j];
 | 
						|
						word_eol[wordcount] = cmd + 1;
 | 
						|
						wordcount++;
 | 
						|
					}
 | 
						|
 | 
						|
					space = TRUE;
 | 
						|
				}
 | 
						|
				cmd++;
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		default:
 | 
						|
def:
 | 
						|
			space = FALSE;
 | 
						|
			len = g_utf8_skip[((unsigned char *)cmd)[0]];
 | 
						|
			if (len == 1)
 | 
						|
			{
 | 
						|
				buf[j] = *cmd;
 | 
						|
				j++;
 | 
						|
				cmd++;
 | 
						|
			} else
 | 
						|
			{
 | 
						|
				/* skip past a multi-byte utf8 char */
 | 
						|
				memcpy (buf + j, cmd, len);
 | 
						|
				j += len;
 | 
						|
				cmd += len;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_addbutton (struct session *sess, char *tbuf, char *word[],
 | 
						|
					char *word_eol[])
 | 
						|
{
 | 
						|
	if (*word[2] && *word_eol[3])
 | 
						|
	{
 | 
						|
		if (sess->type == SESS_DIALOG)
 | 
						|
		{
 | 
						|
			list_addentry (&dlgbutton_list, word_eol[3], word[2]);
 | 
						|
			fe_dlgbuttons_update (sess);
 | 
						|
		} else
 | 
						|
		{
 | 
						|
			list_addentry (&button_list, word_eol[3], word[2]);
 | 
						|
			fe_buttons_update (sess);
 | 
						|
		}
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
	return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_allchannels (session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	GSList *list = sess_list;
 | 
						|
 | 
						|
	if (!*word_eol[2])
 | 
						|
		return FALSE;
 | 
						|
 | 
						|
	while (list)
 | 
						|
	{
 | 
						|
		sess = list->data;
 | 
						|
		if (sess->type == SESS_CHANNEL && sess->channel[0] && sess->server->connected)
 | 
						|
		{
 | 
						|
			handle_command (sess, word_eol[2], FALSE);
 | 
						|
		}
 | 
						|
		list = list->next;
 | 
						|
	}
 | 
						|
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_allchannelslocal (session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	GSList *list = sess_list;
 | 
						|
	server *serv = sess->server;
 | 
						|
 | 
						|
	if (!*word_eol[2])
 | 
						|
		return FALSE;
 | 
						|
 | 
						|
	while (list)
 | 
						|
	{
 | 
						|
		sess = list->data;
 | 
						|
		if (sess->type == SESS_CHANNEL && sess->channel[0] &&
 | 
						|
			 sess->server->connected && sess->server == serv)
 | 
						|
		{
 | 
						|
			handle_command (sess, word_eol[2], FALSE);
 | 
						|
		}
 | 
						|
		list = list->next;
 | 
						|
	}
 | 
						|
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_allservers (struct session *sess, char *tbuf, char *word[],
 | 
						|
					 char *word_eol[])
 | 
						|
{
 | 
						|
	GSList *list;
 | 
						|
	server *serv;
 | 
						|
 | 
						|
	if (!*word_eol[2])
 | 
						|
		return FALSE;
 | 
						|
 | 
						|
	list = serv_list;
 | 
						|
	while (list)
 | 
						|
	{
 | 
						|
		serv = list->data;
 | 
						|
		if (serv->connected)
 | 
						|
			handle_command (serv->front_session, word_eol[2], FALSE);
 | 
						|
		list = list->next;
 | 
						|
	}
 | 
						|
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_away (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	GSList *list;
 | 
						|
	char *reason = word_eol[2];
 | 
						|
 | 
						|
	if (!(*reason))
 | 
						|
	{
 | 
						|
		if (sess->server->is_away)
 | 
						|
		{
 | 
						|
			if (sess->server->last_away_reason)
 | 
						|
				PrintTextf (sess, _("Already marked away: %s\n"), sess->server->last_away_reason);
 | 
						|
			return FALSE;
 | 
						|
		}
 | 
						|
 | 
						|
		if (sess->server->reconnect_away)
 | 
						|
			reason = sess->server->last_away_reason;
 | 
						|
		else
 | 
						|
			/* must manage memory pointed to by random_line() */
 | 
						|
			reason = random_line (prefs.awayreason);
 | 
						|
	}
 | 
						|
	sess->server->p_set_away (sess->server, reason);
 | 
						|
 | 
						|
	if (prefs.show_away_message)
 | 
						|
	{
 | 
						|
		snprintf (tbuf, TBUFSIZE, "me is away: %s", reason);
 | 
						|
		for (list = sess_list; list; list = list->next)
 | 
						|
		{
 | 
						|
			/* am I the right server and not a dialog box */
 | 
						|
			if (((struct session *) list->data)->server == sess->server
 | 
						|
				 && ((struct session *) list->data)->type == SESS_CHANNEL
 | 
						|
				 && ((struct session *) list->data)->channel[0])
 | 
						|
			{
 | 
						|
				handle_command ((session *) list->data, tbuf, TRUE);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (sess->server->last_away_reason != reason)
 | 
						|
	{
 | 
						|
		if (sess->server->last_away_reason)
 | 
						|
			free (sess->server->last_away_reason);
 | 
						|
 | 
						|
		if (reason == word_eol[2])
 | 
						|
			sess->server->last_away_reason = strdup (reason);
 | 
						|
		else
 | 
						|
			sess->server->last_away_reason = reason;
 | 
						|
	}
 | 
						|
 | 
						|
	if (!sess->server->connected)
 | 
						|
		sess->server->reconnect_away = 1;
 | 
						|
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_back (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	GSList *list;
 | 
						|
	unsigned int gone;
 | 
						|
 | 
						|
	if (sess->server->is_away)
 | 
						|
	{
 | 
						|
		sess->server->p_set_back (sess->server);
 | 
						|
 | 
						|
		if (prefs.show_away_message)
 | 
						|
		{
 | 
						|
			gone = time (NULL) - sess->server->away_time;
 | 
						|
			sprintf (tbuf, "me is back (gone %.2d:%.2d:%.2d)", gone / 3600,
 | 
						|
						(gone / 60) % 60, gone % 60);
 | 
						|
			for (list = sess_list; list; list = list->next)
 | 
						|
			{
 | 
						|
				/* am I the right server and not a dialog box */
 | 
						|
				if (((struct session *) list->data)->server == sess->server
 | 
						|
					 && ((struct session *) list->data)->type == SESS_CHANNEL
 | 
						|
					 && ((struct session *) list->data)->channel[0])
 | 
						|
				{
 | 
						|
					handle_command ((session *) list->data, tbuf, TRUE);
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		PrintText (sess, _("Already marked back.\n"));
 | 
						|
	}
 | 
						|
 | 
						|
	if (sess->server->last_away_reason)
 | 
						|
		free (sess->server->last_away_reason);
 | 
						|
	sess->server->last_away_reason = NULL;
 | 
						|
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
ban (session * sess, char *tbuf, char *mask, char *bantypestr, int deop)
 | 
						|
{
 | 
						|
	int bantype;
 | 
						|
	struct User *user;
 | 
						|
	char *at, *dot, *lastdot;
 | 
						|
	char username[64], fullhost[128], domain[128], *mode, *p2;
 | 
						|
	server *serv = sess->server;
 | 
						|
 | 
						|
	user = userlist_find (sess, mask);
 | 
						|
	if (user && user->hostname)  /* it's a nickname, let's find a proper ban mask */
 | 
						|
	{
 | 
						|
		if (deop)
 | 
						|
		{
 | 
						|
			mode = "-o+b ";
 | 
						|
			p2 = user->nick;
 | 
						|
		} else
 | 
						|
		{
 | 
						|
			mode = "+b";
 | 
						|
			p2 = "";
 | 
						|
		}
 | 
						|
 | 
						|
		mask = user->hostname;
 | 
						|
 | 
						|
		at = strchr (mask, '@');	/* FIXME: utf8 */
 | 
						|
		if (!at)
 | 
						|
			return;					  /* can't happen? */
 | 
						|
		*at = 0;
 | 
						|
 | 
						|
		if (mask[0] == '~' || mask[0] == '+' ||
 | 
						|
		    mask[0] == '=' || mask[0] == '^' || mask[0] == '-')
 | 
						|
		{
 | 
						|
			/* the ident is prefixed with something, we replace that sign with an * */
 | 
						|
			safe_strcpy (username+1, mask+1, sizeof (username)-1);
 | 
						|
			username[0] = '*';
 | 
						|
		} else if (at - mask < USERNAMELEN)
 | 
						|
		{
 | 
						|
			/* we just add an * in the begining of the ident */
 | 
						|
			safe_strcpy (username+1, mask, sizeof (username)-1);
 | 
						|
			username[0] = '*';
 | 
						|
		} else
 | 
						|
		{
 | 
						|
			/* ident might be too long, we just ban what it gives and add an * in the end */
 | 
						|
			safe_strcpy (username, mask, sizeof (username));
 | 
						|
		}
 | 
						|
		*at = '@';
 | 
						|
		safe_strcpy (fullhost, at + 1, sizeof (fullhost));
 | 
						|
 | 
						|
		dot = strchr (fullhost, '.');
 | 
						|
		if (dot)
 | 
						|
		{
 | 
						|
			safe_strcpy (domain, dot, sizeof (domain));
 | 
						|
		} else
 | 
						|
		{
 | 
						|
			safe_strcpy (domain, fullhost, sizeof (domain));
 | 
						|
		}
 | 
						|
 | 
						|
		if (*bantypestr)
 | 
						|
			bantype = atoi (bantypestr);
 | 
						|
		else
 | 
						|
			bantype = prefs.bantype;
 | 
						|
 | 
						|
		tbuf[0] = 0;
 | 
						|
		if (inet_addr (fullhost) != -1)	/* "fullhost" is really a IP number */
 | 
						|
		{
 | 
						|
			lastdot = strrchr (fullhost, '.');
 | 
						|
			if (!lastdot)
 | 
						|
				return;				  /* can't happen? */
 | 
						|
 | 
						|
			*lastdot = 0;
 | 
						|
			strcpy (domain, fullhost);
 | 
						|
			*lastdot = '.';
 | 
						|
 | 
						|
			switch (bantype)
 | 
						|
			{
 | 
						|
			case 0:
 | 
						|
				snprintf (tbuf, TBUFSIZE, "%s%s *!*@%s.*", mode, p2, domain);
 | 
						|
				break;
 | 
						|
 | 
						|
			case 1:
 | 
						|
				snprintf (tbuf, TBUFSIZE, "%s%s *!*@%s", mode, p2, fullhost);
 | 
						|
				break;
 | 
						|
 | 
						|
			case 2:
 | 
						|
				snprintf (tbuf, TBUFSIZE, "%s%s *!%s@%s.*", mode, p2, username, domain);
 | 
						|
				break;
 | 
						|
 | 
						|
			case 3:
 | 
						|
				snprintf (tbuf, TBUFSIZE, "%s%s *!%s@%s", mode, p2, username, fullhost);
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		} else
 | 
						|
		{
 | 
						|
			switch (bantype)
 | 
						|
			{
 | 
						|
			case 0:
 | 
						|
				snprintf (tbuf, TBUFSIZE, "%s%s *!*@*%s", mode, p2, domain);
 | 
						|
				break;
 | 
						|
 | 
						|
			case 1:
 | 
						|
				snprintf (tbuf, TBUFSIZE, "%s%s *!*@%s", mode, p2, fullhost);
 | 
						|
				break;
 | 
						|
 | 
						|
			case 2:
 | 
						|
				snprintf (tbuf, TBUFSIZE, "%s%s *!%s@*%s", mode, p2, username, domain);
 | 
						|
				break;
 | 
						|
 | 
						|
			case 3:
 | 
						|
				snprintf (tbuf, TBUFSIZE, "%s%s *!%s@%s", mode, p2, username, fullhost);
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
	} else
 | 
						|
	{
 | 
						|
		snprintf (tbuf, TBUFSIZE, "+b %s", mask);
 | 
						|
	}
 | 
						|
	serv->p_mode (serv, sess->channel, tbuf);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_ban (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	char *mask = word[2];
 | 
						|
 | 
						|
	if (*mask)
 | 
						|
	{
 | 
						|
		ban (sess, tbuf, mask, word[3], 0);
 | 
						|
	} else
 | 
						|
	{
 | 
						|
		sess->server->p_mode (sess->server, sess->channel, "+b");	/* banlist */
 | 
						|
	}
 | 
						|
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_unban (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	/* Allow more than one mask in /unban -- tvk */
 | 
						|
	int i = 2;
 | 
						|
 | 
						|
	while (1)
 | 
						|
	{
 | 
						|
		if (!*word[i])
 | 
						|
		{
 | 
						|
			if (i == 2)
 | 
						|
				return FALSE;
 | 
						|
			send_channel_modes (sess, tbuf, word, 2, i, '-', 'b', 0);
 | 
						|
			return TRUE;
 | 
						|
		}
 | 
						|
		i++;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_chanopt (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	/* chanopt.c */
 | 
						|
	return chanopt_command (sess, tbuf, word, word_eol);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_charset (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	server *serv = sess->server;
 | 
						|
	const char *locale = NULL;
 | 
						|
	int offset = 0;
 | 
						|
 | 
						|
	if (strcmp (word[2], "-quiet") == 0)
 | 
						|
		offset++;
 | 
						|
 | 
						|
	if (!word[2 + offset][0])
 | 
						|
	{
 | 
						|
		g_get_charset (&locale);
 | 
						|
		PrintTextf (sess, "Current charset: %s\n",
 | 
						|
						serv->encoding ? serv->encoding : locale);
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
 | 
						|
	if (servlist_check_encoding (word[2 + offset]))
 | 
						|
	{
 | 
						|
		server_set_encoding (serv, word[2 + offset]);
 | 
						|
		if (offset < 1)
 | 
						|
			PrintTextf (sess, "Charset changed to: %s\n", word[2 + offset]);
 | 
						|
	} else
 | 
						|
	{
 | 
						|
		PrintTextf (sess, "\0034Unknown charset:\017 %s\n", word[2 + offset]);
 | 
						|
	}
 | 
						|
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_clear (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	GSList *list = sess_list;
 | 
						|
	char *reason = word_eol[2];
 | 
						|
 | 
						|
	if (strcasecmp (reason, "HISTORY") == 0)
 | 
						|
	{
 | 
						|
		history_free (&sess->history);
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
 | 
						|
	if (strncasecmp (reason, "all", 3) == 0)
 | 
						|
	{
 | 
						|
		while (list)
 | 
						|
		{
 | 
						|
			sess = list->data;
 | 
						|
			if (!sess->nick_said)
 | 
						|
				fe_text_clear (list->data, 0);
 | 
						|
			list = list->next;
 | 
						|
		}
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
 | 
						|
	if (reason[0] != '-' && !isdigit (reason[0]) && reason[0] != 0)
 | 
						|
		return FALSE;
 | 
						|
 | 
						|
	fe_text_clear (sess, atoi (reason));
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_close (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	GSList *list;
 | 
						|
 | 
						|
	if (strcmp (word[2], "-m") == 0)
 | 
						|
	{
 | 
						|
		list = sess_list;
 | 
						|
		while (list)
 | 
						|
		{
 | 
						|
			sess = list->data;
 | 
						|
			list = list->next;
 | 
						|
			if (sess->type == SESS_DIALOG)
 | 
						|
				fe_close_window (sess);
 | 
						|
		}
 | 
						|
	} else
 | 
						|
	{
 | 
						|
		if (*word_eol[2])
 | 
						|
			sess->quitreason = word_eol[2];
 | 
						|
		fe_close_window (sess);
 | 
						|
	}
 | 
						|
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_ctcp (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	int mbl;
 | 
						|
	char *to = word[2];
 | 
						|
	if (*to)
 | 
						|
	{
 | 
						|
		char *msg = word_eol[3];
 | 
						|
		if (*msg)
 | 
						|
		{
 | 
						|
			unsigned char *cmd = (unsigned char *)msg;
 | 
						|
 | 
						|
			/* make the first word upper case (as per RFC) */
 | 
						|
			while (1)
 | 
						|
			{
 | 
						|
				if (*cmd == ' ' || *cmd == 0)
 | 
						|
					break;
 | 
						|
				mbl = g_utf8_skip[*cmd];
 | 
						|
				if (mbl == 1)
 | 
						|
					*cmd = toupper (*cmd);
 | 
						|
				cmd += mbl;
 | 
						|
			}
 | 
						|
 | 
						|
			sess->server->p_ctcp (sess->server, to, msg);
 | 
						|
 | 
						|
			EMIT_SIGNAL (XP_TE_CTCPSEND, sess, to, msg, NULL, NULL, 0);
 | 
						|
 | 
						|
			return TRUE;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_country (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	char *code = word[2];
 | 
						|
	if (*code)
 | 
						|
	{
 | 
						|
		/* search? */
 | 
						|
		if (strcmp (code, "-s") == 0)
 | 
						|
		{
 | 
						|
			country_search (word[3], sess, (void *)PrintTextf);
 | 
						|
			return TRUE;
 | 
						|
		}
 | 
						|
 | 
						|
		/* search, but forgot the -s */
 | 
						|
		if (strchr (code, '*'))
 | 
						|
		{
 | 
						|
			country_search (code, sess, (void *)PrintTextf);
 | 
						|
			return TRUE;
 | 
						|
		}
 | 
						|
 | 
						|
		sprintf (tbuf, "%s = %s\n", code, country (code));
 | 
						|
		PrintText (sess, tbuf);
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
	return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_cycle (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	char *key = sess->channelkey;
 | 
						|
	char *chan = word[2];
 | 
						|
	if (!*chan)
 | 
						|
		chan = sess->channel;
 | 
						|
	if (*chan && sess->type == SESS_CHANNEL)
 | 
						|
	{
 | 
						|
		sess->server->p_cycle (sess->server, chan, key);
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
	return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_dcc (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	int goodtype;
 | 
						|
	struct DCC *dcc = 0;
 | 
						|
	char *type = word[2];
 | 
						|
	if (*type)
 | 
						|
	{
 | 
						|
		if (!strcasecmp (type, "HELP"))
 | 
						|
			return FALSE;
 | 
						|
		if (!strcasecmp (type, "CLOSE"))
 | 
						|
		{
 | 
						|
			if (*word[3] && *word[4])
 | 
						|
			{
 | 
						|
				goodtype = 0;
 | 
						|
				if (!strcasecmp (word[3], "SEND"))
 | 
						|
				{
 | 
						|
					dcc = find_dcc (word[4], word[5], TYPE_SEND);
 | 
						|
					dcc_abort (sess, dcc);
 | 
						|
					goodtype = TRUE;
 | 
						|
				}
 | 
						|
				if (!strcasecmp (word[3], "GET"))
 | 
						|
				{
 | 
						|
					dcc = find_dcc (word[4], word[5], TYPE_RECV);
 | 
						|
					dcc_abort (sess, dcc);
 | 
						|
					goodtype = TRUE;
 | 
						|
				}
 | 
						|
				if (!strcasecmp (word[3], "CHAT"))
 | 
						|
				{
 | 
						|
					dcc = find_dcc (word[4], "", TYPE_CHATRECV);
 | 
						|
					if (!dcc)
 | 
						|
						dcc = find_dcc (word[4], "", TYPE_CHATSEND);
 | 
						|
					dcc_abort (sess, dcc);
 | 
						|
					goodtype = TRUE;
 | 
						|
				}
 | 
						|
 | 
						|
				if (!goodtype)
 | 
						|
					return FALSE;
 | 
						|
 | 
						|
				if (!dcc)
 | 
						|
					EMIT_SIGNAL (XP_TE_NODCC, sess, NULL, NULL, NULL, NULL, 0);
 | 
						|
 | 
						|
				return TRUE;
 | 
						|
 | 
						|
			}
 | 
						|
			return FALSE;
 | 
						|
		}
 | 
						|
		if ((!strcasecmp (type, "CHAT")) || (!strcasecmp (type, "PCHAT")))
 | 
						|
		{
 | 
						|
			char *nick = word[3];
 | 
						|
			int passive = (!strcasecmp(type, "PCHAT")) ? 1 : 0;
 | 
						|
			if (*nick)
 | 
						|
				dcc_chat (sess, nick, passive);
 | 
						|
			return TRUE;
 | 
						|
		}
 | 
						|
		if (!strcasecmp (type, "LIST"))
 | 
						|
		{
 | 
						|
			dcc_show_list (sess);
 | 
						|
			return TRUE;
 | 
						|
		}
 | 
						|
		if (!strcasecmp (type, "GET"))
 | 
						|
		{
 | 
						|
			char *nick = word[3];
 | 
						|
			char *file = word[4];
 | 
						|
			if (!*file)
 | 
						|
			{
 | 
						|
				if (*nick)
 | 
						|
					dcc_get_nick (sess, nick);
 | 
						|
			} else
 | 
						|
			{
 | 
						|
				dcc = find_dcc (nick, file, TYPE_RECV);
 | 
						|
				if (dcc)
 | 
						|
					dcc_get (dcc);
 | 
						|
				else
 | 
						|
					EMIT_SIGNAL (XP_TE_NODCC, sess, NULL, NULL, NULL, NULL, 0);
 | 
						|
			}
 | 
						|
			return TRUE;
 | 
						|
		}
 | 
						|
		if ((!strcasecmp (type, "SEND")) || (!strcasecmp (type, "PSEND")))
 | 
						|
		{
 | 
						|
			int i = 3, maxcps;
 | 
						|
			char *nick, *file;
 | 
						|
			int passive = (!strcasecmp(type, "PSEND")) ? 1 : 0;
 | 
						|
 | 
						|
			nick = word[i];
 | 
						|
			if (!*nick)
 | 
						|
				return FALSE;
 | 
						|
 | 
						|
			maxcps = prefs.dcc_max_send_cps;
 | 
						|
			if (!strncasecmp(nick, "-maxcps=", 8))
 | 
						|
			{
 | 
						|
				maxcps = atoi(nick + 8);
 | 
						|
				i++;
 | 
						|
				nick = word[i];
 | 
						|
				if (!*nick)
 | 
						|
					return FALSE;
 | 
						|
			}
 | 
						|
 | 
						|
			i++;
 | 
						|
 | 
						|
			file = word[i];
 | 
						|
			if (!*file)
 | 
						|
			{
 | 
						|
				fe_dcc_send_filereq (sess, nick, maxcps, passive);
 | 
						|
				return TRUE;
 | 
						|
			}
 | 
						|
 | 
						|
			do
 | 
						|
			{
 | 
						|
				dcc_send (sess, nick, file, maxcps, passive);
 | 
						|
				i++;
 | 
						|
				file = word[i];
 | 
						|
			}
 | 
						|
			while (*file);
 | 
						|
 | 
						|
			return TRUE;
 | 
						|
		}
 | 
						|
 | 
						|
		return FALSE;
 | 
						|
	}
 | 
						|
 | 
						|
	dcc_show_list (sess);
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_debug (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	struct session *s;
 | 
						|
	struct server *v;
 | 
						|
	GSList *list = sess_list;
 | 
						|
 | 
						|
	PrintText (sess, "Session   T Channel    WaitChan  WillChan  Server\n");
 | 
						|
	while (list)
 | 
						|
	{
 | 
						|
		s = (struct session *) list->data;
 | 
						|
		sprintf (tbuf, "%p %1x %-10.10s %-10.10s %-10.10s %p\n",
 | 
						|
					s, s->type, s->channel, s->waitchannel,
 | 
						|
					s->willjoinchannel, s->server);
 | 
						|
		PrintText (sess, tbuf);
 | 
						|
		list = list->next;
 | 
						|
	}
 | 
						|
 | 
						|
	list = serv_list;
 | 
						|
	PrintText (sess, "Server    Sock  Name\n");
 | 
						|
	while (list)
 | 
						|
	{
 | 
						|
		v = (struct server *) list->data;
 | 
						|
		sprintf (tbuf, "%p %-5d %s\n",
 | 
						|
					v, v->sok, v->servername);
 | 
						|
		PrintText (sess, tbuf);
 | 
						|
		list = list->next;
 | 
						|
	}
 | 
						|
 | 
						|
	sprintf (tbuf,
 | 
						|
				"\nfront_session: %p\n"
 | 
						|
				"current_tab: %p\n\n",
 | 
						|
				sess->server->front_session, current_tab);
 | 
						|
	PrintText (sess, tbuf);
 | 
						|
#ifdef USE_DEBUG
 | 
						|
	sprintf (tbuf, "current mem: %d\n\n", current_mem_usage);
 | 
						|
	PrintText (sess, tbuf);
 | 
						|
#endif  /* !MEMORY_DEBUG */
 | 
						|
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_delbutton (struct session *sess, char *tbuf, char *word[],
 | 
						|
					char *word_eol[])
 | 
						|
{
 | 
						|
	if (*word[2])
 | 
						|
	{
 | 
						|
		if (sess->type == SESS_DIALOG)
 | 
						|
		{
 | 
						|
			if (list_delentry (&dlgbutton_list, word[2]))
 | 
						|
				fe_dlgbuttons_update (sess);
 | 
						|
		} else
 | 
						|
		{
 | 
						|
			if (list_delentry (&button_list, word[2]))
 | 
						|
				fe_buttons_update (sess);
 | 
						|
		}
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
	return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_dehop (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	int i = 2;
 | 
						|
 | 
						|
	while (1)
 | 
						|
	{
 | 
						|
		if (!*word[i])
 | 
						|
		{
 | 
						|
			if (i == 2)
 | 
						|
				return FALSE;
 | 
						|
			send_channel_modes (sess, tbuf, word, 2, i, '-', 'h', 0);
 | 
						|
			return TRUE;
 | 
						|
		}
 | 
						|
		i++;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_deop (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	int i = 2;
 | 
						|
 | 
						|
	while (1)
 | 
						|
	{
 | 
						|
		if (!*word[i])
 | 
						|
		{
 | 
						|
			if (i == 2)
 | 
						|
				return FALSE;
 | 
						|
			send_channel_modes (sess, tbuf, word, 2, i, '-', 'o', 0);
 | 
						|
			return TRUE;
 | 
						|
		}
 | 
						|
		i++;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
typedef struct
 | 
						|
{
 | 
						|
	char **nicks;
 | 
						|
	int i;
 | 
						|
	session *sess;
 | 
						|
	char *reason;
 | 
						|
	char *tbuf;
 | 
						|
} multidata;
 | 
						|
 | 
						|
static int
 | 
						|
mdehop_cb (struct User *user, multidata *data)
 | 
						|
{
 | 
						|
	if (user->hop && !user->me)
 | 
						|
	{
 | 
						|
		data->nicks[data->i] = user->nick;
 | 
						|
		data->i++;
 | 
						|
	}
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_mdehop (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	char **nicks = malloc (sizeof (char *) * sess->hops);
 | 
						|
	multidata data;
 | 
						|
 | 
						|
	data.nicks = nicks;
 | 
						|
	data.i = 0;
 | 
						|
	tree_foreach (sess->usertree, (tree_traverse_func *)mdehop_cb, &data);
 | 
						|
	send_channel_modes (sess, tbuf, nicks, 0, data.i, '-', 'h', 0);
 | 
						|
	free (nicks);
 | 
						|
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
mdeop_cb (struct User *user, multidata *data)
 | 
						|
{
 | 
						|
	if (user->op && !user->me)
 | 
						|
	{
 | 
						|
		data->nicks[data->i] = user->nick;
 | 
						|
		data->i++;
 | 
						|
	}
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_mdeop (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	char **nicks = malloc (sizeof (char *) * sess->ops);
 | 
						|
	multidata data;
 | 
						|
 | 
						|
	data.nicks = nicks;
 | 
						|
	data.i = 0;
 | 
						|
	tree_foreach (sess->usertree, (tree_traverse_func *)mdeop_cb, &data);
 | 
						|
	send_channel_modes (sess, tbuf, nicks, 0, data.i, '-', 'o', 0);
 | 
						|
	free (nicks);
 | 
						|
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
GSList *menu_list = NULL;
 | 
						|
 | 
						|
static void
 | 
						|
menu_free (menu_entry *me)
 | 
						|
{
 | 
						|
	free (me->path);
 | 
						|
	if (me->label)
 | 
						|
		free (me->label);
 | 
						|
	if (me->cmd)
 | 
						|
		free (me->cmd);
 | 
						|
	if (me->ucmd)
 | 
						|
		free (me->ucmd);
 | 
						|
	if (me->group)
 | 
						|
		free (me->group);
 | 
						|
	if (me->icon)
 | 
						|
		free (me->icon);
 | 
						|
	free (me);
 | 
						|
}
 | 
						|
 | 
						|
/* strings equal? but ignore underscores */
 | 
						|
 | 
						|
int
 | 
						|
menu_streq (const char *s1, const char *s2, int def)
 | 
						|
{
 | 
						|
	/* for separators */
 | 
						|
	if (s1 == NULL && s2 == NULL)
 | 
						|
		return 0;
 | 
						|
	if (s1 == NULL || s2 == NULL)
 | 
						|
		return 1;
 | 
						|
	while (*s1)
 | 
						|
	{
 | 
						|
		if (*s1 == '_')
 | 
						|
			s1++;
 | 
						|
		if (*s2 == '_')
 | 
						|
			s2++;
 | 
						|
		if (*s1 != *s2)
 | 
						|
			return 1;
 | 
						|
		s1++;
 | 
						|
		s2++;
 | 
						|
	}
 | 
						|
	if (!*s2)
 | 
						|
		return 0;
 | 
						|
	return def;
 | 
						|
}
 | 
						|
 | 
						|
static menu_entry *
 | 
						|
menu_entry_find (char *path, char *label)
 | 
						|
{
 | 
						|
	GSList *list;
 | 
						|
	menu_entry *me;
 | 
						|
 | 
						|
	list = menu_list;
 | 
						|
	while (list)
 | 
						|
	{
 | 
						|
		me = list->data;
 | 
						|
		if (!strcmp (path, me->path))
 | 
						|
		{
 | 
						|
			if (me->label && label && !strcmp (label, me->label))
 | 
						|
				return me;
 | 
						|
		}
 | 
						|
		list = list->next;
 | 
						|
	}
 | 
						|
	return NULL;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
menu_del_children (char *path, char *label)
 | 
						|
{
 | 
						|
	GSList *list, *next;
 | 
						|
	menu_entry *me;
 | 
						|
	char buf[512];
 | 
						|
 | 
						|
	if (!label)
 | 
						|
		label = "";
 | 
						|
	if (path[0])
 | 
						|
		snprintf (buf, sizeof (buf), "%s/%s", path, label);
 | 
						|
	else
 | 
						|
		snprintf (buf, sizeof (buf), "%s", label);
 | 
						|
 | 
						|
	list = menu_list;
 | 
						|
	while (list)
 | 
						|
	{
 | 
						|
		me = list->data;
 | 
						|
		next = list->next;
 | 
						|
		if (!menu_streq (buf, me->path, 0))
 | 
						|
		{
 | 
						|
			menu_list = g_slist_remove (menu_list, me);
 | 
						|
			menu_free (me);
 | 
						|
		}
 | 
						|
		list = next;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
menu_del (char *path, char *label)
 | 
						|
{
 | 
						|
	GSList *list;
 | 
						|
	menu_entry *me;
 | 
						|
 | 
						|
	list = menu_list;
 | 
						|
	while (list)
 | 
						|
	{
 | 
						|
		me = list->data;
 | 
						|
		if (!menu_streq (me->label, label, 1) && !menu_streq (me->path, path, 1))
 | 
						|
		{
 | 
						|
			menu_list = g_slist_remove (menu_list, me);
 | 
						|
			fe_menu_del (me);
 | 
						|
			menu_free (me);
 | 
						|
			/* delete this item's children, if any */
 | 
						|
			menu_del_children (path, label);
 | 
						|
			return 1;
 | 
						|
		}
 | 
						|
		list = list->next;
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static char
 | 
						|
menu_is_mainmenu_root (char *path, gint16 *offset)
 | 
						|
{
 | 
						|
	static const char *menus[] = {"\x4$TAB","\x5$TRAY","\x4$URL","\x5$NICK","\x5$CHAN"};
 | 
						|
	int i;
 | 
						|
 | 
						|
	for (i = 0; i < 5; i++)
 | 
						|
	{
 | 
						|
		if (!strncmp (path, menus[i] + 1, menus[i][0]))
 | 
						|
		{
 | 
						|
			*offset = menus[i][0] + 1;	/* number of bytes to offset the root */
 | 
						|
			return 0;	/* is not main menu */
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	*offset = 0;
 | 
						|
	return 1;	/* is main menu */
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
menu_add (char *path, char *label, char *cmd, char *ucmd, int pos, int state, int markup, int enable, int mod, int key, char *group, char *icon)
 | 
						|
{
 | 
						|
	menu_entry *me;
 | 
						|
 | 
						|
	/* already exists? */
 | 
						|
	me = menu_entry_find (path, label);
 | 
						|
	if (me)
 | 
						|
	{
 | 
						|
		/* update only */
 | 
						|
		me->state = state;
 | 
						|
		me->enable = enable;
 | 
						|
		fe_menu_update (me);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	me = malloc (sizeof (menu_entry));
 | 
						|
	me->pos = pos;
 | 
						|
	me->modifier = mod;
 | 
						|
	me->is_main = menu_is_mainmenu_root (path, &me->root_offset);
 | 
						|
	me->state = state;
 | 
						|
	me->markup = markup;
 | 
						|
	me->enable = enable;
 | 
						|
	me->key = key;
 | 
						|
	me->path = strdup (path);
 | 
						|
	me->label = NULL;
 | 
						|
	me->cmd = NULL;
 | 
						|
	me->ucmd = NULL;
 | 
						|
	me->group = NULL;
 | 
						|
	me->icon = NULL;
 | 
						|
 | 
						|
	if (label)
 | 
						|
		me->label = strdup (label);
 | 
						|
	if (cmd)
 | 
						|
		me->cmd = strdup (cmd);
 | 
						|
	if (ucmd)
 | 
						|
		me->ucmd = strdup (ucmd);
 | 
						|
	if (group)
 | 
						|
		me->group = strdup (group);
 | 
						|
	if (icon)
 | 
						|
		me->icon = strdup (icon);
 | 
						|
 | 
						|
	menu_list = g_slist_append (menu_list, me);
 | 
						|
	label = fe_menu_add (me);
 | 
						|
	if (label)
 | 
						|
	{
 | 
						|
		/* FE has given us a stripped label */
 | 
						|
		free (me->label);
 | 
						|
		me->label = strdup (label);
 | 
						|
		g_free (label); /* this is from pango */
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_menu (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	int idx = 2;
 | 
						|
	int len;
 | 
						|
	int pos = 0xffff;
 | 
						|
	int state;
 | 
						|
	int toggle = FALSE;
 | 
						|
	int enable = TRUE;
 | 
						|
	int markup = FALSE;
 | 
						|
	int key = 0;
 | 
						|
	int mod = 0;
 | 
						|
	char *label;
 | 
						|
	char *group = NULL;
 | 
						|
	char *icon = NULL;
 | 
						|
 | 
						|
	if (!word[2][0] || !word[3][0])
 | 
						|
		return FALSE;
 | 
						|
 | 
						|
	/* -eX enabled or not? */
 | 
						|
	if (word[idx][0] == '-' && word[idx][1] == 'e')
 | 
						|
	{
 | 
						|
		enable = atoi (word[idx] + 2);
 | 
						|
		idx++;
 | 
						|
	}
 | 
						|
 | 
						|
	/* -i<ICONFILE> */
 | 
						|
	if (word[idx][0] == '-' && word[idx][1] == 'i')
 | 
						|
	{
 | 
						|
		icon = word[idx] + 2;
 | 
						|
		idx++;
 | 
						|
	}
 | 
						|
 | 
						|
	/* -k<mod>,<key> key binding */
 | 
						|
	if (word[idx][0] == '-' && word[idx][1] == 'k')
 | 
						|
	{
 | 
						|
		char *comma = strchr (word[idx], ',');
 | 
						|
		if (!comma)
 | 
						|
			return FALSE;
 | 
						|
		mod = atoi (word[idx] + 2);
 | 
						|
		key = atoi (comma + 1);
 | 
						|
		idx++;
 | 
						|
	}
 | 
						|
 | 
						|
	/* -m to specify PangoMarkup language */
 | 
						|
	if (word[idx][0] == '-' && word[idx][1] == 'm')
 | 
						|
	{
 | 
						|
		markup = TRUE;
 | 
						|
		idx++;
 | 
						|
	}
 | 
						|
 | 
						|
	/* -pX to specify menu position */
 | 
						|
	if (word[idx][0] == '-' && word[idx][1] == 'p')
 | 
						|
	{
 | 
						|
		pos = atoi (word[idx] + 2);
 | 
						|
		idx++;
 | 
						|
	}
 | 
						|
 | 
						|
	/* -rSTATE,GROUP to specify a radio item */
 | 
						|
	if (word[idx][0] == '-' && word[idx][1] == 'r')
 | 
						|
	{
 | 
						|
		state = atoi (word[idx] + 2);
 | 
						|
		group = word[idx] + 4;
 | 
						|
		idx++;
 | 
						|
	}
 | 
						|
 | 
						|
	/* -tX to specify toggle item with default state */
 | 
						|
	if (word[idx][0] == '-' && word[idx][1] == 't')
 | 
						|
	{
 | 
						|
		state = atoi (word[idx] + 2);
 | 
						|
		idx++;
 | 
						|
		toggle = TRUE;
 | 
						|
	}
 | 
						|
 | 
						|
	if (word[idx+1][0] == 0)
 | 
						|
		return FALSE;
 | 
						|
 | 
						|
	/* the path */
 | 
						|
	path_part (word[idx+1], tbuf, 512);
 | 
						|
	len = strlen (tbuf);
 | 
						|
	if (len)
 | 
						|
		tbuf[len - 1] = 0;
 | 
						|
 | 
						|
	/* the name of the item */
 | 
						|
	label = file_part (word[idx + 1]);
 | 
						|
	if (label[0] == '-' && label[1] == 0)
 | 
						|
		label = NULL;	/* separator */
 | 
						|
 | 
						|
	if (markup)
 | 
						|
	{
 | 
						|
		char *p;	/* to force pango closing tags through */
 | 
						|
		for (p = label; *p; p++)
 | 
						|
			if (*p == 3)
 | 
						|
				*p = '/';
 | 
						|
	}
 | 
						|
 | 
						|
	if (!strcasecmp (word[idx], "ADD"))
 | 
						|
	{
 | 
						|
		if (toggle)
 | 
						|
		{
 | 
						|
			menu_add (tbuf, label, word[idx + 2], word[idx + 3], pos, state, markup, enable, mod, key, NULL, NULL);
 | 
						|
		} else
 | 
						|
		{
 | 
						|
			if (word[idx + 2][0])
 | 
						|
				menu_add (tbuf, label, word[idx + 2], NULL, pos, state, markup, enable, mod, key, group, icon);
 | 
						|
			else
 | 
						|
				menu_add (tbuf, label, NULL, NULL, pos, state, markup, enable, mod, key, group, icon);
 | 
						|
		}
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
 | 
						|
	if (!strcasecmp (word[idx], "DEL"))
 | 
						|
	{
 | 
						|
		menu_del (tbuf, label);
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
 | 
						|
	return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
mkick_cb (struct User *user, multidata *data)
 | 
						|
{
 | 
						|
	if (!user->op && !user->me)
 | 
						|
		data->sess->server->p_kick (data->sess->server, data->sess->channel, user->nick, data->reason);
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
mkickops_cb (struct User *user, multidata *data)
 | 
						|
{
 | 
						|
	if (user->op && !user->me)
 | 
						|
		data->sess->server->p_kick (data->sess->server, data->sess->channel, user->nick, data->reason);
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_mkick (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	multidata data;
 | 
						|
 | 
						|
	data.sess = sess;
 | 
						|
	data.reason = word_eol[2];
 | 
						|
	tree_foreach (sess->usertree, (tree_traverse_func *)mkickops_cb, &data);
 | 
						|
	tree_foreach (sess->usertree, (tree_traverse_func *)mkick_cb, &data);
 | 
						|
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_devoice (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	int i = 2;
 | 
						|
 | 
						|
	while (1)
 | 
						|
	{
 | 
						|
		if (!*word[i])
 | 
						|
		{
 | 
						|
			if (i == 2)
 | 
						|
				return FALSE;
 | 
						|
			send_channel_modes (sess, tbuf, word, 2, i, '-', 'v', 0);
 | 
						|
			return TRUE;
 | 
						|
		}
 | 
						|
		i++;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_discon (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	sess->server->disconnect (sess, TRUE, -1);
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_dns (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
#ifdef WIN32
 | 
						|
	PrintText (sess, "DNS is not implemented in Windows.\n");
 | 
						|
	return TRUE;
 | 
						|
#else
 | 
						|
	char *nick = word[2];
 | 
						|
	struct User *user;
 | 
						|
 | 
						|
	if (*nick)
 | 
						|
	{
 | 
						|
		if (strchr (nick, '.') == NULL)
 | 
						|
		{
 | 
						|
			user = userlist_find (sess, nick);
 | 
						|
			if (user && user->hostname)
 | 
						|
			{
 | 
						|
				do_dns (sess, user->nick, user->hostname);
 | 
						|
			} else
 | 
						|
			{
 | 
						|
				sess->server->p_get_ip (sess->server, nick);
 | 
						|
				sess->server->doing_dns = TRUE;
 | 
						|
			}
 | 
						|
		} else
 | 
						|
		{
 | 
						|
			snprintf (tbuf, TBUFSIZE, "exec -d %s %s", prefs.dnsprogram, nick);
 | 
						|
			handle_command (sess, tbuf, FALSE);
 | 
						|
		}
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
	return FALSE;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_echo (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	PrintText (sess, word_eol[2]);
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
#ifndef WIN32
 | 
						|
 | 
						|
static void
 | 
						|
exec_check_process (struct session *sess)
 | 
						|
{
 | 
						|
	int val;
 | 
						|
 | 
						|
	if (sess->running_exec == NULL)
 | 
						|
		return;
 | 
						|
	val = waitpid (sess->running_exec->childpid, NULL, WNOHANG);
 | 
						|
	if (val == -1 || val > 0)
 | 
						|
	{
 | 
						|
		close (sess->running_exec->myfd);
 | 
						|
		fe_input_remove (sess->running_exec->iotag);
 | 
						|
		free (sess->running_exec);
 | 
						|
		sess->running_exec = NULL;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
#ifndef __EMX__
 | 
						|
static int
 | 
						|
cmd_execs (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	int r;
 | 
						|
 | 
						|
	exec_check_process (sess);
 | 
						|
	if (sess->running_exec == NULL)
 | 
						|
	{
 | 
						|
		EMIT_SIGNAL (XP_TE_NOCHILD, sess, NULL, NULL, NULL, NULL, 0);
 | 
						|
		return FALSE;
 | 
						|
	}
 | 
						|
	r = kill (sess->running_exec->childpid, SIGSTOP);
 | 
						|
	if (r == -1)
 | 
						|
		PrintText (sess, "Error in kill(2)\n");
 | 
						|
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_execc (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	int r;
 | 
						|
 | 
						|
	exec_check_process (sess);
 | 
						|
	if (sess->running_exec == NULL)
 | 
						|
	{
 | 
						|
		EMIT_SIGNAL (XP_TE_NOCHILD, sess, NULL, NULL, NULL, NULL, 0);
 | 
						|
		return FALSE;
 | 
						|
	}
 | 
						|
	r = kill (sess->running_exec->childpid, SIGCONT);
 | 
						|
	if (r == -1)
 | 
						|
		PrintText (sess, "Error in kill(2)\n");
 | 
						|
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_execk (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	int r;
 | 
						|
 | 
						|
	exec_check_process (sess);
 | 
						|
	if (sess->running_exec == NULL)
 | 
						|
	{
 | 
						|
		EMIT_SIGNAL (XP_TE_NOCHILD, sess, NULL, NULL, NULL, NULL, 0);
 | 
						|
		return FALSE;
 | 
						|
	}
 | 
						|
	if (strcmp (word[2], "-9") == 0)
 | 
						|
		r = kill (sess->running_exec->childpid, SIGKILL);
 | 
						|
	else
 | 
						|
		r = kill (sess->running_exec->childpid, SIGTERM);
 | 
						|
	if (r == -1)
 | 
						|
		PrintText (sess, "Error in kill(2)\n");
 | 
						|
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
/* OS/2 Can't have the /EXECW command because it uses pipe(2) not socketpair
 | 
						|
   and thus it is simplex --AGL */
 | 
						|
static int
 | 
						|
cmd_execw (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	int len;
 | 
						|
	char *temp;
 | 
						|
	exec_check_process (sess);
 | 
						|
	if (sess->running_exec == NULL)
 | 
						|
	{
 | 
						|
		EMIT_SIGNAL (XP_TE_NOCHILD, sess, NULL, NULL, NULL, NULL, 0);
 | 
						|
		return FALSE;
 | 
						|
	}
 | 
						|
	len = strlen(word_eol[2]);
 | 
						|
	temp = malloc(len + 2);
 | 
						|
	sprintf(temp, "%s\n", word_eol[2]);
 | 
						|
	PrintText(sess, temp);
 | 
						|
	write(sess->running_exec->myfd, temp, len + 1);
 | 
						|
	free(temp);
 | 
						|
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
#endif /* !__EMX__ */
 | 
						|
 | 
						|
/* convert ANSI escape color codes to mIRC codes */
 | 
						|
 | 
						|
static short escconv[] =
 | 
						|
/* 0 1 2 3 4 5  6 7  0 1 2 3 4  5  6  7 */
 | 
						|
{  1,4,3,5,2,10,6,1, 1,7,9,8,12,11,13,1 };
 | 
						|
 | 
						|
static void
 | 
						|
exec_handle_colors (char *buf, int len)
 | 
						|
{
 | 
						|
	char numb[16];
 | 
						|
	char *nbuf;
 | 
						|
	int i = 0, j = 0, k = 0, firstn = 0, col, colf = 0, colb = 0;
 | 
						|
	int esc = FALSE, backc = FALSE, bold = FALSE;
 | 
						|
 | 
						|
	/* any escape codes in this text? */
 | 
						|
	if (strchr (buf, 27) == 0)
 | 
						|
		return;
 | 
						|
 | 
						|
	nbuf = malloc (len + 1);
 | 
						|
 | 
						|
	while (i < len)
 | 
						|
	{
 | 
						|
		switch (buf[i])
 | 
						|
		{
 | 
						|
		case '\r':
 | 
						|
			break;
 | 
						|
		case 27:
 | 
						|
			esc = TRUE;
 | 
						|
			break;
 | 
						|
		case ';':
 | 
						|
			if (!esc)
 | 
						|
				goto norm;
 | 
						|
			backc = TRUE;
 | 
						|
			numb[k] = 0;
 | 
						|
			firstn = atoi (numb);
 | 
						|
			k = 0;
 | 
						|
			break;
 | 
						|
		case '[':
 | 
						|
			if (!esc)
 | 
						|
				goto norm;
 | 
						|
			break;
 | 
						|
		default:
 | 
						|
			if (esc)
 | 
						|
			{
 | 
						|
				if (buf[i] >= 'A' && buf[i] <= 'z')
 | 
						|
				{
 | 
						|
					if (buf[i] == 'm')
 | 
						|
					{
 | 
						|
						/* ^[[0m */
 | 
						|
						if (k == 0 || (numb[0] == '0' && k == 1))
 | 
						|
						{
 | 
						|
							nbuf[j] = '\017';
 | 
						|
							j++;
 | 
						|
							bold = FALSE;
 | 
						|
							goto cont;
 | 
						|
						}
 | 
						|
 | 
						|
						numb[k] = 0;
 | 
						|
						col = atoi (numb);
 | 
						|
						backc = FALSE;
 | 
						|
 | 
						|
						if (firstn == 1)
 | 
						|
							bold = TRUE;
 | 
						|
 | 
						|
						if (firstn >= 30 && firstn <= 37)
 | 
						|
							colf = firstn - 30;
 | 
						|
 | 
						|
						if (col >= 40)
 | 
						|
						{
 | 
						|
							colb = col - 40;
 | 
						|
							backc = TRUE;
 | 
						|
						}
 | 
						|
 | 
						|
						if (col >= 30 && col <= 37)
 | 
						|
							colf = col - 30;
 | 
						|
 | 
						|
						if (bold)
 | 
						|
							colf += 8;
 | 
						|
 | 
						|
						if (backc)
 | 
						|
						{
 | 
						|
							colb = escconv[colb % 14];
 | 
						|
							colf = escconv[colf % 14];
 | 
						|
							j += sprintf (&nbuf[j], "\003%d,%02d", colf, colb);
 | 
						|
						} else
 | 
						|
						{
 | 
						|
							colf = escconv[colf % 14];
 | 
						|
							j += sprintf (&nbuf[j], "\003%02d", colf);
 | 
						|
						}
 | 
						|
					}
 | 
						|
cont:				esc = FALSE;
 | 
						|
					backc = FALSE;
 | 
						|
					k = 0;
 | 
						|
				} else
 | 
						|
				{
 | 
						|
					if (isdigit ((unsigned char) buf[i]) && k < (sizeof (numb) - 1))
 | 
						|
					{
 | 
						|
						numb[k] = buf[i];
 | 
						|
						k++;
 | 
						|
					}
 | 
						|
				}
 | 
						|
			} else
 | 
						|
			{
 | 
						|
norm:			nbuf[j] = buf[i];
 | 
						|
				j++;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		i++;
 | 
						|
	}
 | 
						|
 | 
						|
	nbuf[j] = 0;
 | 
						|
	memcpy (buf, nbuf, j + 1);
 | 
						|
	free (nbuf);
 | 
						|
}
 | 
						|
 | 
						|
#ifndef HAVE_MEMRCHR
 | 
						|
static void *
 | 
						|
memrchr (const void *block, int c, size_t size)
 | 
						|
{
 | 
						|
	unsigned char *p;
 | 
						|
 | 
						|
	for (p = (unsigned char *)block + size; p != block; p--)
 | 
						|
		if (*p == c)
 | 
						|
			return p;
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
static gboolean
 | 
						|
exec_data (GIOChannel *source, GIOCondition condition, struct nbexec *s)
 | 
						|
{
 | 
						|
	char *buf, *readpos, *rest;
 | 
						|
	int rd, len;
 | 
						|
	int sok = s->myfd;
 | 
						|
 | 
						|
	len = s->buffill;
 | 
						|
	if (len) {
 | 
						|
		/* append new data to buffered incomplete line */
 | 
						|
		buf = malloc(len + 2050);
 | 
						|
		memcpy(buf, s->linebuf, len);
 | 
						|
		readpos = buf + len;
 | 
						|
		free(s->linebuf);
 | 
						|
		s->linebuf = NULL;
 | 
						|
	}
 | 
						|
	else
 | 
						|
		readpos = buf = malloc(2050);
 | 
						|
 | 
						|
	rd = read (sok, readpos, 2048);
 | 
						|
	if (rd < 1)
 | 
						|
	{
 | 
						|
		/* The process has died */
 | 
						|
		kill(s->childpid, SIGKILL);
 | 
						|
		if (len) {
 | 
						|
			buf[len] = '\0';
 | 
						|
			exec_handle_colors(buf, len);
 | 
						|
			if (s->tochannel)
 | 
						|
			{
 | 
						|
				/* must turn off auto-completion temporarily */
 | 
						|
				unsigned int old = prefs.nickcompletion;
 | 
						|
				prefs.nickcompletion = 0;
 | 
						|
				handle_multiline (s->sess, buf, FALSE, TRUE);
 | 
						|
				prefs.nickcompletion = old;
 | 
						|
			}
 | 
						|
			else
 | 
						|
				PrintText (s->sess, buf);
 | 
						|
		}
 | 
						|
		free(buf);
 | 
						|
		waitpid (s->childpid, NULL, 0);
 | 
						|
		s->sess->running_exec = NULL;
 | 
						|
		fe_input_remove (s->iotag);
 | 
						|
		close (sok);
 | 
						|
		free (s);
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
	len += rd;
 | 
						|
	buf[len] = '\0';
 | 
						|
 | 
						|
	rest = memrchr(buf, '\n', len);
 | 
						|
	if (rest)
 | 
						|
		rest++;
 | 
						|
	else
 | 
						|
		rest = buf;
 | 
						|
	if (*rest) {
 | 
						|
		s->buffill = len - (rest - buf); /* = strlen(rest) */
 | 
						|
		s->linebuf = malloc(s->buffill);
 | 
						|
		memcpy(s->linebuf, rest, s->buffill);
 | 
						|
		*rest = '\0';
 | 
						|
		len -= s->buffill; /* possibly 0 */
 | 
						|
	}
 | 
						|
	else
 | 
						|
		s->buffill = 0;
 | 
						|
 | 
						|
	if (len) {
 | 
						|
		exec_handle_colors (buf, len);
 | 
						|
		if (s->tochannel)
 | 
						|
			handle_multiline (s->sess, buf, FALSE, TRUE);
 | 
						|
		else
 | 
						|
			PrintText (s->sess, buf);
 | 
						|
	}
 | 
						|
 | 
						|
	free(buf);
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_exec (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	int tochannel = FALSE;
 | 
						|
	char *cmd = word_eol[2];
 | 
						|
	int fds[2], pid = 0;
 | 
						|
	struct nbexec *s;
 | 
						|
	int shell = TRUE;
 | 
						|
	int fd;
 | 
						|
 | 
						|
	if (*cmd)
 | 
						|
	{
 | 
						|
		exec_check_process (sess);
 | 
						|
		if (sess->running_exec != NULL)
 | 
						|
		{
 | 
						|
			EMIT_SIGNAL (XP_TE_ALREADYPROCESS, sess, NULL, NULL, NULL, NULL, 0);
 | 
						|
			return TRUE;
 | 
						|
		}
 | 
						|
 | 
						|
		if (!strcmp (word[2], "-d"))
 | 
						|
		{
 | 
						|
			if (!*word[3])
 | 
						|
				return FALSE;
 | 
						|
			cmd = word_eol[3];
 | 
						|
			shell = FALSE;
 | 
						|
		}
 | 
						|
		else if (!strcmp (word[2], "-o"))
 | 
						|
		{
 | 
						|
			if (!*word[3])
 | 
						|
				return FALSE;
 | 
						|
			cmd = word_eol[3];
 | 
						|
			tochannel = TRUE;
 | 
						|
		}
 | 
						|
 | 
						|
		if (shell)
 | 
						|
		{
 | 
						|
			if (access ("/bin/sh", X_OK) != 0)
 | 
						|
			{
 | 
						|
				fe_message (_("I need /bin/sh to run!\n"), FE_MSG_ERROR);
 | 
						|
				return TRUE;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
#ifdef __EMX__						  /* if os/2 */
 | 
						|
		if (pipe (fds) < 0)
 | 
						|
		{
 | 
						|
			PrintText (sess, "Pipe create error\n");
 | 
						|
			return FALSE;
 | 
						|
		}
 | 
						|
		setmode (fds[0], O_BINARY);
 | 
						|
		setmode (fds[1], O_BINARY);
 | 
						|
#else
 | 
						|
		if (socketpair (PF_UNIX, SOCK_STREAM, 0, fds) == -1)
 | 
						|
		{
 | 
						|
			PrintText (sess, "socketpair(2) failed\n");
 | 
						|
			return FALSE;
 | 
						|
		}
 | 
						|
#endif
 | 
						|
		s = (struct nbexec *) malloc (sizeof (struct nbexec));
 | 
						|
		memset(s, 0, sizeof(*s));
 | 
						|
		s->myfd = fds[0];
 | 
						|
		s->tochannel = tochannel;
 | 
						|
		s->sess = sess;
 | 
						|
 | 
						|
		pid = fork ();
 | 
						|
		if (pid == 0)
 | 
						|
		{
 | 
						|
			/* This is the child's context */
 | 
						|
			close (0);
 | 
						|
			close (1);
 | 
						|
			close (2);
 | 
						|
			/* Close parent's end of pipe */
 | 
						|
			close(s->myfd);
 | 
						|
			/* Copy the child end of the pipe to stdout and stderr */
 | 
						|
			dup2 (fds[1], 1);
 | 
						|
			dup2 (fds[1], 2);
 | 
						|
			/* Also copy it to stdin so we can write to it */
 | 
						|
			dup2 (fds[1], 0);
 | 
						|
			/* Now close all open file descriptors except stdin, stdout and stderr */
 | 
						|
			for (fd = 3; fd < 1024; fd++) close(fd);
 | 
						|
			/* Now we call /bin/sh to run our cmd ; made it more friendly -DC1 */
 | 
						|
			if (shell)
 | 
						|
			{
 | 
						|
				execl ("/bin/sh", "sh", "-c", cmd, NULL);
 | 
						|
			} else
 | 
						|
			{
 | 
						|
				char **argv;
 | 
						|
				int argc;
 | 
						|
 | 
						|
				my_poptParseArgvString (cmd, &argc, &argv);
 | 
						|
				execvp (argv[0], argv);
 | 
						|
			}
 | 
						|
			/* not reached unless error */
 | 
						|
			/*printf("exec error\n");*/
 | 
						|
			fflush (stdout);
 | 
						|
			fflush (stdin);
 | 
						|
			_exit (0);
 | 
						|
		}
 | 
						|
		if (pid == -1)
 | 
						|
		{
 | 
						|
			/* Parent context, fork() failed */
 | 
						|
 | 
						|
			PrintText (sess, "Error in fork(2)\n");
 | 
						|
			close(fds[0]);
 | 
						|
			close(fds[1]);
 | 
						|
		} else
 | 
						|
		{
 | 
						|
			/* Parent path */
 | 
						|
			close(fds[1]);
 | 
						|
			s->childpid = pid;
 | 
						|
			s->iotag = fe_input_add (s->myfd, FIA_READ|FIA_EX, exec_data, s);
 | 
						|
			sess->running_exec = s;
 | 
						|
			return TRUE;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
static int
 | 
						|
cmd_flushq (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	sprintf (tbuf, "Flushing server send queue, %d bytes.\n", sess->server->sendq_len);
 | 
						|
	PrintText (sess, tbuf);
 | 
						|
	sess->server->flush_queue (sess->server);
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_quit (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	if (*word_eol[2])
 | 
						|
		sess->quitreason = word_eol[2];
 | 
						|
	sess->server->disconnect (sess, TRUE, -1);
 | 
						|
	sess->quitreason = NULL;
 | 
						|
	return 2;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_gate (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	char *server_name = word[2];
 | 
						|
	server *serv = sess->server;
 | 
						|
	if (*server_name)
 | 
						|
	{
 | 
						|
		char *port = word[3];
 | 
						|
#ifdef USE_OPENSSL
 | 
						|
		serv->use_ssl = FALSE;
 | 
						|
#endif
 | 
						|
		server_fill_her_up (serv);
 | 
						|
		if (*port)
 | 
						|
			serv->connect (serv, server_name, atoi (port), TRUE);
 | 
						|
		else
 | 
						|
			serv->connect (serv, server_name, 23, TRUE);
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
	return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
typedef struct
 | 
						|
{
 | 
						|
	char *cmd;
 | 
						|
	session *sess;
 | 
						|
} getvalinfo;
 | 
						|
 | 
						|
static void
 | 
						|
get_int_cb (int cancel, int val, getvalinfo *info)
 | 
						|
{
 | 
						|
	char buf[512];
 | 
						|
 | 
						|
	if (!cancel)
 | 
						|
	{
 | 
						|
		snprintf (buf, sizeof (buf), "%s %d", info->cmd, val);
 | 
						|
		if (is_session (info->sess))
 | 
						|
			handle_command (info->sess, buf, FALSE);
 | 
						|
	}
 | 
						|
 | 
						|
	free (info->cmd);
 | 
						|
	free (info);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_getint (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	getvalinfo *info;
 | 
						|
 | 
						|
	if (!word[4][0])
 | 
						|
		return FALSE;
 | 
						|
 | 
						|
	info = malloc (sizeof (*info));
 | 
						|
	info->cmd = strdup (word[3]);
 | 
						|
	info->sess = sess;
 | 
						|
 | 
						|
	fe_get_int (word[4], atoi (word[2]), get_int_cb, info);
 | 
						|
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
get_file_cb (char *cmd, char *file)
 | 
						|
{
 | 
						|
	char buf[1024 + 128];
 | 
						|
 | 
						|
	/* execute the command once per file, then once more with
 | 
						|
      no args */
 | 
						|
	if (file)
 | 
						|
	{
 | 
						|
		snprintf (buf, sizeof (buf), "%s %s", cmd, file);
 | 
						|
		handle_command (current_sess, buf, FALSE);
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		handle_command (current_sess, cmd, FALSE);
 | 
						|
		free (cmd);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_getfile (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	int idx = 2;
 | 
						|
	int flags = 0;
 | 
						|
 | 
						|
	if (!word[3][0])
 | 
						|
		return FALSE;
 | 
						|
 | 
						|
	if (!strcmp (word[2], "-folder"))
 | 
						|
	{
 | 
						|
		flags |= FRF_CHOOSEFOLDER;
 | 
						|
		idx++;
 | 
						|
	}
 | 
						|
 | 
						|
	if (!strcmp (word[idx], "-multi"))
 | 
						|
	{
 | 
						|
		flags |= FRF_MULTIPLE;
 | 
						|
		idx++;
 | 
						|
	}
 | 
						|
 | 
						|
	if (!strcmp (word[idx], "-save"))
 | 
						|
	{
 | 
						|
		flags |= FRF_WRITE;
 | 
						|
		idx++;
 | 
						|
	}
 | 
						|
 | 
						|
	fe_get_file (word[idx+1], word[idx+2], (void *)get_file_cb, strdup (word[idx]), flags);
 | 
						|
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
get_str_cb (int cancel, char *val, getvalinfo *info)
 | 
						|
{
 | 
						|
	char buf[512];
 | 
						|
 | 
						|
	if (!cancel)
 | 
						|
	{
 | 
						|
		snprintf (buf, sizeof (buf), "%s %s", info->cmd, val);
 | 
						|
		if (is_session (info->sess))
 | 
						|
			handle_command (info->sess, buf, FALSE);
 | 
						|
	}
 | 
						|
 | 
						|
	free (info->cmd);
 | 
						|
	free (info);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_getstr (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	getvalinfo *info;
 | 
						|
 | 
						|
	if (!word[4][0])
 | 
						|
		return FALSE;
 | 
						|
 | 
						|
	info = malloc (sizeof (*info));
 | 
						|
	info->cmd = strdup (word[3]);
 | 
						|
	info->sess = sess;
 | 
						|
 | 
						|
	fe_get_str (word[4], word[2], get_str_cb, info);
 | 
						|
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_ghost (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	if (!word[2][0])
 | 
						|
		return FALSE;
 | 
						|
 | 
						|
	sess->server->p_ns_ghost (sess->server, word[2], word[3]);
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_gui (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	switch (str_ihash (word[2]))
 | 
						|
	{
 | 
						|
	case 0x058b836e: fe_ctrl_gui (sess, 8, 0); break; /* APPLY */
 | 
						|
	case 0xac1eee45: fe_ctrl_gui (sess, 7, 2); break; /* ATTACH */
 | 
						|
	case 0x05a72f63: fe_ctrl_gui (sess, 4, atoi (word[3])); break; /* COLOR */
 | 
						|
	case 0xb06a1793: fe_ctrl_gui (sess, 7, 1); break; /* DETACH */
 | 
						|
	case 0x05cfeff0: fe_ctrl_gui (sess, 3, 0); break; /* FLASH */
 | 
						|
	case 0x05d154d8: fe_ctrl_gui (sess, 2, 0); break; /* FOCUS */
 | 
						|
	case 0x0030dd42: fe_ctrl_gui (sess, 0, 0); break; /* HIDE */
 | 
						|
	case 0x61addbe3: fe_ctrl_gui (sess, 5, 0); break; /* ICONIFY */
 | 
						|
	case 0xc0851aaa: fe_message (word[3], FE_MSG_INFO|FE_MSG_MARKUP); break; /* MSGBOX */
 | 
						|
	case 0x0035dafd: fe_ctrl_gui (sess, 1, 0); break; /* SHOW */
 | 
						|
	case 0x0033155f: /* MENU */
 | 
						|
		if (!strcasecmp (word[3], "TOGGLE"))
 | 
						|
			fe_ctrl_gui (sess, 6, 0);
 | 
						|
		else
 | 
						|
			return FALSE;
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		return FALSE;
 | 
						|
	}
 | 
						|
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
typedef struct
 | 
						|
{
 | 
						|
	int longfmt;
 | 
						|
	int i, t;
 | 
						|
	char *buf;
 | 
						|
} help_list;
 | 
						|
 | 
						|
static void
 | 
						|
show_help_line (session *sess, help_list *hl, char *name, char *usage)
 | 
						|
{
 | 
						|
	int j, len, max;
 | 
						|
	char *p;
 | 
						|
 | 
						|
	if (name[0] == '.')	/* hidden command? */
 | 
						|
		return;
 | 
						|
 | 
						|
	if (hl->longfmt)	/* long format for /HELP -l */
 | 
						|
	{
 | 
						|
		if (!usage || usage[0] == 0)
 | 
						|
			PrintTextf (sess, "   \0034%s\003 :\n", name);
 | 
						|
		else
 | 
						|
			PrintTextf (sess, "   \0034%s\003 : %s\n", name, _(usage));
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* append the name into buffer, but convert to uppercase */
 | 
						|
	len = strlen (hl->buf);
 | 
						|
	p = name;
 | 
						|
	while (*p)
 | 
						|
	{
 | 
						|
		hl->buf[len] = toupper ((unsigned char) *p);
 | 
						|
		len++;
 | 
						|
		p++;
 | 
						|
	}
 | 
						|
	hl->buf[len] = 0;
 | 
						|
 | 
						|
	hl->t++;
 | 
						|
	if (hl->t == 5)
 | 
						|
	{
 | 
						|
		hl->t = 0;
 | 
						|
		strcat (hl->buf, "\n");
 | 
						|
		PrintText (sess, hl->buf);
 | 
						|
		hl->buf[0] = ' ';
 | 
						|
		hl->buf[1] = ' ';
 | 
						|
		hl->buf[2] = 0;
 | 
						|
	} else
 | 
						|
	{
 | 
						|
		/* append some spaces after the command name */
 | 
						|
		max = strlen (name);
 | 
						|
		if (max < 10)
 | 
						|
		{
 | 
						|
			max = 10 - max;
 | 
						|
			for (j = 0; j < max; j++)
 | 
						|
			{
 | 
						|
				hl->buf[len] = ' ';
 | 
						|
				len++;
 | 
						|
				hl->buf[len] = 0;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_help (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	int i = 0, longfmt = 0;
 | 
						|
	char *helpcmd = "";
 | 
						|
	GSList *list;
 | 
						|
 | 
						|
	if (tbuf)
 | 
						|
		helpcmd = word[2];
 | 
						|
	if (*helpcmd && strcmp (helpcmd, "-l") == 0)
 | 
						|
		longfmt = 1;
 | 
						|
 | 
						|
	if (*helpcmd && !longfmt)
 | 
						|
	{
 | 
						|
		help (sess, tbuf, helpcmd, FALSE);
 | 
						|
	} else
 | 
						|
	{
 | 
						|
		struct popup *pop;
 | 
						|
		char *buf = malloc (4096);
 | 
						|
		help_list hl;
 | 
						|
 | 
						|
		hl.longfmt = longfmt;
 | 
						|
		hl.buf = buf;
 | 
						|
 | 
						|
		PrintTextf (sess, "\n%s\n\n", _("Commands Available:"));
 | 
						|
		buf[0] = ' ';
 | 
						|
		buf[1] = ' ';
 | 
						|
		buf[2] = 0;
 | 
						|
		hl.t = 0;
 | 
						|
		hl.i = 0;
 | 
						|
		while (xc_cmds[i].name)
 | 
						|
		{
 | 
						|
			show_help_line (sess, &hl, xc_cmds[i].name, xc_cmds[i].help);
 | 
						|
			i++;
 | 
						|
		}
 | 
						|
		strcat (buf, "\n");
 | 
						|
		PrintText (sess, buf);
 | 
						|
 | 
						|
		PrintTextf (sess, "\n%s\n\n", _("User defined commands:"));
 | 
						|
		buf[0] = ' ';
 | 
						|
		buf[1] = ' ';
 | 
						|
		buf[2] = 0;
 | 
						|
		hl.t = 0;
 | 
						|
		hl.i = 0;
 | 
						|
		list = command_list;
 | 
						|
		while (list)
 | 
						|
		{
 | 
						|
			pop = list->data;
 | 
						|
			show_help_line (sess, &hl, pop->name, pop->cmd);
 | 
						|
			list = list->next;
 | 
						|
		}
 | 
						|
		strcat (buf, "\n");
 | 
						|
		PrintText (sess, buf);
 | 
						|
 | 
						|
		PrintTextf (sess, "\n%s\n\n", _("Plugin defined commands:"));
 | 
						|
		buf[0] = ' ';
 | 
						|
		buf[1] = ' ';
 | 
						|
		buf[2] = 0;
 | 
						|
		hl.t = 0;
 | 
						|
		hl.i = 0;
 | 
						|
		plugin_command_foreach (sess, &hl, (void *)show_help_line);
 | 
						|
		strcat (buf, "\n");
 | 
						|
		PrintText (sess, buf);
 | 
						|
		free (buf);
 | 
						|
 | 
						|
		PrintTextf (sess, "\n%s\n\n", _("Type /HELP <command> for more information, or /HELP -l"));
 | 
						|
	}
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_id (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	if (word[2][0])
 | 
						|
	{
 | 
						|
		sess->server->p_ns_identify (sess->server, word[2]);
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
 | 
						|
	return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_ignore (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	int i;
 | 
						|
	int type = 0;
 | 
						|
	int quiet = 0;
 | 
						|
	char *mask;
 | 
						|
 | 
						|
	if (!*word[2])
 | 
						|
	{
 | 
						|
		ignore_showlist (sess);
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
	if (!*word[3])
 | 
						|
		return FALSE;
 | 
						|
 | 
						|
	i = 3;
 | 
						|
	while (1)
 | 
						|
	{
 | 
						|
		if (!*word[i])
 | 
						|
		{
 | 
						|
			if (type == 0)
 | 
						|
				return FALSE;
 | 
						|
 | 
						|
			mask = word[2];
 | 
						|
			if (strchr (mask, '?') == NULL &&
 | 
						|
			    strchr (mask, '*') == NULL &&
 | 
						|
			    userlist_find (sess, mask))
 | 
						|
			{
 | 
						|
				mask = tbuf;
 | 
						|
				snprintf (tbuf, TBUFSIZE, "%s!*@*", word[2]);
 | 
						|
			}
 | 
						|
 | 
						|
			i = ignore_add (mask, type);
 | 
						|
			if (quiet)
 | 
						|
				return TRUE;
 | 
						|
			switch (i)
 | 
						|
			{
 | 
						|
			case 1:
 | 
						|
				EMIT_SIGNAL (XP_TE_IGNOREADD, sess, mask, NULL, NULL, NULL, 0);
 | 
						|
				break;
 | 
						|
			case 2:	/* old ignore changed */
 | 
						|
				EMIT_SIGNAL (XP_TE_IGNORECHANGE, sess, mask, NULL, NULL, NULL, 0);
 | 
						|
			}
 | 
						|
			return TRUE;
 | 
						|
		}
 | 
						|
		if (!strcasecmp (word[i], "UNIGNORE"))
 | 
						|
			type |= IG_UNIG;
 | 
						|
		else if (!strcasecmp (word[i], "ALL"))
 | 
						|
			type |= IG_PRIV | IG_NOTI | IG_CHAN | IG_CTCP | IG_INVI | IG_DCC;
 | 
						|
		else if (!strcasecmp (word[i], "PRIV"))
 | 
						|
			type |= IG_PRIV;
 | 
						|
		else if (!strcasecmp (word[i], "NOTI"))
 | 
						|
			type |= IG_NOTI;
 | 
						|
		else if (!strcasecmp (word[i], "CHAN"))
 | 
						|
			type |= IG_CHAN;
 | 
						|
		else if (!strcasecmp (word[i], "CTCP"))
 | 
						|
			type |= IG_CTCP;
 | 
						|
		else if (!strcasecmp (word[i], "INVI"))
 | 
						|
			type |= IG_INVI;
 | 
						|
		else if (!strcasecmp (word[i], "QUIET"))
 | 
						|
			quiet = 1;
 | 
						|
		else if (!strcasecmp (word[i], "NOSAVE"))
 | 
						|
			type |= IG_NOSAVE;
 | 
						|
		else if (!strcasecmp (word[i], "DCC"))
 | 
						|
			type |= IG_DCC;
 | 
						|
		else
 | 
						|
		{
 | 
						|
			sprintf (tbuf, _("Unknown arg '%s' ignored."), word[i]);
 | 
						|
			PrintText (sess, tbuf);
 | 
						|
		}
 | 
						|
		i++;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_invite (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	if (!*word[2])
 | 
						|
		return FALSE;
 | 
						|
	if (*word[3])
 | 
						|
		sess->server->p_invite (sess->server, word[3], word[2]);
 | 
						|
	else
 | 
						|
		sess->server->p_invite (sess->server, sess->channel, word[2]);
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_join (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	char *chan = word[2];
 | 
						|
	if (*chan)
 | 
						|
	{
 | 
						|
		char *po, *pass = word[3];
 | 
						|
		sess->server->p_join (sess->server, chan, pass);
 | 
						|
		if (sess->channel[0] == 0 && sess->waitchannel[0])
 | 
						|
		{
 | 
						|
			po = strchr (chan, ',');
 | 
						|
			if (po)
 | 
						|
				*po = 0;
 | 
						|
			safe_strcpy (sess->waitchannel, chan, CHANLEN);
 | 
						|
		}
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
	return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_kick (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	char *nick = word[2];
 | 
						|
	char *reason = word_eol[3];
 | 
						|
	if (*nick)
 | 
						|
	{
 | 
						|
		sess->server->p_kick (sess->server, sess->channel, nick, reason);
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
	return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_kickban (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	char *nick = word[2];
 | 
						|
	char *reason = word_eol[3];
 | 
						|
	struct User *user;
 | 
						|
 | 
						|
	if (*nick)
 | 
						|
	{
 | 
						|
		/* if the reason is a 1 digit number, treat it as a bantype */
 | 
						|
 | 
						|
		user = userlist_find (sess, nick);
 | 
						|
 | 
						|
		if (isdigit ((unsigned char) reason[0]) && reason[1] == 0)
 | 
						|
		{
 | 
						|
			ban (sess, tbuf, nick, reason, (user && user->op));
 | 
						|
			reason[0] = 0;
 | 
						|
		} else
 | 
						|
			ban (sess, tbuf, nick, "", (user && user->op));
 | 
						|
 | 
						|
		sess->server->p_kick (sess->server, sess->channel, nick, reason);
 | 
						|
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
	return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_killall (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	xchat_exit();
 | 
						|
	return 2;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_lagcheck (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	lag_check ();
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
lastlog (session *sess, char *search, gboolean regexp)
 | 
						|
{
 | 
						|
	session *lastlog_sess;
 | 
						|
 | 
						|
	if (!is_session (sess))
 | 
						|
		return;
 | 
						|
 | 
						|
	lastlog_sess = find_dialog (sess->server, "(lastlog)");
 | 
						|
	if (!lastlog_sess)
 | 
						|
		lastlog_sess = new_ircwindow (sess->server, "(lastlog)", SESS_DIALOG, 0);
 | 
						|
 | 
						|
	lastlog_sess->lastlog_sess = sess;
 | 
						|
	lastlog_sess->lastlog_regexp = regexp;	/* remember the search type */
 | 
						|
 | 
						|
	fe_text_clear (lastlog_sess, 0);
 | 
						|
	fe_lastlog (sess, lastlog_sess, search, regexp);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_lastlog (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	if (*word_eol[2])
 | 
						|
	{
 | 
						|
		if (!strcmp (word[2], "-r"))
 | 
						|
			lastlog (sess, word_eol[3], TRUE);
 | 
						|
		else
 | 
						|
			lastlog (sess, word_eol[2], FALSE);
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
 | 
						|
	return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_list (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	sess->server->p_list_channels (sess->server, word_eol[2], 1);
 | 
						|
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
gboolean
 | 
						|
load_perform_file (session *sess, char *file)
 | 
						|
{
 | 
						|
	char tbuf[1024 + 4];
 | 
						|
	char *nl;
 | 
						|
	FILE *fp;
 | 
						|
 | 
						|
	fp = xchat_fopen_file (file, "r", XOF_FULLPATH);
 | 
						|
	if (!fp)
 | 
						|
		return FALSE;
 | 
						|
 | 
						|
	tbuf[1024] = 0;
 | 
						|
	while (fgets (tbuf, 1024, fp))
 | 
						|
	{
 | 
						|
		nl = strchr (tbuf, '\n');
 | 
						|
		if (nl == tbuf) /* skip empty commands */
 | 
						|
			continue;
 | 
						|
		if (nl)
 | 
						|
			*nl = 0;
 | 
						|
		if (tbuf[0] == prefs.cmdchar[0])
 | 
						|
			handle_command (sess, tbuf + 1, TRUE);
 | 
						|
		else
 | 
						|
			handle_command (sess, tbuf, TRUE);
 | 
						|
	}
 | 
						|
	fclose (fp);
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_load (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	char *error, *arg, *file;
 | 
						|
	int len;
 | 
						|
 | 
						|
	if (!word[2][0])
 | 
						|
		return FALSE;
 | 
						|
 | 
						|
	if (strcmp (word[2], "-e") == 0)
 | 
						|
	{
 | 
						|
		file = expand_homedir (word[3]);
 | 
						|
		if (!load_perform_file (sess, file))
 | 
						|
		{
 | 
						|
			PrintTextf (sess, _("Cannot access %s\n"), file);
 | 
						|
			PrintText (sess, errorstring (errno));
 | 
						|
		}
 | 
						|
		free (file);
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
 | 
						|
#ifdef USE_PLUGIN
 | 
						|
	len = strlen (word[2]);
 | 
						|
#ifdef WIN32
 | 
						|
	if (len > 4 && strcasecmp (".dll", word[2] + len - 4) == 0)
 | 
						|
#else
 | 
						|
#if defined(__hpux)
 | 
						|
	if (len > 3 && strcasecmp (".sl", word[2] + len - 3) == 0)
 | 
						|
#else
 | 
						|
	if (len > 3 && strcasecmp (".so", word[2] + len - 3) == 0)
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
	{
 | 
						|
		arg = NULL;
 | 
						|
		if (word_eol[3][0])
 | 
						|
			arg = word_eol[3];
 | 
						|
 | 
						|
		file = expand_homedir (word[2]);
 | 
						|
		error = plugin_load (sess, file, arg);
 | 
						|
		free (file);
 | 
						|
 | 
						|
		if (error)
 | 
						|
			PrintText (sess, error);
 | 
						|
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
 | 
						|
	sprintf (tbuf, "Unknown file type %s. Maybe you need to install the Perl or Python plugin?\n", word[2]);
 | 
						|
	PrintText (sess, tbuf);
 | 
						|
 | 
						|
	return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_me (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	char *act = word_eol[2];
 | 
						|
 | 
						|
	if (!(*act))
 | 
						|
		return FALSE;
 | 
						|
 | 
						|
	if (sess->type == SESS_SERVER)
 | 
						|
	{
 | 
						|
		notj_msg (sess);
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
 | 
						|
	snprintf (tbuf, TBUFSIZE, "\001ACTION %s\001\r", act);
 | 
						|
	/* first try through DCC CHAT */
 | 
						|
	if (dcc_write_chat (sess->channel, tbuf))
 | 
						|
	{
 | 
						|
		/* print it to screen */
 | 
						|
		inbound_action (sess, sess->channel, sess->server->nick, "", act, TRUE, FALSE);
 | 
						|
	} else
 | 
						|
	{
 | 
						|
		/* DCC CHAT failed, try through server */
 | 
						|
		if (sess->server->connected)
 | 
						|
		{
 | 
						|
			sess->server->p_action (sess->server, sess->channel, act);
 | 
						|
			/* print it to screen */
 | 
						|
			inbound_action (sess, sess->channel, sess->server->nick, "", act, TRUE, FALSE);
 | 
						|
		} else
 | 
						|
		{
 | 
						|
			notc_msg (sess);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_mode (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	/* +channel channels are dying, let those servers whine about modes.
 | 
						|
	 * return info about current channel if available and no info is given */
 | 
						|
	if ((*word[2] == '+') || (*word[2] == 0) || (!is_channel(sess->server, word[2]) &&
 | 
						|
				!(rfc_casecmp(sess->server->nick, word[2]) == 0)))
 | 
						|
	{
 | 
						|
		if(sess->channel[0] == 0)
 | 
						|
			return FALSE;
 | 
						|
		sess->server->p_mode (sess->server, sess->channel, word_eol[2]);
 | 
						|
	}
 | 
						|
	else
 | 
						|
		sess->server->p_mode (sess->server, word[2], word_eol[3]);
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
mop_cb (struct User *user, multidata *data)
 | 
						|
{
 | 
						|
	if (!user->op)
 | 
						|
	{
 | 
						|
		data->nicks[data->i] = user->nick;
 | 
						|
		data->i++;
 | 
						|
	}
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_mop (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	char **nicks = malloc (sizeof (char *) * (sess->total - sess->ops));
 | 
						|
	multidata data;
 | 
						|
 | 
						|
	data.nicks = nicks;
 | 
						|
	data.i = 0;
 | 
						|
	tree_foreach (sess->usertree, (tree_traverse_func *)mop_cb, &data);
 | 
						|
	send_channel_modes (sess, tbuf, nicks, 0, data.i, '+', 'o', 0);
 | 
						|
 | 
						|
	free (nicks);
 | 
						|
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_msg (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	char *nick = word[2];
 | 
						|
	char *msg = word_eol[3];
 | 
						|
	struct session *newsess;
 | 
						|
 | 
						|
	if (*nick)
 | 
						|
	{
 | 
						|
		if (*msg)
 | 
						|
		{
 | 
						|
			if (strcmp (nick, ".") == 0)
 | 
						|
			{							  /* /msg the last nick /msg'ed */
 | 
						|
				if (sess->lastnick[0])
 | 
						|
					nick = sess->lastnick;
 | 
						|
			} else
 | 
						|
			{
 | 
						|
				safe_strcpy (sess->lastnick, nick, NICKLEN);	/* prime the last nick memory */
 | 
						|
			}
 | 
						|
 | 
						|
			if (*nick == '=')
 | 
						|
			{
 | 
						|
				nick++;
 | 
						|
				if (!dcc_write_chat (nick, msg))
 | 
						|
				{
 | 
						|
					EMIT_SIGNAL (XP_TE_NODCC, sess, NULL, NULL, NULL, NULL, 0);
 | 
						|
					return TRUE;
 | 
						|
				}
 | 
						|
			} else
 | 
						|
			{
 | 
						|
				if (!sess->server->connected)
 | 
						|
				{
 | 
						|
					notc_msg (sess);
 | 
						|
					return TRUE;
 | 
						|
				}
 | 
						|
				sess->server->p_message (sess->server, nick, msg);
 | 
						|
			}
 | 
						|
			newsess = find_dialog (sess->server, nick);
 | 
						|
			if (!newsess)
 | 
						|
				newsess = find_channel (sess->server, nick);
 | 
						|
			if (newsess)
 | 
						|
				inbound_chanmsg (newsess->server, NULL, newsess->channel,
 | 
						|
									  newsess->server->nick, msg, TRUE, FALSE);
 | 
						|
			else
 | 
						|
			{
 | 
						|
				/* mask out passwords */
 | 
						|
				if (strcasecmp (nick, "nickserv") == 0 &&
 | 
						|
					 strncasecmp (msg, "identify ", 9) == 0)
 | 
						|
					msg = "identify ****";
 | 
						|
				EMIT_SIGNAL (XP_TE_MSGSEND, sess, nick, msg, NULL, NULL, 0);
 | 
						|
			}
 | 
						|
 | 
						|
			return TRUE;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_names (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	if (*word[2])
 | 
						|
	  	sess->server->p_names (sess->server, word[2]);
 | 
						|
	else
 | 
						|
		sess->server->p_names (sess->server, sess->channel);
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_nctcp (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	if (*word_eol[3])
 | 
						|
	{
 | 
						|
		sess->server->p_nctcp (sess->server, word[2], word_eol[3]);
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
	return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_newserver (struct session *sess, char *tbuf, char *word[],
 | 
						|
					char *word_eol[])
 | 
						|
{
 | 
						|
	if (strcmp (word[2], "-noconnect") == 0)
 | 
						|
	{
 | 
						|
		new_ircwindow (NULL, word[3], SESS_SERVER, 0);
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
	
 | 
						|
	sess = new_ircwindow (NULL, NULL, SESS_SERVER, 0);
 | 
						|
	cmd_server (sess, tbuf, word, word_eol);
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_nick (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	char *nick = word[2];
 | 
						|
	if (*nick)
 | 
						|
	{
 | 
						|
		if (sess->server->connected)
 | 
						|
			sess->server->p_change_nick (sess->server, nick);
 | 
						|
		else
 | 
						|
			inbound_newnick (sess->server, sess->server->nick, nick, TRUE);
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
	return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_notice (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	if (*word[2] && *word_eol[3])
 | 
						|
	{
 | 
						|
		sess->server->p_notice (sess->server, word[2], word_eol[3]);
 | 
						|
		EMIT_SIGNAL (XP_TE_NOTICESEND, sess, word[2], word_eol[3], NULL, NULL, 0);
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
	return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_notify (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	int i = 1;
 | 
						|
	char *net = NULL;
 | 
						|
 | 
						|
	if (*word[2])
 | 
						|
	{
 | 
						|
		if (strcmp (word[2], "-n") == 0)	/* comma sep network list */
 | 
						|
		{
 | 
						|
			net = word[3];
 | 
						|
			i += 2;
 | 
						|
		}
 | 
						|
 | 
						|
		while (1)
 | 
						|
		{
 | 
						|
			i++;
 | 
						|
			if (!*word[i])
 | 
						|
				break;
 | 
						|
			if (notify_deluser (word[i]))
 | 
						|
			{
 | 
						|
				EMIT_SIGNAL (XP_TE_DELNOTIFY, sess, word[i], NULL, NULL, NULL, 0);
 | 
						|
				return TRUE;
 | 
						|
			}
 | 
						|
 | 
						|
			if (net && strcmp (net, "ASK") == 0)
 | 
						|
				fe_notify_ask (word[i], NULL);
 | 
						|
			else
 | 
						|
			{
 | 
						|
				notify_adduser (word[i], net);
 | 
						|
				EMIT_SIGNAL (XP_TE_ADDNOTIFY, sess, word[i], NULL, NULL, NULL, 0);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	} else
 | 
						|
		notify_showlist (sess);
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_op (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	int i = 2;
 | 
						|
 | 
						|
	while (1)
 | 
						|
	{
 | 
						|
		if (!*word[i])
 | 
						|
		{
 | 
						|
			if (i == 2)
 | 
						|
				return FALSE;
 | 
						|
			send_channel_modes (sess, tbuf, word, 2, i, '+', 'o', 0);
 | 
						|
			return TRUE;
 | 
						|
		}
 | 
						|
		i++;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_part (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	char *chan = word[2];
 | 
						|
	char *reason = word_eol[3];
 | 
						|
	if (!*chan)
 | 
						|
		chan = sess->channel;
 | 
						|
	if ((*chan) && is_channel (sess->server, chan))
 | 
						|
	{
 | 
						|
		if (reason[0] == 0)
 | 
						|
			reason = NULL;
 | 
						|
		server_sendpart (sess->server, chan, reason);
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
	return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_ping (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	char timestring[64];
 | 
						|
	unsigned long tim;
 | 
						|
	char *to = word[2];
 | 
						|
 | 
						|
	tim = make_ping_time ();
 | 
						|
 | 
						|
	snprintf (timestring, sizeof (timestring), "%lu", tim);
 | 
						|
	sess->server->p_ping (sess->server, to, timestring);
 | 
						|
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
open_query (server *serv, char *nick, gboolean focus_existing)
 | 
						|
{
 | 
						|
	session *sess;
 | 
						|
 | 
						|
	sess = find_dialog (serv, nick);
 | 
						|
	if (!sess)
 | 
						|
		new_ircwindow (serv, nick, SESS_DIALOG, 1);
 | 
						|
	else if (focus_existing)
 | 
						|
		fe_ctrl_gui (sess, 2, 0);	/* bring-to-front */
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_query (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	char *nick = word[2];
 | 
						|
	gboolean focus = TRUE;
 | 
						|
 | 
						|
	if (strcmp (word[2], "-nofocus") == 0)
 | 
						|
	{
 | 
						|
		nick = word[3];
 | 
						|
		focus = FALSE;
 | 
						|
	}
 | 
						|
 | 
						|
	if (*nick && !is_channel (sess->server, nick))
 | 
						|
	{
 | 
						|
		open_query (sess->server, nick, focus);
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
	return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_quote (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	char *raw = word_eol[2];
 | 
						|
 | 
						|
	return sess->server->p_raw (sess->server, raw);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_reconnect (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	int tmp = prefs.recon_delay;
 | 
						|
	GSList *list;
 | 
						|
	server *serv = sess->server;
 | 
						|
 | 
						|
	prefs.recon_delay = 0;
 | 
						|
 | 
						|
	if (!strcasecmp (word[2], "ALL"))
 | 
						|
	{
 | 
						|
		list = serv_list;
 | 
						|
		while (list)
 | 
						|
		{
 | 
						|
			serv = list->data;
 | 
						|
			if (serv->connected)
 | 
						|
				serv->auto_reconnect (serv, TRUE, -1);
 | 
						|
			list = list->next;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	/* If it isn't "ALL" and there is something
 | 
						|
	there it *should* be a server they are trying to connect to*/
 | 
						|
	else if (*word[2])
 | 
						|
	{
 | 
						|
		int offset = 0;
 | 
						|
#ifdef USE_OPENSSL
 | 
						|
		int use_ssl = FALSE;
 | 
						|
 | 
						|
		if (strcmp (word[2], "-ssl") == 0)
 | 
						|
		{
 | 
						|
			use_ssl = TRUE;
 | 
						|
			offset++;	/* args move up by 1 word */
 | 
						|
		}
 | 
						|
		serv->use_ssl = use_ssl;
 | 
						|
		serv->accept_invalid_cert = TRUE;
 | 
						|
#endif
 | 
						|
 | 
						|
		if (*word[4+offset])
 | 
						|
			safe_strcpy (serv->password, word[4+offset], sizeof (serv->password));
 | 
						|
		if (*word[3+offset])
 | 
						|
			serv->port = atoi (word[3+offset]);
 | 
						|
		safe_strcpy (serv->hostname, word[2+offset], sizeof (serv->hostname));
 | 
						|
		serv->auto_reconnect (serv, TRUE, -1);
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		serv->auto_reconnect (serv, TRUE, -1);
 | 
						|
	}
 | 
						|
	prefs.recon_delay = tmp;
 | 
						|
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_recv (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	if (*word_eol[2])
 | 
						|
	{
 | 
						|
		sess->server->p_inline (sess->server, word_eol[2], strlen (word_eol[2]));
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
 | 
						|
	return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_say (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	char *speech = word_eol[2];
 | 
						|
	if (*speech)
 | 
						|
	{
 | 
						|
		handle_say (sess, speech, FALSE);
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
	return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_send (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	guint32 addr;
 | 
						|
	socklen_t len;
 | 
						|
	struct sockaddr_in SAddr;
 | 
						|
 | 
						|
	if (!word[2][0])
 | 
						|
		return FALSE;
 | 
						|
 | 
						|
	addr = dcc_get_my_address ();
 | 
						|
	if (addr == 0)
 | 
						|
	{
 | 
						|
		/* use the one from our connected server socket */
 | 
						|
		memset (&SAddr, 0, sizeof (struct sockaddr_in));
 | 
						|
		len = sizeof (SAddr);
 | 
						|
		getsockname (sess->server->sok, (struct sockaddr *) &SAddr, &len);
 | 
						|
		addr = SAddr.sin_addr.s_addr;
 | 
						|
	}
 | 
						|
	addr = ntohl (addr);
 | 
						|
 | 
						|
	if ((addr & 0xffff0000) == 0xc0a80000 ||	/* 192.168.x.x */
 | 
						|
		 (addr & 0xff000000) == 0x0a000000)		/* 10.x.x.x */
 | 
						|
		/* we got a private net address, let's PSEND or it'll fail */
 | 
						|
		snprintf (tbuf, 512, "DCC PSEND %s", word_eol[2]);
 | 
						|
	else
 | 
						|
		snprintf (tbuf, 512, "DCC SEND %s", word_eol[2]);
 | 
						|
 | 
						|
	handle_command (sess, tbuf, FALSE);
 | 
						|
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_setcursor (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	int delta = FALSE;
 | 
						|
 | 
						|
	if (*word[2])
 | 
						|
	{
 | 
						|
		if (word[2][0] == '-' || word[2][0] == '+')
 | 
						|
			delta = TRUE;
 | 
						|
		fe_set_inputbox_cursor (sess, delta, atoi (word[2]));
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
 | 
						|
	return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_settab (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	if (*word_eol[2])
 | 
						|
	{
 | 
						|
		strcpy (tbuf, sess->channel);
 | 
						|
		safe_strcpy (sess->channel, word_eol[2], CHANLEN);
 | 
						|
		fe_set_channel (sess);
 | 
						|
		strcpy (sess->channel, tbuf);
 | 
						|
	}
 | 
						|
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_settext (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	fe_set_inputbox_contents (sess, word_eol[2]);
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_splay (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	if (*word[2])
 | 
						|
	{
 | 
						|
		sound_play (word[2], FALSE);
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
 | 
						|
	return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
parse_irc_url (char *url, char *server_name[], char *port[], char *channel[], int *use_ssl)
 | 
						|
{
 | 
						|
	char *co;
 | 
						|
#ifdef USE_OPENSSL
 | 
						|
	if (strncasecmp ("ircs://", url, 7) == 0)
 | 
						|
	{
 | 
						|
		*use_ssl = TRUE;
 | 
						|
		*server_name = url + 7;
 | 
						|
		goto urlserv;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
 | 
						|
	if (strncasecmp ("irc://", url, 6) == 0)
 | 
						|
	{
 | 
						|
		*server_name = url + 6;
 | 
						|
#ifdef USE_OPENSSL
 | 
						|
urlserv:
 | 
						|
#endif
 | 
						|
		/* check for port */
 | 
						|
		co = strchr (*server_name, ':');
 | 
						|
		if (co)
 | 
						|
		{
 | 
						|
			*port = co + 1;
 | 
						|
			*co = 0;
 | 
						|
		} else
 | 
						|
			co = *server_name;
 | 
						|
		/* check for channel - mirc style */
 | 
						|
		co = strchr (co + 1, '/');
 | 
						|
		if (co)
 | 
						|
		{
 | 
						|
			*co = 0;
 | 
						|
			co++;
 | 
						|
			if (*co == '#')
 | 
						|
				*channel = co+1;
 | 
						|
			else
 | 
						|
				*channel = co;
 | 
						|
			
 | 
						|
		}
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
	return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_server (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	int offset = 0;
 | 
						|
	char *server_name = NULL;
 | 
						|
	char *port = NULL;
 | 
						|
	char *pass = NULL;
 | 
						|
	char *channel = NULL;
 | 
						|
	int use_ssl = FALSE;
 | 
						|
	int is_url = TRUE;
 | 
						|
	server *serv = sess->server;
 | 
						|
 | 
						|
#ifdef USE_OPENSSL
 | 
						|
	/* BitchX uses -ssl, mIRC uses -e, let's support both */
 | 
						|
	if (strcmp (word[2], "-ssl") == 0 || strcmp (word[2], "-e") == 0)
 | 
						|
	{
 | 
						|
		use_ssl = TRUE;
 | 
						|
		offset++;	/* args move up by 1 word */
 | 
						|
	}
 | 
						|
#endif
 | 
						|
 | 
						|
	if (!parse_irc_url (word[2 + offset], &server_name, &port, &channel, &use_ssl))
 | 
						|
	{
 | 
						|
		is_url = FALSE;
 | 
						|
		server_name = word[2 + offset];
 | 
						|
	}
 | 
						|
	if (port)
 | 
						|
		pass = word[3 + offset];
 | 
						|
	else
 | 
						|
	{
 | 
						|
		port = word[3 + offset];
 | 
						|
		pass = word[4 + offset];
 | 
						|
	}
 | 
						|
	
 | 
						|
	if (!(*server_name))
 | 
						|
		return FALSE;
 | 
						|
 | 
						|
	sess->server->network = NULL;
 | 
						|
 | 
						|
	/* dont clear it for /servchan */
 | 
						|
	if (strncasecmp (word_eol[1], "SERVCHAN ", 9))
 | 
						|
		sess->willjoinchannel[0] = 0;
 | 
						|
 | 
						|
	if (channel)
 | 
						|
	{
 | 
						|
		sess->willjoinchannel[0] = '#';
 | 
						|
		safe_strcpy ((sess->willjoinchannel + 1), channel, (CHANLEN - 1));
 | 
						|
	}
 | 
						|
 | 
						|
	/* support +7000 style ports like mIRC */
 | 
						|
	if (port[0] == '+')
 | 
						|
	{
 | 
						|
		port++;
 | 
						|
#ifdef USE_OPENSSL
 | 
						|
		use_ssl = TRUE;
 | 
						|
#endif
 | 
						|
	}
 | 
						|
 | 
						|
	if (*pass)
 | 
						|
	{
 | 
						|
		safe_strcpy (serv->password, pass, sizeof (serv->password));
 | 
						|
	}
 | 
						|
#ifdef USE_OPENSSL
 | 
						|
	serv->use_ssl = use_ssl;
 | 
						|
	serv->accept_invalid_cert = TRUE;
 | 
						|
#endif
 | 
						|
 | 
						|
	/* try to connect by Network name */
 | 
						|
	if (servlist_connect_by_netname (sess, server_name, !is_url))
 | 
						|
		return TRUE;
 | 
						|
 | 
						|
	if (*port)
 | 
						|
	{
 | 
						|
		serv->connect (serv, server_name, atoi (port), FALSE);
 | 
						|
	} else
 | 
						|
	{
 | 
						|
		/* -1 for default port */
 | 
						|
		serv->connect (serv, server_name, -1, FALSE);
 | 
						|
	}
 | 
						|
 | 
						|
	/* try to associate this connection with a listed network */
 | 
						|
	if (!serv->network)
 | 
						|
		/* search for this hostname in the entire server list */
 | 
						|
		serv->network = servlist_net_find_from_server (server_name);
 | 
						|
		/* may return NULL, but that's OK */
 | 
						|
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_servchan (struct session *sess, char *tbuf, char *word[],
 | 
						|
				  char *word_eol[])
 | 
						|
{
 | 
						|
	int offset = 0;
 | 
						|
 | 
						|
#ifdef USE_OPENSSL
 | 
						|
	if (strcmp (word[2], "-ssl") == 0)
 | 
						|
		offset++;
 | 
						|
#endif
 | 
						|
 | 
						|
	if (*word[4 + offset])
 | 
						|
	{
 | 
						|
		safe_strcpy (sess->willjoinchannel, word[4 + offset], CHANLEN);
 | 
						|
		return cmd_server (sess, tbuf, word, word_eol);
 | 
						|
	}
 | 
						|
 | 
						|
	return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_topic (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	if (word[2][0] && is_channel (sess->server, word[2]))
 | 
						|
		sess->server->p_topic (sess->server, word[2], word_eol[3]);
 | 
						|
	else
 | 
						|
		sess->server->p_topic (sess->server, sess->channel, word_eol[2]);
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_tray (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	if (strcmp (word[2], "-b") == 0)
 | 
						|
	{
 | 
						|
		fe_tray_set_balloon (word[3], word[4][0] ? word[4] : NULL);
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
 | 
						|
	if (strcmp (word[2], "-t") == 0)
 | 
						|
	{
 | 
						|
		fe_tray_set_tooltip (word[3][0] ? word[3] : NULL);
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
 | 
						|
	if (strcmp (word[2], "-i") == 0)
 | 
						|
	{
 | 
						|
		fe_tray_set_icon (atoi (word[3]));
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
 | 
						|
	if (strcmp (word[2], "-f") != 0)
 | 
						|
		return FALSE;
 | 
						|
 | 
						|
	if (!word[3][0])
 | 
						|
	{
 | 
						|
		fe_tray_set_file (NULL);	/* default xchat icon */
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
 | 
						|
	if (!word[4][0])
 | 
						|
	{
 | 
						|
		fe_tray_set_file (word[3]);	/* fixed custom icon */
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
 | 
						|
	/* flash between 2 icons */
 | 
						|
	fe_tray_set_flash (word[4], word[5][0] ? word[5] : NULL, atoi (word[3]));
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_unignore (struct session *sess, char *tbuf, char *word[],
 | 
						|
				  char *word_eol[])
 | 
						|
{
 | 
						|
	char *mask = word[2];
 | 
						|
	char *arg = word[3];
 | 
						|
	if (*mask)
 | 
						|
	{
 | 
						|
		if (ignore_del (mask, NULL))
 | 
						|
		{
 | 
						|
			if (strcasecmp (arg, "QUIET"))
 | 
						|
				EMIT_SIGNAL (XP_TE_IGNOREREMOVE, sess, mask, NULL, NULL, NULL, 0);
 | 
						|
		}
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
	return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_unload (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
#ifdef USE_PLUGIN
 | 
						|
	int len, by_file = FALSE;
 | 
						|
 | 
						|
	len = strlen (word[2]);
 | 
						|
#ifdef WIN32
 | 
						|
	if (len > 4 && strcasecmp (word[2] + len - 4, ".dll") == 0)
 | 
						|
#else
 | 
						|
#if defined(__hpux)
 | 
						|
	if (len > 3 && strcasecmp (word[2] + len - 3, ".sl") == 0)
 | 
						|
#else
 | 
						|
	if (len > 3 && strcasecmp (word[2] + len - 3, ".so") == 0)
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
		by_file = TRUE;
 | 
						|
 | 
						|
	switch (plugin_kill (word[2], by_file))
 | 
						|
	{
 | 
						|
	case 0:
 | 
						|
			PrintText (sess, _("No such plugin found.\n"));
 | 
						|
			break;
 | 
						|
	case 1:
 | 
						|
			return TRUE;
 | 
						|
	case 2:
 | 
						|
			PrintText (sess, _("That plugin is refusing to unload.\n"));
 | 
						|
			break;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
 | 
						|
	return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static server *
 | 
						|
find_server_from_hostname (char *hostname)
 | 
						|
{
 | 
						|
	GSList *list = serv_list;
 | 
						|
	server *serv;
 | 
						|
 | 
						|
	while (list)
 | 
						|
	{
 | 
						|
		serv = list->data;
 | 
						|
		if (!strcasecmp (hostname, serv->hostname) && serv->connected)
 | 
						|
			return serv;
 | 
						|
		list = list->next;
 | 
						|
	}
 | 
						|
 | 
						|
	return NULL;
 | 
						|
}
 | 
						|
 | 
						|
static server *
 | 
						|
find_server_from_net (void *net)
 | 
						|
{
 | 
						|
	GSList *list = serv_list;
 | 
						|
	server *serv;
 | 
						|
 | 
						|
	while (list)
 | 
						|
	{
 | 
						|
		serv = list->data;
 | 
						|
		if (serv->network == net && serv->connected)
 | 
						|
			return serv;
 | 
						|
		list = list->next;
 | 
						|
	}
 | 
						|
 | 
						|
	return NULL;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
url_join_only (server *serv, char *tbuf, char *channel)
 | 
						|
{
 | 
						|
	/* already connected, JOIN only. FIXME: support keys? */
 | 
						|
	tbuf[0] = '#';
 | 
						|
	/* tbuf is 4kb */
 | 
						|
	safe_strcpy ((tbuf + 1), channel, 256);
 | 
						|
	serv->p_join (serv, tbuf, "");
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_url (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	if (word[2][0])
 | 
						|
	{
 | 
						|
		char *server_name = NULL;
 | 
						|
		char *port = NULL;
 | 
						|
		char *channel = NULL;
 | 
						|
		char *url = g_strdup (word[2]);
 | 
						|
		int use_ssl = FALSE;
 | 
						|
		void *net;
 | 
						|
		server *serv;
 | 
						|
 | 
						|
		if (parse_irc_url (url, &server_name, &port, &channel, &use_ssl))
 | 
						|
		{
 | 
						|
			/* maybe we're already connected to this net */
 | 
						|
 | 
						|
			/* check for "FreeNode" */
 | 
						|
			net = servlist_net_find (server_name, NULL, strcasecmp);
 | 
						|
			/* check for "irc.eu.freenode.net" */
 | 
						|
			if (!net)
 | 
						|
				net = servlist_net_find_from_server (server_name);
 | 
						|
 | 
						|
			if (net)
 | 
						|
			{
 | 
						|
				/* found the network, but are we connected? */
 | 
						|
				serv = find_server_from_net (net);
 | 
						|
				if (serv)
 | 
						|
				{
 | 
						|
					url_join_only (serv, tbuf, channel);
 | 
						|
					g_free (url);
 | 
						|
					return TRUE;
 | 
						|
				}
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				/* an un-listed connection */
 | 
						|
				serv = find_server_from_hostname (server_name);
 | 
						|
				if (serv)
 | 
						|
				{
 | 
						|
					url_join_only (serv, tbuf, channel);
 | 
						|
					g_free (url);
 | 
						|
					return TRUE;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			/* not connected to this net, open new window */
 | 
						|
			cmd_newserver (sess, tbuf, word, word_eol);
 | 
						|
 | 
						|
		} else
 | 
						|
			fe_open_url (word[2]);
 | 
						|
		g_free (url);
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
 | 
						|
	return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
userlist_cb (struct User *user, session *sess)
 | 
						|
{
 | 
						|
	time_t lt;
 | 
						|
 | 
						|
	if (!user->lasttalk)
 | 
						|
		lt = 0;
 | 
						|
	else
 | 
						|
		lt = time (0) - user->lasttalk;
 | 
						|
	PrintTextf (sess,
 | 
						|
				"\00306%s\t\00314[\00310%-38s\00314] \017ov\0033=\017%d%d away=%u lt\0033=\017%d\n",
 | 
						|
				user->nick, user->hostname, user->op, user->voice, user->away, lt);
 | 
						|
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_uselect (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	int idx = 2;
 | 
						|
	int clear = TRUE;
 | 
						|
	int scroll = FALSE;
 | 
						|
 | 
						|
	if (strcmp (word[2], "-a") == 0)	/* ADD (don't clear selections) */
 | 
						|
	{
 | 
						|
		clear = FALSE;
 | 
						|
		idx++;
 | 
						|
	}
 | 
						|
	if (strcmp (word[idx], "-s") == 0)	/* SCROLL TO */
 | 
						|
	{
 | 
						|
		scroll = TRUE;
 | 
						|
		idx++;
 | 
						|
	}
 | 
						|
	/* always valid, no args means clear the selection list */
 | 
						|
	fe_uselect (sess, word + idx, clear, scroll);
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_userlist (struct session *sess, char *tbuf, char *word[],
 | 
						|
				  char *word_eol[])
 | 
						|
{
 | 
						|
	tree_foreach (sess->usertree, (tree_traverse_func *)userlist_cb, sess);
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
wallchop_cb (struct User *user, multidata *data)
 | 
						|
{
 | 
						|
	if (user->op)
 | 
						|
	{
 | 
						|
		if (data->i)
 | 
						|
			strcat (data->tbuf, ",");
 | 
						|
		strcat (data->tbuf, user->nick);
 | 
						|
		data->i++;
 | 
						|
	}
 | 
						|
	if (data->i == 5)
 | 
						|
	{
 | 
						|
		data->i = 0;
 | 
						|
		sprintf (data->tbuf + strlen (data->tbuf),
 | 
						|
					" :[@%s] %s", data->sess->channel, data->reason);
 | 
						|
		data->sess->server->p_raw (data->sess->server, data->tbuf);
 | 
						|
		strcpy (data->tbuf, "NOTICE ");
 | 
						|
	}
 | 
						|
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_wallchop (struct session *sess, char *tbuf, char *word[],
 | 
						|
				  char *word_eol[])
 | 
						|
{
 | 
						|
	multidata data;
 | 
						|
 | 
						|
	if (!(*word_eol[2]))
 | 
						|
		return FALSE;
 | 
						|
 | 
						|
	strcpy (tbuf, "NOTICE ");
 | 
						|
 | 
						|
	data.reason = word_eol[2];
 | 
						|
	data.tbuf = tbuf;
 | 
						|
	data.i = 0;
 | 
						|
	data.sess = sess;
 | 
						|
	tree_foreach (sess->usertree, (tree_traverse_func*)wallchop_cb, &data);
 | 
						|
 | 
						|
	if (data.i)
 | 
						|
	{
 | 
						|
		sprintf (tbuf + strlen (tbuf),
 | 
						|
					" :[@%s] %s", sess->channel, word_eol[2]);
 | 
						|
		sess->server->p_raw (sess->server, tbuf);
 | 
						|
	}
 | 
						|
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_wallchan (struct session *sess, char *tbuf, char *word[],
 | 
						|
				  char *word_eol[])
 | 
						|
{
 | 
						|
	GSList *list;
 | 
						|
 | 
						|
	if (*word_eol[2])
 | 
						|
	{
 | 
						|
		list = sess_list;
 | 
						|
		while (list)
 | 
						|
		{
 | 
						|
			sess = list->data;
 | 
						|
			if (sess->type == SESS_CHANNEL)
 | 
						|
			{
 | 
						|
				inbound_chanmsg (sess->server, NULL, sess->channel,
 | 
						|
									  sess->server->nick, word_eol[2], TRUE, FALSE);
 | 
						|
				sess->server->p_message (sess->server, sess->channel, word_eol[2]);
 | 
						|
			}
 | 
						|
			list = list->next;
 | 
						|
		}
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
	return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_hop (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	int i = 2;
 | 
						|
 | 
						|
	while (1)
 | 
						|
	{
 | 
						|
		if (!*word[i])
 | 
						|
		{
 | 
						|
			if (i == 2)
 | 
						|
				return FALSE;
 | 
						|
			send_channel_modes (sess, tbuf, word, 2, i, '+', 'h', 0);
 | 
						|
			return TRUE;
 | 
						|
		}
 | 
						|
		i++;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmd_voice (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 | 
						|
{
 | 
						|
	int i = 2;
 | 
						|
 | 
						|
	while (1)
 | 
						|
	{
 | 
						|
		if (!*word[i])
 | 
						|
		{
 | 
						|
			if (i == 2)
 | 
						|
				return FALSE;
 | 
						|
			send_channel_modes (sess, tbuf, word, 2, i, '+', 'v', 0);
 | 
						|
			return TRUE;
 | 
						|
		}
 | 
						|
		i++;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/* *MUST* be kept perfectly sorted for the bsearch to work */
 | 
						|
const struct commands xc_cmds[] = {
 | 
						|
	{"ADDBUTTON", cmd_addbutton, 0, 0, 1,
 | 
						|
	 N_("ADDBUTTON <name> <action>, adds a button under the user-list")},
 | 
						|
	{"ALLCHAN", cmd_allchannels, 0, 0, 1,
 | 
						|
	 N_("ALLCHAN <cmd>, sends a command to all channels you're in")},
 | 
						|
	{"ALLCHANL", cmd_allchannelslocal, 0, 0, 1,
 | 
						|
	 N_("ALLCHANL <cmd>, sends a command to all channels you're in")},
 | 
						|
	{"ALLSERV", cmd_allservers, 0, 0, 1,
 | 
						|
	 N_("ALLSERV <cmd>, sends a command to all servers you're in")},
 | 
						|
	{"AWAY", cmd_away, 1, 0, 1, N_("AWAY [<reason>], sets you away")},
 | 
						|
	{"BACK", cmd_back, 1, 0, 1, N_("BACK, sets you back (not away)")},
 | 
						|
	{"BAN", cmd_ban, 1, 1, 1,
 | 
						|
	 N_("BAN <mask> [<bantype>], bans everyone matching the mask from the current channel. If they are already on the channel this doesn't kick them (needs chanop)")},
 | 
						|
	{"CHANOPT", cmd_chanopt, 0, 0, 1, N_("CHANOPT [-quiet] <variable> [<value>]")},
 | 
						|
	{"CHARSET", cmd_charset, 0, 0, 1, 0},
 | 
						|
	{"CLEAR", cmd_clear, 0, 0, 1, N_("CLEAR [ALL|HISTORY], Clears the current text window or command history")},
 | 
						|
	{"CLOSE", cmd_close, 0, 0, 1, N_("CLOSE, Closes the current window/tab")},
 | 
						|
 | 
						|
	{"COUNTRY", cmd_country, 0, 0, 1,
 | 
						|
	 N_("COUNTRY [-s] <code|wildcard>, finds a country code, eg: au = australia")},
 | 
						|
	{"CTCP", cmd_ctcp, 1, 0, 1,
 | 
						|
	 N_("CTCP <nick> <message>, send the CTCP message to nick, common messages are VERSION and USERINFO")},
 | 
						|
	{"CYCLE", cmd_cycle, 1, 1, 1,
 | 
						|
	 N_("CYCLE [<channel>], parts the current or given channel and immediately rejoins")},
 | 
						|
	{"DCC", cmd_dcc, 0, 0, 1,
 | 
						|
	 N_("\n"
 | 
						|
	 "DCC GET <nick>                      - accept an offered file\n"
 | 
						|
	 "DCC SEND [-maxcps=#] <nick> [file]  - send a file to someone\n"
 | 
						|
	 "DCC PSEND [-maxcps=#] <nick> [file] - send a file using passive mode\n"
 | 
						|
	 "DCC LIST                            - show DCC list\n"
 | 
						|
	 "DCC CHAT <nick>                     - offer DCC CHAT to someone\n"
 | 
						|
	 "DCC PCHAT <nick>                    - offer DCC CHAT using passive mode\n"
 | 
						|
	 "DCC CLOSE <type> <nick> <file>         example:\n"
 | 
						|
	 "         /dcc close send johnsmith file.tar.gz")},
 | 
						|
	{"DEBUG", cmd_debug, 0, 0, 1, 0},
 | 
						|
 | 
						|
	{"DEHOP", cmd_dehop, 1, 1, 1,
 | 
						|
	 N_("DEHOP <nick>, removes chanhalf-op status from the nick on the current channel (needs chanop)")},
 | 
						|
	{"DELBUTTON", cmd_delbutton, 0, 0, 1,
 | 
						|
	 N_("DELBUTTON <name>, deletes a button from under the user-list")},
 | 
						|
	{"DEOP", cmd_deop, 1, 1, 1,
 | 
						|
	 N_("DEOP <nick>, removes chanop status from the nick on the current channel (needs chanop)")},
 | 
						|
	{"DEVOICE", cmd_devoice, 1, 1, 1,
 | 
						|
	 N_("DEVOICE <nick>, removes voice status from the nick on the current channel (needs chanop)")},
 | 
						|
	{"DISCON", cmd_discon, 0, 0, 1, N_("DISCON, Disconnects from server")},
 | 
						|
	{"DNS", cmd_dns, 0, 0, 1, N_("DNS <nick|host|ip>, Finds a users IP number")},
 | 
						|
	{"ECHO", cmd_echo, 0, 0, 1, N_("ECHO <text>, Prints text locally")},
 | 
						|
#ifndef WIN32
 | 
						|
	{"EXEC", cmd_exec, 0, 0, 1,
 | 
						|
	 N_("EXEC [-o] <command>, runs the command. If -o flag is used then output is sent to current channel, else is printed to current text box")},
 | 
						|
#ifndef __EMX__
 | 
						|
	{"EXECCONT", cmd_execc, 0, 0, 1, N_("EXECCONT, sends the process SIGCONT")},
 | 
						|
#endif
 | 
						|
	{"EXECKILL", cmd_execk, 0, 0, 1,
 | 
						|
	 N_("EXECKILL [-9], kills a running exec in the current session. If -9 is given the process is SIGKILL'ed")},
 | 
						|
#ifndef __EMX__
 | 
						|
	{"EXECSTOP", cmd_execs, 0, 0, 1, N_("EXECSTOP, sends the process SIGSTOP")},
 | 
						|
	{"EXECWRITE", cmd_execw, 0, 0, 1, N_("EXECWRITE, sends data to the processes stdin")},
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
	{"FLUSHQ", cmd_flushq, 0, 0, 1,
 | 
						|
	 N_("FLUSHQ, flushes the current server's send queue")},
 | 
						|
	{"GATE", cmd_gate, 0, 0, 1,
 | 
						|
	 N_("GATE <host> [<port>], proxies through a host, port defaults to 23")},
 | 
						|
	{"GETFILE", cmd_getfile, 0, 0, 1, "GETFILE [-folder] [-multi] [-save] <command> <title> [<initial>]"},
 | 
						|
	{"GETINT", cmd_getint, 0, 0, 1, "GETINT <default> <command> <prompt>"},
 | 
						|
	{"GETSTR", cmd_getstr, 0, 0, 1, "GETSTR <default> <command> <prompt>"},
 | 
						|
	{"GHOST", cmd_ghost, 1, 0, 1, N_("GHOST <nick> [password], Kills a ghosted nickname")},
 | 
						|
	{"GUI", cmd_gui, 0, 0, 1, "GUI [APPLY|ATTACH|DETACH|SHOW|HIDE|FOCUS|FLASH|ICONIFY|COLOR <n>]\n"
 | 
						|
									  "       GUI [MSGBOX <text>|MENU TOGGLE]"},
 | 
						|
	{"HELP", cmd_help, 0, 0, 1, 0},
 | 
						|
	{"HOP", cmd_hop, 1, 1, 1,
 | 
						|
	 N_("HOP <nick>, gives chanhalf-op status to the nick (needs chanop)")},
 | 
						|
	{"ID", cmd_id, 1, 0, 1, N_("ID <password>, identifies yourself to nickserv")},
 | 
						|
	{"IGNORE", cmd_ignore, 0, 0, 1,
 | 
						|
	 N_("IGNORE <mask> <types..> <options..>\n"
 | 
						|
	 "    mask - host mask to ignore, eg: *!*@*.aol.com\n"
 | 
						|
	 "    types - types of data to ignore, one or all of:\n"
 | 
						|
	 "            PRIV, CHAN, NOTI, CTCP, DCC, INVI, ALL\n"
 | 
						|
	 "    options - NOSAVE, QUIET")},
 | 
						|
 | 
						|
	{"INVITE", cmd_invite, 1, 0, 1,
 | 
						|
	 N_("INVITE <nick> [<channel>], invites someone to a channel, by default the current channel (needs chanop)")},
 | 
						|
	{"JOIN", cmd_join, 1, 0, 0, N_("JOIN <channel>, joins the channel")},
 | 
						|
	{"KICK", cmd_kick, 1, 1, 1,
 | 
						|
	 N_("KICK <nick>, kicks the nick from the current channel (needs chanop)")},
 | 
						|
	{"KICKBAN", cmd_kickban, 1, 1, 1,
 | 
						|
	 N_("KICKBAN <nick>, bans then kicks the nick from the current channel (needs chanop)")},
 | 
						|
	{"KILLALL", cmd_killall, 0, 0, 1, "KILLALL, immediately exit"},
 | 
						|
	{"LAGCHECK", cmd_lagcheck, 0, 0, 1,
 | 
						|
	 N_("LAGCHECK, forces a new lag check")},
 | 
						|
	{"LASTLOG", cmd_lastlog, 0, 0, 1,
 | 
						|
	 N_("LASTLOG <string>, searches for a string in the buffer")},
 | 
						|
	{"LIST", cmd_list, 1, 0, 1, 0},
 | 
						|
	{"LOAD", cmd_load, 0, 0, 1, N_("LOAD [-e] <file>, loads a plugin or script")},
 | 
						|
 | 
						|
	{"MDEHOP", cmd_mdehop, 1, 1, 1,
 | 
						|
	 N_("MDEHOP, Mass deop's all chanhalf-ops in the current channel (needs chanop)")},
 | 
						|
	{"MDEOP", cmd_mdeop, 1, 1, 1,
 | 
						|
	 N_("MDEOP, Mass deop's all chanops in the current channel (needs chanop)")},
 | 
						|
	{"ME", cmd_me, 0, 0, 1,
 | 
						|
	 N_("ME <action>, sends the action to the current channel (actions are written in the 3rd person, like /me jumps)")},
 | 
						|
	{"MENU", cmd_menu, 0, 0, 1, "MENU [-eX] [-i<ICONFILE>] [-k<mod>,<key>] [-m] [-pX] [-r<X,group>] [-tX] {ADD|DEL} <path> [command] [unselect command]\n"
 | 
						|
										 "       See http://xchat.org/docs/menu/ for more details."},
 | 
						|
	{"MKICK", cmd_mkick, 1, 1, 1,
 | 
						|
	 N_("MKICK, Mass kicks everyone except you in the current channel (needs chanop)")},
 | 
						|
	{"MODE", cmd_mode, 1, 0, 1, 0},
 | 
						|
	{"MOP", cmd_mop, 1, 1, 1,
 | 
						|
	 N_("MOP, Mass op's all users in the current channel (needs chanop)")},
 | 
						|
	{"MSG", cmd_msg, 0, 0, 1, N_("MSG <nick> <message>, sends a private message")},
 | 
						|
 | 
						|
	{"NAMES", cmd_names, 1, 0, 1,
 | 
						|
	 N_("NAMES, Lists the nicks on the current channel")},
 | 
						|
	{"NCTCP", cmd_nctcp, 1, 0, 1,
 | 
						|
	 N_("NCTCP <nick> <message>, Sends a CTCP notice")},
 | 
						|
	{"NEWSERVER", cmd_newserver, 0, 0, 1, N_("NEWSERVER [-noconnect] <hostname> [<port>]")},
 | 
						|
	{"NICK", cmd_nick, 0, 0, 1, N_("NICK <nickname>, sets your nick")},
 | 
						|
 | 
						|
	{"NOTICE", cmd_notice, 1, 0, 1,
 | 
						|
	 N_("NOTICE <nick/channel> <message>, sends a notice. Notices are a type of message that should be auto reacted to")},
 | 
						|
	{"NOTIFY", cmd_notify, 0, 0, 1,
 | 
						|
	 N_("NOTIFY [-n network1[,network2,...]] [<nick>], displays your notify list or adds someone to it")},
 | 
						|
	{"OP", cmd_op, 1, 1, 1,
 | 
						|
	 N_("OP <nick>, gives chanop status to the nick (needs chanop)")},
 | 
						|
	{"PART", cmd_part, 1, 1, 0,
 | 
						|
	 N_("PART [<channel>] [<reason>], leaves the channel, by default the current one")},
 | 
						|
	{"PING", cmd_ping, 1, 0, 1,
 | 
						|
	 N_("PING <nick | channel>, CTCP pings nick or channel")},
 | 
						|
	{"QUERY", cmd_query, 0, 0, 1,
 | 
						|
	 N_("QUERY [-nofocus] <nick>, opens up a new privmsg window to someone")},
 | 
						|
	{"QUIT", cmd_quit, 0, 0, 1,
 | 
						|
	 N_("QUIT [<reason>], disconnects from the current server")},
 | 
						|
	{"QUOTE", cmd_quote, 1, 0, 1,
 | 
						|
	 N_("QUOTE <text>, sends the text in raw form to the server")},
 | 
						|
#ifdef USE_OPENSSL
 | 
						|
	{"RECONNECT", cmd_reconnect, 0, 0, 1,
 | 
						|
	 N_("RECONNECT [-ssl] [<host>] [<port>] [<password>], Can be called just as /RECONNECT to reconnect to the current server or with /RECONNECT ALL to reconnect to all the open servers")},
 | 
						|
#else
 | 
						|
	{"RECONNECT", cmd_reconnect, 0, 0, 1,
 | 
						|
	 N_("RECONNECT [<host>] [<port>] [<password>], Can be called just as /RECONNECT to reconnect to the current server or with /RECONNECT ALL to reconnect to all the open servers")},
 | 
						|
#endif
 | 
						|
	{"RECV", cmd_recv, 1, 0, 1, N_("RECV <text>, send raw data to xchat, as if it was received from the irc server")},
 | 
						|
 | 
						|
	{"SAY", cmd_say, 0, 0, 1,
 | 
						|
	 N_("SAY <text>, sends the text to the object in the current window")},
 | 
						|
	{"SEND", cmd_send, 0, 0, 1, N_("SEND <nick> [<file>]")},
 | 
						|
#ifdef USE_OPENSSL
 | 
						|
	{"SERVCHAN", cmd_servchan, 0, 0, 1,
 | 
						|
	 N_("SERVCHAN [-ssl] <host> <port> <channel>, connects and joins a channel")},
 | 
						|
#else
 | 
						|
	{"SERVCHAN", cmd_servchan, 0, 0, 1,
 | 
						|
	 N_("SERVCHAN <host> <port> <channel>, connects and joins a channel")},
 | 
						|
#endif
 | 
						|
#ifdef USE_OPENSSL
 | 
						|
	{"SERVER", cmd_server, 0, 0, 1,
 | 
						|
	 N_("SERVER [-ssl] <host> [<port>] [<password>], connects to a server, the default port is 6667 for normal connections, and 9999 for ssl connections")},
 | 
						|
#else
 | 
						|
	{"SERVER", cmd_server, 0, 0, 1,
 | 
						|
	 N_("SERVER <host> [<port>] [<password>], connects to a server, the default port is 6667")},
 | 
						|
#endif
 | 
						|
	{"SET", cmd_set, 0, 0, 1, N_("SET [-e] [-off|-on] [-quiet] <variable> [<value>]")},
 | 
						|
	{"SETCURSOR", cmd_setcursor, 0, 0, 1, N_("SETCURSOR [-|+]<position>")},
 | 
						|
	{"SETTAB", cmd_settab, 0, 0, 1, 0},
 | 
						|
	{"SETTEXT", cmd_settext, 0, 0, 1, 0},
 | 
						|
	{"SPLAY", cmd_splay, 0, 0, 1, "SPLAY <soundfile>"},
 | 
						|
	{"TOPIC", cmd_topic, 1, 1, 1,
 | 
						|
	 N_("TOPIC [<topic>], sets the topic if one is given, else shows the current topic")},
 | 
						|
	{"TRAY", cmd_tray, 0, 0, 1,
 | 
						|
	 N_("\nTRAY -f <timeout> <file1> [<file2>] Blink tray between two icons.\n"
 | 
						|
		   "TRAY -f <filename>                  Set tray to a fixed icon.\n"
 | 
						|
			"TRAY -i <number>                    Blink tray with an internal icon.\n"
 | 
						|
			"TRAY -t <text>                      Set the tray tooltip.\n"
 | 
						|
			"TRAY -b <title> <text>              Set the tray balloon."
 | 
						|
			)},
 | 
						|
	{"UNBAN", cmd_unban, 1, 1, 1,
 | 
						|
	 N_("UNBAN <mask> [<mask>...], unbans the specified masks.")},
 | 
						|
	{"UNIGNORE", cmd_unignore, 0, 0, 1, N_("UNIGNORE <mask> [QUIET]")},
 | 
						|
	{"UNLOAD", cmd_unload, 0, 0, 1, N_("UNLOAD <name>, unloads a plugin or script")},
 | 
						|
	{"URL", cmd_url, 0, 0, 1, N_("URL <url>, opens a URL in your browser")},
 | 
						|
	{"USELECT", cmd_uselect, 0, 1, 0,
 | 
						|
	 N_("USELECT [-a] [-s] <nick1> <nick2> etc, highlights nick(s) in channel userlist")},
 | 
						|
	{"USERLIST", cmd_userlist, 1, 1, 1, 0},
 | 
						|
	{"VOICE", cmd_voice, 1, 1, 1,
 | 
						|
	 N_("VOICE <nick>, gives voice status to someone (needs chanop)")},
 | 
						|
	{"WALLCHAN", cmd_wallchan, 1, 1, 1,
 | 
						|
	 N_("WALLCHAN <message>, writes the message to all channels")},
 | 
						|
	{"WALLCHOP", cmd_wallchop, 1, 1, 1,
 | 
						|
	 N_("WALLCHOP <message>, sends the message to all chanops on the current channel")},
 | 
						|
	{0, 0, 0, 0, 0, 0}
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
command_compare (const void *a, const void *b)
 | 
						|
{
 | 
						|
	return strcasecmp (a, ((struct commands *)b)->name);
 | 
						|
}
 | 
						|
 | 
						|
static struct commands *
 | 
						|
find_internal_command (char *name)
 | 
						|
{
 | 
						|
	/* the "-1" is to skip the NULL terminator */
 | 
						|
	return bsearch (name, xc_cmds, (sizeof (xc_cmds) /
 | 
						|
				sizeof (xc_cmds[0])) - 1, sizeof (xc_cmds[0]), command_compare);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
help (session *sess, char *tbuf, char *helpcmd, int quiet)
 | 
						|
{
 | 
						|
	struct commands *cmd;
 | 
						|
 | 
						|
	if (plugin_show_help (sess, helpcmd))
 | 
						|
		return;
 | 
						|
 | 
						|
	cmd = find_internal_command (helpcmd);
 | 
						|
 | 
						|
	if (cmd)
 | 
						|
	{
 | 
						|
		if (cmd->help)
 | 
						|
		{
 | 
						|
			snprintf (tbuf, TBUFSIZE, _("Usage: %s\n"), _(cmd->help));
 | 
						|
			PrintText (sess, tbuf);
 | 
						|
		} else
 | 
						|
		{
 | 
						|
			if (!quiet)
 | 
						|
				PrintText (sess, _("\nNo help available on that command.\n"));
 | 
						|
		}
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	if (!quiet)
 | 
						|
		PrintText (sess, _("No such command.\n"));
 | 
						|
}
 | 
						|
 | 
						|
/* inserts %a, %c, %d etc into buffer. Also handles &x %x for word/word_eol. *
 | 
						|
 *   returns 2 on buffer overflow
 | 
						|
 *   returns 1 on success                                                    *
 | 
						|
 *   returns 0 on bad-args-for-user-command                                  *
 | 
						|
 * - word/word_eol args might be NULL                                        *
 | 
						|
 * - this beast is used for UserCommands, UserlistButtons and CTCP replies   */
 | 
						|
 | 
						|
int
 | 
						|
auto_insert (char *dest, int destlen, unsigned char *src, char *word[],
 | 
						|
				 char *word_eol[], char *a, char *c, char *d, char *e, char *h,
 | 
						|
				 char *n, char *s)
 | 
						|
{
 | 
						|
	int num;
 | 
						|
	char buf[32];
 | 
						|
	time_t now;
 | 
						|
	struct tm *tm_ptr;
 | 
						|
	char *utf;
 | 
						|
	gsize utf_len;
 | 
						|
	char *orig = dest;
 | 
						|
 | 
						|
	destlen--;
 | 
						|
 | 
						|
	while (src[0])
 | 
						|
	{
 | 
						|
		if (src[0] == '%' || src[0] == '&')
 | 
						|
		{
 | 
						|
			if (isdigit ((unsigned char) src[1]))
 | 
						|
			{
 | 
						|
				if (isdigit ((unsigned char) src[2]) && isdigit ((unsigned char) src[3]))
 | 
						|
				{
 | 
						|
					buf[0] = src[1];
 | 
						|
					buf[1] = src[2];
 | 
						|
					buf[2] = src[3];
 | 
						|
					buf[3] = 0;
 | 
						|
					dest[0] = atoi (buf);
 | 
						|
					utf = g_locale_to_utf8 (dest, 1, 0, &utf_len, 0);
 | 
						|
					if (utf)
 | 
						|
					{
 | 
						|
						if ((dest - orig) + utf_len >= destlen)
 | 
						|
						{
 | 
						|
							g_free (utf);
 | 
						|
							return 2;
 | 
						|
						}
 | 
						|
 | 
						|
						memcpy (dest, utf, utf_len);
 | 
						|
						g_free (utf);
 | 
						|
						dest += utf_len;
 | 
						|
					}
 | 
						|
					src += 3;
 | 
						|
				} else
 | 
						|
				{
 | 
						|
					if (word)
 | 
						|
					{
 | 
						|
						src++;
 | 
						|
						num = src[0] - '0';	/* ascii to decimal */
 | 
						|
						if (*word[num] == 0)
 | 
						|
							return 0;
 | 
						|
 | 
						|
						if (src[-1] == '%')
 | 
						|
							utf = word[num];
 | 
						|
						else
 | 
						|
							utf = word_eol[num];
 | 
						|
 | 
						|
						/* avoid recusive usercommand overflow */
 | 
						|
						if ((dest - orig) + strlen (utf) >= destlen)
 | 
						|
							return 2;
 | 
						|
 | 
						|
						strcpy (dest, utf);
 | 
						|
						dest += strlen (dest);
 | 
						|
					}
 | 
						|
				}
 | 
						|
			} else
 | 
						|
			{
 | 
						|
				if (src[0] == '&')
 | 
						|
					goto lamecode;
 | 
						|
				src++;
 | 
						|
				utf = NULL;
 | 
						|
				switch (src[0])
 | 
						|
				{
 | 
						|
				case '%':
 | 
						|
					if ((dest - orig) + 2 >= destlen)
 | 
						|
						return 2;
 | 
						|
					dest[0] = '%';
 | 
						|
					dest[1] = 0;
 | 
						|
					dest++;
 | 
						|
					break;
 | 
						|
				case 'a':
 | 
						|
					utf = a; break;
 | 
						|
				case 'c':
 | 
						|
					utf = c; break;
 | 
						|
				case 'd':
 | 
						|
					utf = d; break;
 | 
						|
				case 'e':
 | 
						|
					utf = e; break;
 | 
						|
				case 'h':
 | 
						|
					utf = h; break;
 | 
						|
				case 'm':
 | 
						|
					utf = get_cpu_str (); break;
 | 
						|
				case 'n':
 | 
						|
					utf = n; break;
 | 
						|
				case 's':
 | 
						|
					utf = s; break;
 | 
						|
				case 't':
 | 
						|
					now = time (0);
 | 
						|
					utf = ctime (&now);
 | 
						|
					utf[19] = 0;
 | 
						|
					break;
 | 
						|
				case 'v':
 | 
						|
					utf = PACKAGE_VERSION; break;
 | 
						|
					break;
 | 
						|
				case 'y':
 | 
						|
					now = time (0);
 | 
						|
					tm_ptr = localtime (&now);
 | 
						|
					snprintf (buf, sizeof (buf), "%4d%02d%02d", 1900 +
 | 
						|
								 tm_ptr->tm_year, 1 + tm_ptr->tm_mon, tm_ptr->tm_mday);
 | 
						|
					utf = buf;
 | 
						|
					break;
 | 
						|
				default:
 | 
						|
					src--;
 | 
						|
					goto lamecode;
 | 
						|
				}
 | 
						|
 | 
						|
				if (utf)
 | 
						|
				{
 | 
						|
					if ((dest - orig) + strlen (utf) >= destlen)
 | 
						|
						return 2;
 | 
						|
					strcpy (dest, utf);
 | 
						|
					dest += strlen (dest);
 | 
						|
				}
 | 
						|
 | 
						|
			}
 | 
						|
			src++;
 | 
						|
		} else
 | 
						|
		{
 | 
						|
			utf_len = g_utf8_skip[src[0]];
 | 
						|
 | 
						|
			if ((dest - orig) + utf_len >= destlen)
 | 
						|
				return 2;
 | 
						|
 | 
						|
			if (utf_len == 1)
 | 
						|
			{
 | 
						|
		 lamecode:
 | 
						|
				dest[0] = src[0];
 | 
						|
				dest++;
 | 
						|
				src++;
 | 
						|
			} else
 | 
						|
			{
 | 
						|
				memcpy (dest, src, utf_len);
 | 
						|
				dest += utf_len;
 | 
						|
				src += utf_len;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	dest[0] = 0;
 | 
						|
 | 
						|
	return 1;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
check_special_chars (char *cmd, int do_ascii) /* check for %X */
 | 
						|
{
 | 
						|
	int occur = 0;
 | 
						|
	int len = strlen (cmd);
 | 
						|
	char *buf, *utf;
 | 
						|
	char tbuf[4];
 | 
						|
	int i = 0, j = 0;
 | 
						|
	gsize utf_len;
 | 
						|
 | 
						|
	if (!len)
 | 
						|
		return;
 | 
						|
 | 
						|
	buf = malloc (len + 1);
 | 
						|
 | 
						|
	if (buf)
 | 
						|
	{
 | 
						|
		while (cmd[j])
 | 
						|
		{
 | 
						|
			switch (cmd[j])
 | 
						|
			{
 | 
						|
			case '%':
 | 
						|
				occur++;
 | 
						|
				if (	do_ascii &&
 | 
						|
						j + 3 < len &&
 | 
						|
						(isdigit ((unsigned char) cmd[j + 1]) && isdigit ((unsigned char) cmd[j + 2]) &&
 | 
						|
						isdigit ((unsigned char) cmd[j + 3])))
 | 
						|
				{
 | 
						|
					tbuf[0] = cmd[j + 1];
 | 
						|
					tbuf[1] = cmd[j + 2];
 | 
						|
					tbuf[2] = cmd[j + 3];
 | 
						|
					tbuf[3] = 0;
 | 
						|
					buf[i] = atoi (tbuf);
 | 
						|
					utf = g_locale_to_utf8 (buf + i, 1, 0, &utf_len, 0);
 | 
						|
					if (utf)
 | 
						|
					{
 | 
						|
						memcpy (buf + i, utf, utf_len);
 | 
						|
						g_free (utf);
 | 
						|
						i += (utf_len - 1);
 | 
						|
					}
 | 
						|
					j += 3;
 | 
						|
				} else
 | 
						|
				{
 | 
						|
					switch (cmd[j + 1])
 | 
						|
					{
 | 
						|
					case 'R':
 | 
						|
						buf[i] = '\026';
 | 
						|
						break;
 | 
						|
					case 'U':
 | 
						|
						buf[i] = '\037';
 | 
						|
						break;
 | 
						|
					case 'B':
 | 
						|
						buf[i] = '\002';
 | 
						|
						break;
 | 
						|
					case 'C':
 | 
						|
						buf[i] = '\003';
 | 
						|
						break;
 | 
						|
					case 'O':
 | 
						|
						buf[i] = '\017';
 | 
						|
						break;
 | 
						|
					case 'H':	/* CL: invisible text code */
 | 
						|
						buf[i] = HIDDEN_CHAR;
 | 
						|
						break;
 | 
						|
					case '%':
 | 
						|
						buf[i] = '%';
 | 
						|
						break;
 | 
						|
					default:
 | 
						|
						buf[i] = '%';
 | 
						|
						j--;
 | 
						|
						break;
 | 
						|
					}
 | 
						|
					j++;
 | 
						|
					break;
 | 
						|
			default:
 | 
						|
					buf[i] = cmd[j];
 | 
						|
				}
 | 
						|
			}
 | 
						|
			j++;
 | 
						|
			i++;
 | 
						|
		}
 | 
						|
		buf[i] = 0;
 | 
						|
		if (occur)
 | 
						|
			strcpy (cmd, buf);
 | 
						|
		free (buf);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
typedef struct
 | 
						|
{
 | 
						|
	char *nick;
 | 
						|
	int len;
 | 
						|
	struct User *best;
 | 
						|
	int bestlen;
 | 
						|
	char *space;
 | 
						|
	char *tbuf;
 | 
						|
} nickdata;
 | 
						|
 | 
						|
static int
 | 
						|
nick_comp_cb (struct User *user, nickdata *data)
 | 
						|
{
 | 
						|
	int lenu;
 | 
						|
 | 
						|
	if (!rfc_ncasecmp (user->nick, data->nick, data->len))
 | 
						|
	{
 | 
						|
		lenu = strlen (user->nick);
 | 
						|
		if (lenu == data->len)
 | 
						|
		{
 | 
						|
			snprintf (data->tbuf, TBUFSIZE, "%s%s", user->nick, data->space);
 | 
						|
			data->len = -1;
 | 
						|
			return FALSE;
 | 
						|
		} else if (lenu < data->bestlen)
 | 
						|
		{
 | 
						|
			data->bestlen = lenu;
 | 
						|
			data->best = user;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
perform_nick_completion (struct session *sess, char *cmd, char *tbuf)
 | 
						|
{
 | 
						|
	int len;
 | 
						|
	char *space = strchr (cmd, ' ');
 | 
						|
	if (space && space != cmd)
 | 
						|
	{
 | 
						|
		if (space[-1] == prefs.nick_suffix[0] && space - 1 != cmd)
 | 
						|
		{
 | 
						|
			len = space - cmd - 1;
 | 
						|
			if (len < NICKLEN)
 | 
						|
			{
 | 
						|
				char nick[NICKLEN];
 | 
						|
				nickdata data;
 | 
						|
 | 
						|
				memcpy (nick, cmd, len);
 | 
						|
				nick[len] = 0;
 | 
						|
 | 
						|
				data.nick = nick;
 | 
						|
				data.len = len;
 | 
						|
				data.bestlen = INT_MAX;
 | 
						|
				data.best = NULL;
 | 
						|
				data.tbuf = tbuf;
 | 
						|
				data.space = space - 1;
 | 
						|
				tree_foreach (sess->usertree, (tree_traverse_func *)nick_comp_cb, &data);
 | 
						|
 | 
						|
				if (data.len == -1)
 | 
						|
					return;
 | 
						|
 | 
						|
				if (data.best)
 | 
						|
				{
 | 
						|
					snprintf (tbuf, TBUFSIZE, "%s%s", data.best->nick, space - 1);
 | 
						|
					return;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	strcpy (tbuf, cmd);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
user_command (session * sess, char *tbuf, char *cmd, char *word[],
 | 
						|
				  char *word_eol[])
 | 
						|
{
 | 
						|
	if (!auto_insert (tbuf, 2048, cmd, word, word_eol, "", sess->channel, "",
 | 
						|
							server_get_network (sess->server, TRUE), "",
 | 
						|
							sess->server->nick, ""))
 | 
						|
	{
 | 
						|
		PrintText (sess, _("Bad arguments for user command.\n"));
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	handle_command (sess, tbuf, TRUE);
 | 
						|
}
 | 
						|
 | 
						|
/* handle text entered without a CMDchar prefix */
 | 
						|
 | 
						|
static void
 | 
						|
handle_say (session *sess, char *text, int check_spch)
 | 
						|
{
 | 
						|
	struct DCC *dcc;
 | 
						|
	char *word[PDIWORDS+1];
 | 
						|
	char *word_eol[PDIWORDS+1];
 | 
						|
	char pdibuf_static[1024];
 | 
						|
	char newcmd_static[1024];
 | 
						|
	char *pdibuf = pdibuf_static;
 | 
						|
	char *newcmd = newcmd_static;
 | 
						|
	int len;
 | 
						|
	int newcmdlen = sizeof newcmd_static;
 | 
						|
 | 
						|
	if (strcmp (sess->channel, "(lastlog)") == 0)
 | 
						|
	{
 | 
						|
		lastlog (sess->lastlog_sess, text, sess->lastlog_regexp);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	len = strlen (text);
 | 
						|
	if (len >= sizeof pdibuf_static)
 | 
						|
		pdibuf = malloc (len + 1);
 | 
						|
 | 
						|
	if (len + NICKLEN >= newcmdlen)
 | 
						|
		newcmd = malloc (newcmdlen = len + NICKLEN + 1);
 | 
						|
 | 
						|
	if (check_spch && prefs.perc_color)
 | 
						|
		check_special_chars (text, prefs.perc_ascii);
 | 
						|
 | 
						|
	/* Python relies on this */
 | 
						|
	word[PDIWORDS] = NULL;
 | 
						|
	word_eol[PDIWORDS] = NULL;
 | 
						|
 | 
						|
	/* split the text into words and word_eol */
 | 
						|
	process_data_init (pdibuf, text, word, word_eol, TRUE, FALSE);
 | 
						|
 | 
						|
	/* a command of "" can be hooked for non-commands */
 | 
						|
	if (plugin_emit_command (sess, "", word, word_eol))
 | 
						|
		goto xit;
 | 
						|
 | 
						|
	/* incase a plugin did /close */
 | 
						|
	if (!is_session (sess))
 | 
						|
		goto xit;
 | 
						|
 | 
						|
	if (!sess->channel[0] || sess->type == SESS_SERVER || sess->type == SESS_NOTICES || sess->type == SESS_SNOTICES)
 | 
						|
	{
 | 
						|
		notj_msg (sess);
 | 
						|
		goto xit;
 | 
						|
	}
 | 
						|
 | 
						|
	if (prefs.nickcompletion)
 | 
						|
		perform_nick_completion (sess, text, newcmd);
 | 
						|
	else
 | 
						|
		safe_strcpy (newcmd, text, newcmdlen);
 | 
						|
 | 
						|
	text = newcmd;
 | 
						|
 | 
						|
	if (sess->type == SESS_DIALOG)
 | 
						|
	{
 | 
						|
		/* try it via dcc, if possible */
 | 
						|
		dcc = dcc_write_chat (sess->channel, text);
 | 
						|
		if (dcc)
 | 
						|
		{
 | 
						|
			inbound_chanmsg (sess->server, NULL, sess->channel,
 | 
						|
								  sess->server->nick, text, TRUE, FALSE);
 | 
						|
			set_topic (sess, net_ip (dcc->addr), net_ip (dcc->addr));
 | 
						|
			goto xit;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (sess->server->connected)
 | 
						|
	{
 | 
						|
		unsigned int max;
 | 
						|
		unsigned char t = 0;
 | 
						|
 | 
						|
		/* maximum allowed message text */
 | 
						|
		/* :nickname!username@host.com PRIVMSG #channel :text\r\n */
 | 
						|
		max = 512;
 | 
						|
		max -= 16;	/* :, !, @, " PRIVMSG ", " ", :, \r, \n */
 | 
						|
		max -= strlen (sess->server->nick);
 | 
						|
		max -= strlen (sess->channel);
 | 
						|
		if (sess->me && sess->me->hostname)
 | 
						|
			max -= strlen (sess->me->hostname);
 | 
						|
		else
 | 
						|
		{
 | 
						|
			max -= 9;	/* username */
 | 
						|
			max -= 65;	/* max possible hostname and '@' */
 | 
						|
		}
 | 
						|
 | 
						|
		if (strlen (text) > max)
 | 
						|
		{
 | 
						|
			int i = 0, size;
 | 
						|
 | 
						|
			/* traverse the utf8 string and find the nearest cut point that
 | 
						|
				doesn't split 1 char in half */
 | 
						|
			while (1)
 | 
						|
			{
 | 
						|
				size = g_utf8_skip[((unsigned char *)text)[i]];
 | 
						|
				if ((i + size) >= max)
 | 
						|
					break;
 | 
						|
				i += size;
 | 
						|
			}
 | 
						|
			max = i;
 | 
						|
			t = text[max];
 | 
						|
			text[max] = 0;			  /* insert a NULL terminator to shorten it */
 | 
						|
		}
 | 
						|
 | 
						|
		inbound_chanmsg (sess->server, sess, sess->channel, sess->server->nick,
 | 
						|
							  text, TRUE, FALSE);
 | 
						|
		sess->server->p_message (sess->server, sess->channel, text);
 | 
						|
 | 
						|
		if (t)
 | 
						|
		{
 | 
						|
			text[max] = t;
 | 
						|
			handle_say (sess, text + max, FALSE);
 | 
						|
		}
 | 
						|
 | 
						|
	} else
 | 
						|
	{
 | 
						|
		notc_msg (sess);
 | 
						|
	}
 | 
						|
 | 
						|
xit:
 | 
						|
	if (pdibuf != pdibuf_static)
 | 
						|
		free (pdibuf);
 | 
						|
 | 
						|
	if (newcmd != newcmd_static)
 | 
						|
		free (newcmd);
 | 
						|
}
 | 
						|
 | 
						|
/* handle a command, without the '/' prefix */
 | 
						|
 | 
						|
int
 | 
						|
handle_command (session *sess, char *cmd, int check_spch)
 | 
						|
{
 | 
						|
	struct popup *pop;
 | 
						|
	int user_cmd = FALSE;
 | 
						|
	GSList *list;
 | 
						|
	char *word[PDIWORDS+1];
 | 
						|
	char *word_eol[PDIWORDS+1];
 | 
						|
	static int command_level = 0;
 | 
						|
	struct commands *int_cmd;
 | 
						|
	char pdibuf_static[1024];
 | 
						|
	char tbuf_static[TBUFSIZE];
 | 
						|
	char *pdibuf;
 | 
						|
	char *tbuf;
 | 
						|
	int len;
 | 
						|
	int ret = TRUE;
 | 
						|
 | 
						|
	if (command_level > 99)
 | 
						|
	{
 | 
						|
		fe_message (_("Too many recursive usercommands, aborting."), FE_MSG_ERROR);
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
	command_level++;
 | 
						|
	/* anything below MUST DEC command_level before returning */
 | 
						|
 | 
						|
	len = strlen (cmd);
 | 
						|
	if (len >= sizeof (pdibuf_static))
 | 
						|
		pdibuf = malloc (len + 1);
 | 
						|
	else
 | 
						|
		pdibuf = pdibuf_static;
 | 
						|
 | 
						|
	if ((len * 2) >= sizeof (tbuf_static))
 | 
						|
		tbuf = malloc ((len * 2) + 1);
 | 
						|
	else
 | 
						|
		tbuf = tbuf_static;
 | 
						|
 | 
						|
	/* split the text into words and word_eol */
 | 
						|
	process_data_init (pdibuf, cmd, word, word_eol, TRUE, TRUE);
 | 
						|
 | 
						|
	/* ensure an empty string at index 32 for cmd_deop etc */
 | 
						|
	/* (internal use only, plugins can still only read 1-31). */
 | 
						|
	word[PDIWORDS] = "\000\000";
 | 
						|
	word_eol[PDIWORDS] = "\000\000";
 | 
						|
 | 
						|
	int_cmd = find_internal_command (word[1]);
 | 
						|
	/* redo it without quotes processing, for some commands like /JOIN */
 | 
						|
	if (int_cmd && !int_cmd->handle_quotes)
 | 
						|
		process_data_init (pdibuf, cmd, word, word_eol, FALSE, FALSE);
 | 
						|
 | 
						|
	if (check_spch && prefs.perc_color)
 | 
						|
		check_special_chars (cmd, prefs.perc_ascii);
 | 
						|
 | 
						|
	if (plugin_emit_command (sess, word[1], word, word_eol))
 | 
						|
		goto xit;
 | 
						|
 | 
						|
	/* incase a plugin did /close */
 | 
						|
	if (!is_session (sess))
 | 
						|
		goto xit;
 | 
						|
 | 
						|
	/* first see if it's a userCommand */
 | 
						|
	list = command_list;
 | 
						|
	while (list)
 | 
						|
	{
 | 
						|
		pop = (struct popup *) list->data;
 | 
						|
		if (!strcasecmp (pop->name, word[1]))
 | 
						|
		{
 | 
						|
			user_command (sess, tbuf, pop->cmd, word, word_eol);
 | 
						|
			user_cmd = TRUE;
 | 
						|
		}
 | 
						|
		list = list->next;
 | 
						|
	}
 | 
						|
 | 
						|
	if (user_cmd)
 | 
						|
		goto xit;
 | 
						|
 | 
						|
	/* now check internal commands */
 | 
						|
	int_cmd = find_internal_command (word[1]);
 | 
						|
 | 
						|
	if (int_cmd)
 | 
						|
	{
 | 
						|
		if (int_cmd->needserver && !sess->server->connected)
 | 
						|
		{
 | 
						|
			notc_msg (sess);
 | 
						|
		} else if (int_cmd->needchannel && !sess->channel[0])
 | 
						|
		{
 | 
						|
			notj_msg (sess);
 | 
						|
		} else
 | 
						|
		{
 | 
						|
			switch (int_cmd->callback (sess, tbuf, word, word_eol))
 | 
						|
			{
 | 
						|
			case FALSE:
 | 
						|
				help (sess, tbuf, int_cmd->name, TRUE);
 | 
						|
				break;
 | 
						|
			case 2:
 | 
						|
				ret = FALSE;
 | 
						|
				goto xit;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	} else
 | 
						|
	{
 | 
						|
		/* unknown command, just send it to the server and hope */
 | 
						|
		if (!sess->server->connected)
 | 
						|
			PrintText (sess, _("Unknown Command. Try /help\n"));
 | 
						|
		else
 | 
						|
			sess->server->p_raw (sess->server, cmd);
 | 
						|
	}
 | 
						|
 | 
						|
xit:
 | 
						|
	command_level--;
 | 
						|
 | 
						|
	if (pdibuf != pdibuf_static)
 | 
						|
		free (pdibuf);
 | 
						|
 | 
						|
	if (tbuf != tbuf_static)
 | 
						|
		free (tbuf);
 | 
						|
 | 
						|
	return ret;
 | 
						|
}
 | 
						|
 | 
						|
/* handle one line entered into the input box */
 | 
						|
 | 
						|
static int
 | 
						|
handle_user_input (session *sess, char *text, int history, int nocommand)
 | 
						|
{
 | 
						|
	if (*text == '\0')
 | 
						|
		return 1;
 | 
						|
 | 
						|
	if (history)
 | 
						|
		history_add (&sess->history, text);
 | 
						|
 | 
						|
	/* is it NOT a command, just text? */
 | 
						|
	if (nocommand || text[0] != prefs.cmdchar[0])
 | 
						|
	{
 | 
						|
		handle_say (sess, text, TRUE);
 | 
						|
		return 1;
 | 
						|
	}
 | 
						|
 | 
						|
	/* check for // */
 | 
						|
	if (text[0] == prefs.cmdchar[0] && text[1] == prefs.cmdchar[0])
 | 
						|
	{
 | 
						|
		handle_say (sess, text + 1, TRUE);
 | 
						|
		return 1;
 | 
						|
	}
 | 
						|
 | 
						|
	if (prefs.cmdchar[0] == '/')
 | 
						|
	{
 | 
						|
		int i;
 | 
						|
		const char *unix_dirs [] = {
 | 
						|
			"/bin/", "/boot/", "/dev/",
 | 
						|
			"/etc/", "/home/", "/lib/",
 | 
						|
			"/lost+found/", "/mnt/", "/opt/",
 | 
						|
			"/proc/", "/root/", "/sbin/",
 | 
						|
			"/tmp/", "/usr/", "/var/",
 | 
						|
			"/gnome/", NULL};
 | 
						|
		for (i = 0; unix_dirs[i] != NULL; i++)
 | 
						|
			if (strncmp (text, unix_dirs[i], strlen (unix_dirs[i]))==0)
 | 
						|
			{
 | 
						|
				handle_say (sess, text, TRUE);
 | 
						|
				return 1;
 | 
						|
			}
 | 
						|
	}
 | 
						|
 | 
						|
	return handle_command (sess, text + 1, TRUE);
 | 
						|
}
 | 
						|
 | 
						|
/* changed by Steve Green. Macs sometimes paste with imbedded \r */
 | 
						|
void
 | 
						|
handle_multiline (session *sess, char *cmd, int history, int nocommand)
 | 
						|
{
 | 
						|
	while (*cmd)
 | 
						|
	{
 | 
						|
		char *cr = cmd + strcspn (cmd, "\n\r");
 | 
						|
		int end_of_string = *cr == 0;
 | 
						|
		*cr = 0;
 | 
						|
		if (!handle_user_input (sess, cmd, history, nocommand))
 | 
						|
			return;
 | 
						|
		if (end_of_string)
 | 
						|
			break;
 | 
						|
		cmd = cr + 1;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*void
 | 
						|
handle_multiline (session *sess, char *cmd, int history, int nocommand)
 | 
						|
{
 | 
						|
	char *cr;
 | 
						|
 | 
						|
	cr = strchr (cmd, '\n');
 | 
						|
	if (cr)
 | 
						|
	{
 | 
						|
		while (1)
 | 
						|
		{
 | 
						|
			if (cr)
 | 
						|
				*cr = 0;
 | 
						|
			if (!handle_user_input (sess, cmd, history, nocommand))
 | 
						|
				return;
 | 
						|
			if (!cr)
 | 
						|
				break;
 | 
						|
			cmd = cr + 1;
 | 
						|
			if (*cmd == 0)
 | 
						|
				break;
 | 
						|
			cr = strchr (cmd, '\n');
 | 
						|
		}
 | 
						|
	} else
 | 
						|
	{
 | 
						|
		handle_user_input (sess, cmd, history, nocommand);
 | 
						|
	}
 | 
						|
}*/
 |