/src/common/outbound.cpp
C++ | 4323 lines | 3628 code | 531 blank | 164 comment | 772 complexity | a58c9f02e7870bf087ca9704557a5602 MD5 | raw file
Possible License(s): GPL-2.0
- /* 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
-
- #ifdef __GNUC__
- #include <unistd.h>
- #endif
- #include <time.h>
- #include <signal.h>
- #include <sys/stat.h>
- #include <fcntl.h>
-
- #include "xchat.h"
- #include "xchatc.h"
- #include "outbound.h"
- #include "cfgfiles.h" // xchat_fopen_file()
- #include "chanopt.h"
- #include "dcc.h"
- #include "fe.h"
- #include "ignore.h"
- #include "inbound.h"
- #include "modes.h"
- #include "network.h" // net_ip()
- #include "notify.h"
- #include "plugin.h"
- #include "server.h"
- #include "servlist.h"
- #include "text.h"
- #include "tree.h"
- #include "userlist.h"
- #include "util.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(session *sess)
- {
- PrintText(sess, _("No channel joined. Try /join #<channel>\n"));
- }
-
- void notc_msg(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[], bool handle_quotes,
- bool 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] = buf;
- word_eol[1] = 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(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 = (session*)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 = (session*)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(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 = (server*)list->data;
- if (serv->connected)
- handle_command(serv->front_session, word_eol[2], FALSE);
- list = list->next;
- }
-
- return TRUE;
- }
-
- static int cmd_away(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 (((session*)list->data)->server == sess->server
- && ((session*)list->data)->type == SESS_CHANNEL
- && ((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(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 (((session*)list->data)->server == sess->server
- && ((session*)list->data)->type == SESS_CHANNEL
- && ((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;
- 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 a *
- 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 an 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(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(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(session *sess, char *tbuf, char *word[], char *word_eol[])
- {
- // chanopt.c
- return chanopt_command(sess, tbuf, word, word_eol);
- }
-
- static int cmd_charset(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(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 = (session*)list->data;
- if (!sess->nick_said)
- fe_text_clear((session*)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(session *sess, char *tbuf, char *word[], char *word_eol[])
- {
- GSList *list;
-
- if (strcmp(word[2], "-m") == 0)
- {
- list = sess_list;
- while (list)
- {
- sess = (session*)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(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;
- }
-
- typedef void (*print)(void*, char*, ...);
- static int cmd_country(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, (print)PrintTextf);
- return TRUE;
- }
-
- // search, but forgot the -s
- if (strchr(code, '*'))
- {
- country_search(code, sess, (print)PrintTextf);
- return TRUE;
- }
-
- sprintf(tbuf, "%s = %s\n", code, country(code));
- PrintText(sess, tbuf);
- return TRUE;
- }
- return FALSE;
- }
-
- static int cmd_cycle(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(session *sess, char *tbuf, char *word[], char *word_eol[])
- {
- int goodtype;
- 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(session *sess, char *tbuf, char *word[], char *word_eol[])
- {
- session *s;
- server *v;
- GSList *list = sess_list;
-
- PrintText(sess, "Session T Channel WaitChan WillChan Server\n");
- while (list)
- {
- s = (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 = (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(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(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(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(User *user, multidata *data)
- {
- if (user->hop && !user->me)
- {
- data->nicks[data->i] = user->nick;
- data->i++;
- }
- return TRUE;
- }
-
- static int cmd_mdehop(session *sess, char *tbuf, char *word[], char *word_eol[])
- {
- char **nicks = (char**)malloc(sizeof(char*) * sess->hops);
- multidata data;
-
- data.nicks = nicks;
- data.i = 0;
- tree_foreach((tree*)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(User *user, multidata *data)
- {
- if (user->op && !user->me)
- {
- data->nicks[data->i] = user->nick;
- data->i++;
- }
- return TRUE;
- }
-
- static int cmd_mdeop(session *sess, char *tbuf, char *word[], char *word_eol[])
- {
- char **nicks = (char**)malloc(sizeof(char*) * sess->ops);
- multidata data;
-
- data.nicks = nicks;
- data.i = 0;
- tree_foreach((tree*)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 = (menu_entry*)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 = (menu_entry*)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 = (menu_entry*)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, short *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 = (menu_entry*)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(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(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(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(session *sess, char *tbuf, char *word[], char *word_eol[])
- {
- multidata data;
-
- data.sess = sess;
- data.reason = word_eol[2];
- tree_foreach((tree*)sess->usertree, (tree_traverse_func*)mkickops_cb, &data);
- tree_foreach((tree*)sess->usertree, (tree_traverse_func*)mkick_cb, &data);
-
- return TRUE;
- }
-
- static int cmd_devoice(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(session *sess, char *tbuf, char *word[], char *word_eol[])
- {
- sess->server->disconnect(sess, TRUE, -1);
- return TRUE;
- }
-
- static int cmd_dns(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];
- 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(session *sess, char *tbuf, char *word[], char *word_eol[])
- {
- PrintText(sess, word_eol[2]);
- return TRUE;
- }
-
- #ifndef WIN32
-
- static void exec_check_process(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(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(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(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(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 = (char*)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 = (char*)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 bool exec_data(GIOChannel *source, GIOCondition condition, 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 = (char*)malloc(len + 2050);
- memcpy(buf, s->linebuf, len);
- readpos = buf + len;
- free(s->linebuf);
- s->linebuf = NULL;
- }
- else
- readpos = buf = (char*)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 = (char*)memrchr(buf, '\n', len);
- if (rest)
- rest++;
- else
- rest = buf;
- if (*rest) {
- s->buffill = len - (rest - buf); // = strlen(rest)
- s->linebuf = (char*)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(session *sess, char *tbuf, char *word[], char *word_eol[])
- {
- int tochannel = FALSE;
- char *cmd = word_eol[2];
- int fds[2], pid = 0;
- 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 = (nbexec*)malloc(sizeof(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, (void*)exec_data, s);
- sess->running_exec = s;
- return TRUE;
- }
- }
- return FALSE;
- }
-
- #endif
-
- static int cmd_flushq(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(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(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(session *sess, char *tbuf, char *word[], char *word_eol[])
- {
- getvalinfo *info;
-
- if (!word[4][0])
- return FALSE;
-
- info = (getvalinfo*)malloc(sizeof(*info));
- info->cmd = strdup(word[3]);
- info->sess = sess;
-
- fe_get_int(word[4], atoi(word[2]), (void*)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);
- }
- }
-
- typedef void (*callback)(void*, char*);
- static int cmd_getfile(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], (callback)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(session *sess, char *tbuf, char *word[], char *word_eol[])
- {
- getvalinfo *info;
-
- if (!word[4][0])
- return FALSE;
-
- info = (getvalinfo*)malloc(sizeof(*info));
- info->cmd = strdup(word[3]);
- info->sess = sess;
-
- fe_get_str(word[4], word[2], (void*)get_str_cb, info);
-
- return TRUE;
- }
-
- static int cmd_ghost(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(session *sess, char *tbuf, char *word[], char *word_eol[])
- {
- switch (str_ihash((const unsigned char*)word[2]))
- {
- case 0x058b836e: fe_ctrl_gui(sess, FE_GUI_APPLY, 0); break; // APPLY
- case 0xac1eee45: fe_ctrl_gui(sess, FE_GUI_ATTACH, 2); break; // ATTACH
- case 0x05a72f63: fe_ctrl_gui(sess, FE_GUI_COLOR, atoi(word[3])); break; // COLOR
- case 0xb06a1793: fe_ctrl_gui(sess, FE_GUI_ATTACH, 1); break; // DETACH
- case 0x05cfeff0: fe_ctrl_gui(sess, FE_GUI_FLASH, 0); break; // FLASH
- case 0x05d154d8: fe_ctrl_gui(sess, FE_GUI_FOCUS, 0); break; // FOCUS
- case 0x0030dd42: fe_ctrl_gui(sess, FE_GUI_HIDE, 0); break; // HIDE
- case 0x61addbe3: fe_ctrl_gui(sess, FE_GUI_ICONIFY, 0); break; // ICONIFY
- case 0xc0851aaa: fe_message(word[3], FE_MSG_INFO|FE_MSG_MARKUP); break; // MSGBOX
- case 0x0035dafd: fe_ctrl_gui(sess, FE_GUI_SHOW, 0); break; // SHOW
- case 0x0033155f: // MENU
- if (!strcasecmp(word[3], "TOGGLE"))
- fe_ctrl_gui(sess, FE_GUI_MENU, 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;
- }
- }
- }
- }
-
- typedef void (*cb)(session*, void*, char*, char*);
- static int cmd_help(session *sess, char *tbuf, char *word[], char *word_eol[])
- {
- int i = 0, longfmt = 0;
- char *helpcmd = 0;
- GSList *list;
-
- if (tbuf)
- helpcmd = word[2];
- if (*helpcmd && strcmp(helpcmd, "-l") == 0)
- longfmt = 1;
-
- if (*helpcmd && !longfmt)
- {
- help(sess, tbuf, helpcmd, FALSE);
- }
- else
- {
- popup *pop;
- char *buf = (char*)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 = (popup*)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, (cb)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(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(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(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(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(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(session *sess, char *tbuf, char *word[], char *word_eol[])
- {
- char *nick = word[2];
- char *reason = word_eol[3];
- 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(session *sess, char *tbuf, char *word[], char *word_eol[])
- {
- xchat_exit();
- return 2;
- }
-
- static int cmd_lagcheck(session *sess, char *tbuf, char *word[], char *word_eol[])
- {
- lag_check();
- return TRUE;
- }
-
- static void lastlog(session *sess, char *search, bool 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(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(session *sess, char *tbuf, char *word[], char *word_eol[])
- {
- sess->server->p_list_channels(sess->server, word_eol[2], 1);
-
- return TRUE;
- }
-
- bool 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(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(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(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(User *user, multidata *data)
- {
- if (!user->op)
- {
- data->nicks[data->i] = user->nick;
- data->i++;
- }
- return TRUE;
- }
-
- static int cmd_mop(session *sess, char *tbuf, char *word[], char *word_eol[])
- {
- char **nicks = (char**)malloc(sizeof(char*) * (sess->total - sess->ops));
- multidata data;
-
- data.nicks = nicks;
- data.i = 0;
- tree_foreach((tree*)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(session *sess, char *tbuf, char *word[], char *word_eol[])
- {
- char *nick = word[2];
- char *msg = word_eol[3];
- 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 && prefs.gui_auto_open_msg)
- {
- newsess = new_ircwindow(sess->server, nick, SESS_DIALOG, 0);
- }
- }
- 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(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(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(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(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(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(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(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(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(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, bool 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, FE_GUI_FOCUS, 0); // bring-to-front
- }
-
- static int cmd_query(session *sess, char *tbuf, char *word[], char *word_eol[])
- {
- char *nick = word[2];
- bool 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(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(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 = (server*)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(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(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(session *sess, char *tbuf, char *word[], char *word_eol[])
- {
- unsigned int addr;
- socklen_t len;
- 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(sockaddr_in));
- len = sizeof(SAddr);
- getsockname(sess->server->sok, (sockaddr*)&SAddr, (socklen_t*)&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(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(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(session *sess, char *tbuf, char *word[], char *word_eol[])
- {
- fe_set_inputbox_contents(sess, word_eol[2]);
- return TRUE;
- }
-
- static int cmd_splay(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(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(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(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(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((feicon)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(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(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 = (server*)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 = (server*)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(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 = 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);
- free(url);
- return TRUE;
- }
- }
- else
- {
- // an un-listed connection
- serv = find_server_from_hostname(server_name);
- if (serv)
- {
- url_join_only(serv, tbuf, channel);
- 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]);
- free(url);
- return TRUE;
- }
-
- return FALSE;
- }
-
- static int userlist_cb(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(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(session *sess, char *tbuf, char *word[], char *word_eol[])
- {
- tree_foreach((tree*)sess->usertree, (tree_traverse_func*)userlist_cb, sess);
- return TRUE;
- }
-
- static int wallchop_cb(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(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((tree*)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(session *sess, char *tbuf, char *word[], char *word_eol[])
- {
- GSList *list;
-
- if (*word_eol[2])
- {
- list = sess_list;
- while (list)
- {
- sess = (session*)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(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(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 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://pchat-irc.com/documentation/ 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 PChat, 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((const char*)a, ((commands*)b)->name);
- }
-
- static commands* find_internal_command(char *name)
- {
- // the "-1" is to skip the NULL terminator
- return (commands*)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)
- {
- 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;
- tm *tm_ptr;
- char *utf;
- size_t utf_len;
- char *orig = dest;
-
- destlen--;
-
- while (src[0])
- {
- if (src[0] == '%' || src[0] == '&')
- {
- if (isdigit(src[1]))
- {
- if (isdigit(src[2]) && isdigit(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, (gsize*)&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;
- 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;
- size_t utf_len;
-
- if (!len)
- return;
-
- buf = (char*)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, (gsize*)&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;
- User *best;
- int bestlen;
- char *space;
- char *tbuf;
- } nickdata;
-
- static int nick_comp_cb(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(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((tree*)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, (unsigned char*)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)
- {
- 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 = (char*)malloc(len + 1);
-
- if (len + NICKLEN >= newcmdlen)
- newcmd = (char*)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)
- {
- popup *pop;
- int user_cmd = FALSE;
- GSList *list;
- char *word[PDIWORDS+1];
- char *word_eol[PDIWORDS+1];
- static int command_level = 0;
- 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 = (char*)malloc(len + 1);
- else
- pdibuf = pdibuf_static;
-
- if ((len * 2) >= sizeof(tbuf_static))
- tbuf = (char*)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 = (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);
- }
- }*/