/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
Large files files are truncated, but you can click here to view the full file
- /* 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…
Large files files are truncated, but you can click here to view the full file