/src/common/proto-irc.c
C | 1262 lines | 1025 code | 171 blank | 66 comment | 191 complexity | 5f1b76a096dd81cb2f927c4a5b546392 MD5 | raw file
Possible License(s): GPL-2.0
- /* X-Chat
- * Copyright (C) 2002 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
- */
- /* IRC RFC1459(+commonly used extensions) protocol implementation */
- #include <unistd.h>
- #include <string.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <ctype.h>
- #include <stdarg.h>
- #include "xchat.h"
- #include "ctcp.h"
- #include "fe.h"
- #include "ignore.h"
- #include "inbound.h"
- #include "modes.h"
- #include "notify.h"
- #include "plugin.h"
- #include "server.h"
- #include "text.h"
- #include "outbound.h"
- #include "util.h"
- #include "xchatc.h"
- static void
- irc_login (server *serv, char *user, char *realname)
- {
- if (serv->password[0])
- tcp_sendf (serv, "PASS %s\r\n", serv->password);
- tcp_sendf (serv,
- "NICK %s\r\n"
- "USER %s %s %s :%s\r\n",
- serv->nick, user, user, serv->servername, realname);
- }
- static void
- irc_nickserv (server *serv, char *cmd, char *arg1, char *arg2, char *arg3)
- {
- /* are all ircd authors idiots? */
- switch (serv->nickservtype)
- {
- case 0:
- tcp_sendf (serv, "PRIVMSG NICKSERV :%s %s%s%s\r\n", cmd, arg1, arg2, arg3);
- break;
- case 1:
- tcp_sendf (serv, "NICKSERV %s %s%s%s\r\n", cmd, arg1, arg2, arg3);
- break;
- case 2:
- tcp_sendf (serv, "NS %s %s%s%s\r\n", cmd, arg1, arg2, arg3);
- break;
- case 3:
- tcp_sendf (serv, "PRIVMSG NS :%s %s%s%s\r\n", cmd, arg1, arg2, arg3);
- break;
- case 4:
- /* why couldn't QuakeNet implement one of the existing ones? */
- tcp_sendf (serv, "AUTH %s%s%s\r\n", cmd, arg1, arg2, arg3);
- }
- }
- static void
- irc_ns_identify (server *serv, char *pass)
- {
- irc_nickserv (serv, "IDENTIFY", pass, "", "");
- }
- static void
- irc_ns_ghost (server *serv, char *usname, char *pass)
- {
- if (serv->nickservtype != 4)
- irc_nickserv (serv, "GHOST", usname, " ", pass);
- }
- static void
- irc_join (server *serv, char *channel, char *key)
- {
- if (key[0])
- tcp_sendf (serv, "JOIN %s %s\r\n", channel, key);
- else
- tcp_sendf (serv, "JOIN %s\r\n", channel);
- }
- static void
- irc_join_list_flush (server *serv, GString *c, GString *k)
- {
- char *chanstr, *keystr;
- chanstr = g_string_free (c, FALSE);
- keystr = g_string_free (k, FALSE);
- if (chanstr[0])
- {
- if (keystr[0])
- tcp_sendf (serv, "JOIN %s %s\r\n", chanstr, keystr);
- else
- tcp_sendf (serv, "JOIN %s\r\n", chanstr);
- }
- g_free (chanstr);
- g_free (keystr);
- }
- /* join a whole list of channels & keys, split to multiple lines
- * to get around 512 limit */
- static void
- irc_join_list (server *serv, GSList *channels, GSList *keys)
- {
- GSList *clist;
- GSList *klist;
- GString *c = g_string_new (NULL);
- GString *k = g_string_new (NULL);
- int len;
- int add;
- int i, j;
- i = j = 0;
- len = 9; /* "JOIN<space><space>\r\n" */
- clist = channels;
- klist = keys;
- while (clist)
- {
- /* measure how many bytes this channel would add... */
- if (1)
- {
- add = strlen (clist->data);
- if (i != 0)
- add++; /* comma */
- }
- if (klist->data)
- {
- add += strlen (klist->data);
- }
- else
- {
- add++; /* 'x' filler */
- }
- if (j != 0)
- add++; /* comma */
- /* too big? dump buffer and start a fresh one */
- if (len + add > 512)
- {
- irc_join_list_flush (serv, c, k);
- c = g_string_new (NULL);
- k = g_string_new (NULL);
- i = j = 0;
- len = 9;
- }
- /* now actually add it to our GStrings */
- if (1)
- {
- add = strlen (clist->data);
- if (i != 0)
- {
- add++;
- g_string_append_c (c, ',');
- }
- g_string_append (c, clist->data);
- i++;
- }
- if (klist->data)
- {
- add += strlen (klist->data);
- if (j != 0)
- {
- add++;
- g_string_append_c (k, ',');
- }
- g_string_append (k, klist->data);
- j++;
- }
- else
- {
- add++;
- if (j != 0)
- {
- add++;
- g_string_append_c (k, ',');
- }
- g_string_append_c (k, 'x');
- j++;
- }
- len += add;
- klist = klist->next;
- clist = clist->next;
- }
- irc_join_list_flush (serv, c, k);
- }
- static void
- irc_part (server *serv, char *channel, char *reason)
- {
- if (reason[0])
- tcp_sendf (serv, "PART %s :%s\r\n", channel, reason);
- else
- tcp_sendf (serv, "PART %s\r\n", channel);
- }
- static void
- irc_quit (server *serv, char *reason)
- {
- if (reason[0])
- tcp_sendf (serv, "QUIT :%s\r\n", reason);
- else
- tcp_send_len (serv, "QUIT\r\n", 6);
- }
- static void
- irc_set_back (server *serv)
- {
- tcp_send_len (serv, "AWAY\r\n", 6);
- }
- static void
- irc_set_away (server *serv, char *reason)
- {
- if (reason)
- {
- if (!reason[0])
- reason = " ";
- }
- else
- {
- reason = " ";
- }
- tcp_sendf (serv, "AWAY :%s\r\n", reason);
- }
- static void
- irc_ctcp (server *serv, char *to, char *msg)
- {
- tcp_sendf (serv, "PRIVMSG %s :\001%s\001\r\n", to, msg);
- }
- static void
- irc_nctcp (server *serv, char *to, char *msg)
- {
- tcp_sendf (serv, "NOTICE %s :\001%s\001\r\n", to, msg);
- }
- static void
- irc_cycle (server *serv, char *channel, char *key)
- {
- tcp_sendf (serv, "PART %s\r\nJOIN %s %s\r\n", channel, channel, key);
- }
- static void
- irc_kick (server *serv, char *channel, char *nick, char *reason)
- {
- if (reason[0])
- tcp_sendf (serv, "KICK %s %s :%s\r\n", channel, nick, reason);
- else
- tcp_sendf (serv, "KICK %s %s\r\n", channel, nick);
- }
- static void
- irc_invite (server *serv, char *channel, char *nick)
- {
- tcp_sendf (serv, "INVITE %s %s\r\n", nick, channel);
- }
- static void
- irc_mode (server *serv, char *target, char *mode)
- {
- tcp_sendf (serv, "MODE %s %s\r\n", target, mode);
- }
- /* find channel info when joined */
- static void
- irc_join_info (server *serv, char *channel)
- {
- tcp_sendf (serv, "MODE %s\r\n", channel);
- }
- /* initiate userlist retreival */
- static void
- irc_user_list (server *serv, char *channel)
- {
- tcp_sendf (serv, "WHO %s\r\n", channel);
- }
- /* userhost */
- static void
- irc_userhost (server *serv, char *nick)
- {
- tcp_sendf (serv, "USERHOST %s\r\n", nick);
- }
- static void
- irc_away_status (server *serv, char *channel)
- {
- if (serv->have_whox)
- tcp_sendf (serv, "WHO %s %%ctnf,152\r\n", channel);
- else
- tcp_sendf (serv, "WHO %s\r\n", channel);
- }
- /*static void
- irc_get_ip (server *serv, char *nick)
- {
- tcp_sendf (serv, "WHO %s\r\n", nick);
- }*/
- /*
- * Command: WHOIS
- * Parameters: [<server>] <nickmask>[,<nickmask>[,...]]
- */
- static void
- irc_user_whois (server *serv, char *nicks)
- {
- tcp_sendf (serv, "WHOIS %s\r\n", nicks);
- }
- static void
- irc_message (server *serv, char *channel, char *text)
- {
- tcp_sendf (serv, "PRIVMSG %s :%s\r\n", channel, text);
- }
- static void
- irc_action (server *serv, char *channel, char *act)
- {
- tcp_sendf (serv, "PRIVMSG %s :\001ACTION %s\001\r\n", channel, act);
- }
- static void
- irc_notice (server *serv, char *channel, char *text)
- {
- tcp_sendf (serv, "NOTICE %s :%s\r\n", channel, text);
- }
- static void
- irc_topic (server *serv, char *channel, char *topic)
- {
- if (!topic)
- tcp_sendf (serv, "TOPIC %s :\r\n", channel);
- else if (topic[0])
- tcp_sendf (serv, "TOPIC %s :%s\r\n", channel, topic);
- else
- tcp_sendf (serv, "TOPIC %s\r\n", channel);
- }
- static void
- irc_list_channels (server *serv, char *arg, int min_users)
- {
- if (arg[0])
- {
- tcp_sendf (serv, "LIST %s\r\n", arg);
- return;
- }
- if (serv->use_listargs)
- tcp_sendf (serv, "LIST >%d,<10000\r\n", min_users - 1);
- else
- tcp_send_len (serv, "LIST\r\n", 6);
- }
- static void
- irc_names (server *serv, char *channel)
- {
- tcp_sendf (serv, "NAMES %s\r\n", channel);
- }
- static void
- irc_change_nick (server *serv, char *new_nick)
- {
- tcp_sendf (serv, "NICK %s\r\n", new_nick);
- }
- static void
- irc_ping (server *serv, char *to, char *timestring)
- {
- if (*to)
- tcp_sendf (serv, "PRIVMSG %s :\001PING %s\001\r\n", to, timestring);
- else
- tcp_sendf (serv, "PING %s\r\n", timestring);
- }
- static int
- irc_raw (server *serv, char *raw)
- {
- int len;
- char tbuf[4096];
- if (*raw)
- {
- len = strlen (raw);
- if (len < sizeof (tbuf) - 3)
- {
- len = snprintf (tbuf, sizeof (tbuf), "%s\r\n", raw);
- tcp_send_len (serv, tbuf, len);
- } else
- {
- tcp_send_len (serv, raw, len);
- tcp_send_len (serv, "\r\n", 2);
- }
- return TRUE;
- }
- return FALSE;
- }
- /* ============================================================== */
- /* ======================= IRC INPUT ============================ */
- /* ============================================================== */
- static void
- channel_date (session *sess, char *chan, char *timestr)
- {
- time_t timestamp = (time_t) atol (timestr);
- char *tim = ctime (×tamp);
- tim[24] = 0; /* get rid of the \n */
- EMIT_SIGNAL (XP_TE_CHANDATE, sess, chan, tim, NULL, NULL, 0);
- }
- static void
- process_numeric (session * sess, int n,
- char *word[], char *word_eol[], char *text)
- {
- server *serv = sess->server;
- /* show whois is the server tab */
- session *whois_sess = serv->server_session;
- /* unless this setting is on */
- if (prefs.irc_whois_front)
- whois_sess = serv->front_session;
- switch (n)
- {
- case 1:
- inbound_login_start (sess, word[3], word[1]);
- /* if network is PTnet then you must get your IP address
- from "001" server message */
- if ((strncmp(word[7], "PTnet", 5) == 0) &&
- (strncmp(word[8], "IRC", 3) == 0) &&
- (strncmp(word[9], "Network", 7) == 0) &&
- (strrchr(word[10], '@') != NULL))
- {
- serv->use_who = FALSE;
- if (prefs.ip_from_server)
- inbound_foundip (sess, strrchr(word[10], '@')+1);
- }
- /* use /NICKSERV */
- if (strcasecmp (word[7], "DALnet") == 0 ||
- strcasecmp (word[7], "BRASnet") == 0)
- serv->nickservtype = 1;
- /* use /NS */
- else if (strcasecmp (word[7], "FreeNode") == 0)
- serv->nickservtype = 2;
- goto def;
- case 4: /* check the ircd type */
- serv->use_listargs = FALSE;
- serv->modes_per_line = 3; /* default to IRC RFC */
- if (strncmp (word[5], "bahamut", 7) == 0) /* DALNet */
- {
- serv->use_listargs = TRUE; /* use the /list args */
- } else if (strncmp (word[5], "u2.10.", 6) == 0) /* Undernet */
- {
- serv->use_listargs = TRUE; /* use the /list args */
- serv->modes_per_line = 6; /* allow 6 modes per line */
- } else if (strncmp (word[5], "glx2", 4) == 0)
- {
- serv->use_listargs = TRUE; /* use the /list args */
- }
- goto def;
- case 5:
- inbound_005 (serv, word);
- goto def;
- case 263: /*Server load is temporarily too heavy */
- if (fe_is_chanwindow (sess->server))
- {
- fe_chan_list_end (sess->server);
- fe_message (word_eol[5] + 1, FE_MSG_ERROR);
- }
- goto def;
- case 290: /* CAPAB reply */
- if (strstr (word_eol[1], "IDENTIFY-MSG"))
- {
- serv->have_idmsg = TRUE;
- break;
- }
- goto def;
- case 301:
- inbound_away (serv, word[4],
- (word_eol[5][0] == ':') ? word_eol[5] + 1 : word_eol[5]);
- break;
- case 302:
- if (serv->skip_next_userhost)
- {
- char *eq = strchr (word[4], '=');
- if (eq)
- {
- *eq = 0;
- if (!serv->p_cmp (word[4] + 1, serv->nick))
- {
- char *at = strrchr (eq + 1, '@');
- if (at)
- inbound_foundip (sess, at + 1);
- }
- }
- serv->skip_next_userhost = FALSE;
- break;
- }
- else goto def;
- case 303:
- word[4]++;
- notify_markonline (serv, word);
- break;
- case 305:
- inbound_uback (serv);
- goto def;
- case 306:
- inbound_uaway (serv);
- goto def;
- case 312:
- if (!serv->skip_next_whois)
- EMIT_SIGNAL (XP_TE_WHOIS3, whois_sess, word[4], word_eol[5], NULL, NULL, 0);
- else
- inbound_user_info (sess, NULL, NULL, NULL, word[5], word[4], NULL, 0xff);
- break;
- case 311: /* WHOIS 1st line */
- serv->inside_whois = 1;
- inbound_user_info_start (sess, word[4]);
- if (!serv->skip_next_whois)
- EMIT_SIGNAL (XP_TE_WHOIS1, whois_sess, word[4], word[5],
- word[6], word_eol[8] + 1, 0);
- else
- inbound_user_info (sess, NULL, word[5], word[6], NULL, word[4],
- word_eol[8][0] == ':' ? word_eol[8] + 1 : word_eol[8], 0xff);
- break;
- case 314: /* WHOWAS */
- inbound_user_info_start (sess, word[4]);
- EMIT_SIGNAL (XP_TE_WHOIS1, whois_sess, word[4], word[5],
- word[6], word_eol[8] + 1, 0);
- break;
- case 317:
- if (!serv->skip_next_whois)
- {
- time_t timestamp = (time_t) atol (word[6]);
- long idle = atol (word[5]);
- char *tim;
- char outbuf[64];
- snprintf (outbuf, sizeof (outbuf),
- "%02ld:%02ld:%02ld", idle / 3600, (idle / 60) % 60,
- idle % 60);
- if (timestamp == 0)
- EMIT_SIGNAL (XP_TE_WHOIS4, whois_sess, word[4],
- outbuf, NULL, NULL, 0);
- else
- {
- tim = ctime (×tamp);
- tim[19] = 0; /* get rid of the \n */
- EMIT_SIGNAL (XP_TE_WHOIS4T, whois_sess, word[4],
- outbuf, tim, NULL, 0);
- }
- }
- break;
- case 318: /* END OF WHOIS */
- if (!serv->skip_next_whois)
- EMIT_SIGNAL (XP_TE_WHOIS6, whois_sess, word[4], NULL,
- NULL, NULL, 0);
- serv->skip_next_whois = 0;
- serv->inside_whois = 0;
- break;
- case 313:
- case 319:
- if (!serv->skip_next_whois)
- EMIT_SIGNAL (XP_TE_WHOIS2, whois_sess, word[4],
- word_eol[5] + 1, NULL, NULL, 0);
- break;
- case 307: /* dalnet version */
- case 320: /* :is an identified user */
- if (!serv->skip_next_whois)
- EMIT_SIGNAL (XP_TE_WHOIS_ID, whois_sess, word[4],
- word_eol[5] + 1, NULL, NULL, 0);
- break;
- case 321:
- if (!fe_is_chanwindow (sess->server))
- EMIT_SIGNAL (XP_TE_CHANLISTHEAD, serv->server_session, NULL, NULL, NULL, NULL, 0);
- break;
- case 322:
- if (fe_is_chanwindow (sess->server))
- {
- fe_add_chan_list (sess->server, word[4], word[5], word_eol[6] + 1);
- } else
- {
- PrintTextf (serv->server_session, "%-16s %-7d %s\017\n",
- word[4], atoi (word[5]), word_eol[6] + 1);
- }
- break;
- case 323:
- if (!fe_is_chanwindow (sess->server))
- EMIT_SIGNAL (XP_TE_SERVTEXT, serv->server_session, text, word[1], word[2], NULL, 0);
- else
- fe_chan_list_end (sess->server);
- break;
- case 324:
- sess = find_channel (serv, word[4]);
- if (!sess)
- sess = serv->server_session;
- if (sess->ignore_mode)
- sess->ignore_mode = FALSE;
- else
- EMIT_SIGNAL (XP_TE_CHANMODES, sess, word[4], word_eol[5],
- NULL, NULL, 0);
- fe_update_mode_buttons (sess, 't', '-');
- fe_update_mode_buttons (sess, 'n', '-');
- fe_update_mode_buttons (sess, 's', '-');
- fe_update_mode_buttons (sess, 'i', '-');
- fe_update_mode_buttons (sess, 'p', '-');
- fe_update_mode_buttons (sess, 'm', '-');
- fe_update_mode_buttons (sess, 'l', '-');
- fe_update_mode_buttons (sess, 'k', '-');
- handle_mode (serv, word, word_eol, "", TRUE);
- break;
- case 329:
- sess = find_channel (serv, word[4]);
- if (sess)
- {
- if (sess->ignore_date)
- sess->ignore_date = FALSE;
- else
- channel_date (sess, word[4], word[5]);
- }
- break;
- case 330:
- if (!serv->skip_next_whois)
- EMIT_SIGNAL (XP_TE_WHOIS_AUTH, whois_sess, word[4],
- word_eol[6] + 1, word[5], NULL, 0);
- break;
- case 332:
- inbound_topic (serv, word[4],
- (word_eol[5][0] == ':') ? word_eol[5] + 1 : word_eol[5]);
- break;
- case 333:
- inbound_topictime (serv, word[4], word[5], atol (word[6]));
- break;
- #if 0
- case 338: /* Undernet Real user@host, Real IP */
- EMIT_SIGNAL (XP_TE_WHOIS_REALHOST, sess, word[4], word[5], word[6],
- (word_eol[7][0]==':') ? word_eol[7]+1 : word_eol[7], 0);
- break;
- #endif
- case 341: /* INVITE ACK */
- EMIT_SIGNAL (XP_TE_UINVITE, sess, word[4], word[5], serv->servername,
- NULL, 0);
- break;
- case 352: /* WHO */
- {
- unsigned int away = 0;
- session *who_sess = find_channel (serv, word[4]);
- if (*word[9] == 'G')
- away = 1;
- inbound_user_info (sess, word[4], word[5], word[6], word[7],
- word[8], word_eol[11], away);
- /* try to show only user initiated whos */
- if (!who_sess || !who_sess->doing_who)
- EMIT_SIGNAL (XP_TE_SERVTEXT, serv->server_session, text, word[1],
- word[2], NULL, 0);
- }
- break;
- case 354: /* undernet WHOX: used as a reply for irc_away_status */
- {
- unsigned int away = 0;
- session *who_sess;
- /* irc_away_status sends out a "152" */
- if (!strcmp (word[4], "152"))
- {
- who_sess = find_channel (serv, word[5]);
- if (*word[7] == 'G')
- away = 1;
- /* :SanJose.CA.us.undernet.org 354 z1 152 #zed1 z1 H@ */
- inbound_user_info (sess, word[5], 0, 0, 0, word[6], 0, away);
- /* try to show only user initiated whos */
- if (!who_sess || !who_sess->doing_who)
- EMIT_SIGNAL (XP_TE_SERVTEXT, serv->server_session, text,
- word[1], word[2], NULL, 0);
- } else
- goto def;
- }
- break;
- case 315: /* END OF WHO */
- {
- session *who_sess;
- who_sess = find_channel (serv, word[4]);
- if (who_sess)
- {
- if (!who_sess->doing_who)
- EMIT_SIGNAL (XP_TE_SERVTEXT, serv->server_session, text,
- word[1], word[2], NULL, 0);
- who_sess->doing_who = FALSE;
- } else
- {
- if (!serv->doing_dns)
- EMIT_SIGNAL (XP_TE_SERVTEXT, serv->server_session, text,
- word[1], word[2], NULL, 0);
- serv->doing_dns = FALSE;
- }
- }
- break;
- case 348: /* +e-list entry */
- if (!inbound_banlist (sess, atol (word[7]), word[4], word[5], word[6], TRUE))
- goto def;
- break;
- case 349: /* end of exemption list */
- sess = find_channel (serv, word[4]);
- if (!sess)
- {
- sess = serv->front_session;
- goto def;
- }
- if (!fe_is_banwindow (sess))
- goto def;
- fe_ban_list_end (sess, TRUE);
- break;
- case 353: /* NAMES */
- inbound_nameslist (serv, word[5],
- (word_eol[6][0] == ':') ? word_eol[6] + 1 : word_eol[6]);
- break;
- case 366:
- if (!inbound_nameslist_end (serv, word[4]))
- goto def;
- break;
- case 367: /* banlist entry */
- inbound_banlist (sess, atol (word[7]), word[4], word[5], word[6], FALSE);
- break;
- case 368:
- sess = find_channel (serv, word[4]);
- if (!sess)
- {
- sess = serv->front_session;
- goto def;
- }
- if (!fe_is_banwindow (sess))
- goto def;
- fe_ban_list_end (sess, FALSE);
- break;
- case 369: /* WHOWAS end */
- case 406: /* WHOWAS error */
- EMIT_SIGNAL (XP_TE_SERVTEXT, whois_sess, text, word[1], word[2], NULL, 0);
- serv->inside_whois = 0;
- break;
- case 372: /* motd text */
- case 375: /* motd start */
- if (!prefs.skipmotd || serv->motd_skipped)
- EMIT_SIGNAL (XP_TE_MOTD, serv->server_session, text, NULL, NULL,
- NULL, 0);
- break;
- case 376: /* end of motd */
- case 422: /* motd file is missing */
- inbound_login_end (sess, text);
- break;
- case 433: /* nickname in use */
- case 432: /* erroneous nickname */
- if (serv->end_of_motd)
- goto def;
- inbound_next_nick (sess, word[4]);
- break;
- case 437:
- if (serv->end_of_motd || is_channel (serv, word[4]))
- goto def;
- inbound_next_nick (sess, word[4]);
- break;
- case 471:
- EMIT_SIGNAL (XP_TE_USERLIMIT, sess, word[4], NULL, NULL, NULL, 0);
- break;
- case 473:
- EMIT_SIGNAL (XP_TE_INVITE, sess, word[4], NULL, NULL, NULL, 0);
- break;
- case 474:
- EMIT_SIGNAL (XP_TE_BANNED, sess, word[4], NULL, NULL, NULL, 0);
- break;
- case 475:
- EMIT_SIGNAL (XP_TE_KEYWORD, sess, word[4], NULL, NULL, NULL, 0);
- break;
- case 601:
- notify_set_offline (serv, word[4], FALSE);
- break;
- case 605:
- notify_set_offline (serv, word[4], TRUE);
- break;
- case 600:
- case 604:
- notify_set_online (serv, word[4]);
- break;
- default:
- if (serv->inside_whois && word[4][0])
- {
- /* some unknown WHOIS reply, ircd coders make them up weekly */
- if (!serv->skip_next_whois)
- EMIT_SIGNAL (XP_TE_WHOIS_SPECIAL, whois_sess, word[4],
- (word_eol[5][0] == ':') ? word_eol[5] + 1 : word_eol[5],
- word[2], NULL, 0);
- return;
- }
- def:
- if (is_channel (serv, word[4]))
- {
- session *realsess = find_channel (serv, word[4]);
- if (!realsess)
- realsess = serv->server_session;
- EMIT_SIGNAL (XP_TE_SERVTEXT, realsess, text, word[1], word[2], NULL, 0);
- } else
- {
- EMIT_SIGNAL (XP_TE_SERVTEXT, serv->server_session, text, word[1],
- word[2], NULL, 0);
- }
- }
- }
- /* handle named messages that starts with a ':' */
- static void
- process_named_msg (session *sess, char *type, char *word[], char *word_eol[])
- {
- server *serv = sess->server;
- char ip[128], nick[NICKLEN];
- char *text, *ex;
- int len = strlen (type);
- /* fill in the "ip" and "nick" buffers */
- ex = strchr (word[1], '!');
- if (!ex) /* no '!', must be a server message */
- {
- safe_strcpy (ip, word[1], sizeof (ip));
- safe_strcpy (nick, word[1], sizeof (nick));
- } else
- {
- safe_strcpy (ip, ex + 1, sizeof (ip));
- ex[0] = 0;
- safe_strcpy (nick, word[1], sizeof (nick));
- ex[0] = '!';
- }
- if (len == 4)
- {
- guint32 t;
- t = WORDL((guint8)type[0], (guint8)type[1], (guint8)type[2], (guint8)type[3]);
- /* this should compile to a bunch of: CMP.L, JE ... nice & fast */
- switch (t)
- {
- case WORDL('J','O','I','N'):
- {
- char *chan = word[3];
- if (*chan == ':')
- chan++;
- if (!serv->p_cmp (nick, serv->nick))
- inbound_ujoin (serv, chan, nick, ip);
- else
- inbound_join (serv, chan, nick, ip);
- }
- return;
- case WORDL('K','I','C','K'):
- {
- char *kicked = word[4];
- char *reason = word_eol[5];
- if (*kicked)
- {
- if (*reason == ':')
- reason++;
- if (!strcmp (kicked, serv->nick))
- inbound_ukick (serv, word[3], nick, reason);
- else
- inbound_kick (serv, word[3], kicked, nick, reason);
- }
- }
- return;
- case WORDL('K','I','L','L'):
- EMIT_SIGNAL (XP_TE_KILL, sess, nick, word_eol[5], NULL, NULL, 0);
- return;
- case WORDL('M','O','D','E'):
- handle_mode (serv, word, word_eol, nick, FALSE); /* modes.c */
- return;
- case WORDL('N','I','C','K'):
- inbound_newnick (serv, nick, (word_eol[3][0] == ':')
- ? word_eol[3] + 1 : word_eol[3], FALSE);
- return;
- case WORDL('P','A','R','T'):
- {
- char *chan = word[3];
- char *reason = word_eol[4];
- if (*chan == ':')
- chan++;
- if (*reason == ':')
- reason++;
- if (!strcmp (nick, serv->nick))
- inbound_upart (serv, chan, ip, reason);
- else
- inbound_part (serv, chan, nick, ip, reason);
- }
- return;
- case WORDL('P','O','N','G'):
- inbound_ping_reply (serv->server_session,
- (word[4][0] == ':') ? word[4] + 1 : word[4], word[3]);
- return;
- case WORDL('Q','U','I','T'):
- inbound_quit (serv, nick, ip,
- (word_eol[3][0] == ':') ? word_eol[3] + 1 : word_eol[3]);
- return;
- }
- goto garbage;
- }
- else if (len >= 5)
- {
- guint32 t;
- t = WORDL((guint8)type[0], (guint8)type[1], (guint8)type[2], (guint8)type[3]);
- /* this should compile to a bunch of: CMP.L, JE ... nice & fast */
- switch (t)
- {
- case WORDL('I','N','V','I'):
- if (ignore_check (word[1], IG_INVI))
- return;
-
- if (word[4][0] == ':')
- EMIT_SIGNAL (XP_TE_INVITED, sess, word[4] + 1, nick,
- serv->servername, NULL, 0);
- else
- EMIT_SIGNAL (XP_TE_INVITED, sess, word[4], nick,
- serv->servername, NULL, 0);
-
- return;
- case WORDL('N','O','T','I'):
- {
- int id = FALSE; /* identified */
- text = word_eol[4];
- if (*text == ':')
- text++;
- if (serv->have_idmsg)
- {
- if (*text == '+')
- {
- id = TRUE;
- text++;
- } else if (*text == '-')
- text++;
- }
- if (!ignore_check (word[1], IG_NOTI))
- inbound_notice (serv, word[3], nick, text, ip, id);
- }
- return;
- case WORDL('P','R','I','V'):
- {
- char *to = word[3];
- int len;
- int id = FALSE; /* identified */
- if (*to)
- {
- text = word_eol[4];
- if (*text == ':')
- text++;
- if (serv->have_idmsg)
- {
- if (*text == '+')
- {
- id = TRUE;
- text++;
- } else if (*text == '-')
- text++;
- }
- len = strlen (text);
- if (text[0] == 1 && text[len - 1] == 1) /* ctcp */
- {
- text[len - 1] = 0;
- text++;
- if (strncasecmp (text, "ACTION", 6) != 0)
- flood_check (nick, ip, serv, sess, 0);
- if (strncasecmp (text, "DCC ", 4) == 0)
- /* redo this with handle_quotes TRUE */
- process_data_init (word[1], word_eol[1], word, word_eol, TRUE, FALSE);
- ctcp_handle (sess, to, nick, ip, text, word, word_eol, id);
- } else
- {
- if (is_channel (serv, to))
- {
- if (ignore_check (word[1], IG_CHAN))
- return;
- inbound_chanmsg (serv, NULL, to, nick, text, FALSE, id);
- } else
- {
- if (ignore_check (word[1], IG_PRIV))
- return;
- inbound_privmsg (serv, nick, ip, text, id);
- }
- }
- }
- }
- return;
- case WORDL('T','O','P','I'):
- inbound_topicnew (serv, nick, word[3],
- (word_eol[4][0] == ':') ? word_eol[4] + 1 : word_eol[4]);
- return;
- case WORDL('W','A','L','L'):
- text = word_eol[3];
- if (*text == ':')
- text++;
- EMIT_SIGNAL (XP_TE_WALLOPS, sess, nick, text, NULL, NULL, 0);
- return;
- }
- }
- garbage:
- /* unknown message */
- PrintTextf (sess, "GARBAGE: %s\n", word_eol[1]);
- }
- /* handle named messages that DON'T start with a ':' */
- static void
- process_named_servermsg (session *sess, char *buf, char *rawname, char *word_eol[])
- {
- sess = sess->server->server_session;
- if (!strncmp (buf, "PING ", 5))
- {
- tcp_sendf (sess->server, "PONG %s\r\n", buf + 5);
- return;
- }
- if (!strncmp (buf, "ERROR", 5))
- {
- EMIT_SIGNAL (XP_TE_SERVERERROR, sess, buf + 7, NULL, NULL, NULL, 0);
- return;
- }
- if (!strncmp (buf, "NOTICE ", 7))
- {
- buf = word_eol[3];
- if (*buf == ':')
- buf++;
- EMIT_SIGNAL (XP_TE_SERVNOTICE, sess, buf, sess->server->servername, NULL, NULL, 0);
- return;
- }
- EMIT_SIGNAL (XP_TE_SERVTEXT, sess, buf, sess->server->servername, rawname, NULL, 0);
- }
- /* irc_inline() - 1 single line received from serv */
- static void
- irc_inline (server *serv, char *buf, int len)
- {
- session *sess, *tmp;
- char *type, *text;
- char *word[PDIWORDS+1];
- char *word_eol[PDIWORDS+1];
- char pdibuf_static[522]; /* 1 line can potentially be 512*6 in utf8 */
- char *pdibuf = pdibuf_static;
- url_check_line (buf, len);
- /* need more than 522? fall back to malloc */
- if (len >= sizeof (pdibuf_static))
- pdibuf = malloc (len + 1);
- sess = serv->front_session;
- /* Python relies on this */
- word[PDIWORDS] = NULL;
- word_eol[PDIWORDS] = NULL;
- if (buf[0] == ':')
- {
- /* split line into words and words_to_end_of_line */
- process_data_init (pdibuf, buf, word, word_eol, FALSE, FALSE);
- /* find a context for this message */
- if (is_channel (serv, word[3]))
- {
- tmp = find_channel (serv, word[3]);
- if (tmp)
- sess = tmp;
- }
- /* for server messages, the 2nd word is the "message type" */
- type = word[2];
- word[0] = type;
- word_eol[1] = buf; /* keep the ":" for plugins */
- if (plugin_emit_server (sess, type, word, word_eol))
- goto xit;
- word[1]++;
- word_eol[1] = buf + 1; /* but not for xchat internally */
- } else
- {
- process_data_init (pdibuf, buf, word, word_eol, FALSE, FALSE);
- word[0] = type = word[1];
- if (plugin_emit_server (sess, type, word, word_eol))
- goto xit;
- }
- if (buf[0] != ':')
- {
- process_named_servermsg (sess, buf, word[0], word_eol);
- goto xit;
- }
- /* see if the second word is a numeric */
- if (isdigit ((unsigned char) word[2][0]))
- {
- text = word_eol[4];
- if (*text == ':')
- text++;
- process_numeric (sess, atoi (word[2]), word, word_eol, text);
- } else
- {
- process_named_msg (sess, type, word, word_eol);
- }
- xit:
- if (pdibuf != pdibuf_static)
- free (pdibuf);
- }
- void
- proto_fill_her_up (server *serv)
- {
- serv->p_inline = irc_inline;
- serv->p_invite = irc_invite;
- serv->p_cycle = irc_cycle;
- serv->p_ctcp = irc_ctcp;
- serv->p_nctcp = irc_nctcp;
- serv->p_quit = irc_quit;
- serv->p_kick = irc_kick;
- serv->p_part = irc_part;
- serv->p_ns_identify = irc_ns_identify;
- serv->p_ns_ghost = irc_ns_ghost;
- serv->p_join = irc_join;
- serv->p_join_list = irc_join_list;
- serv->p_login = irc_login;
- serv->p_join_info = irc_join_info;
- serv->p_mode = irc_mode;
- serv->p_user_list = irc_user_list;
- serv->p_away_status = irc_away_status;
- /*serv->p_get_ip = irc_get_ip;*/
- serv->p_whois = irc_user_whois;
- serv->p_get_ip = irc_user_list;
- serv->p_get_ip_uh = irc_userhost;
- serv->p_set_back = irc_set_back;
- serv->p_set_away = irc_set_away;
- serv->p_message = irc_message;
- serv->p_action = irc_action;
- serv->p_notice = irc_notice;
- serv->p_topic = irc_topic;
- serv->p_list_channels = irc_list_channels;
- serv->p_change_nick = irc_change_nick;
- serv->p_names = irc_names;
- serv->p_ping = irc_ping;
- serv->p_raw = irc_raw;
- serv->p_cmp = rfc_casecmp; /* can be changed by 005 in modes.c */
- }