diff options
Diffstat (limited to 'src/common/inbound.c')
-rw-r--r-- | src/common/inbound.c | 1336 |
1 files changed, 1336 insertions, 0 deletions
diff --git a/src/common/inbound.c b/src/common/inbound.c new file mode 100644 index 00000000..ec7dd9d0 --- /dev/null +++ b/src/common/inbound.c @@ -0,0 +1,1336 @@ +/* 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 + */ + +#include <string.h> +#include <ctype.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/types.h> +#include <unistd.h> +#include <time.h> + +#define WANTARPA +#define WANTDNS +#include "inet.h" + +#include "xchat.h" +#include "util.h" +#include "ignore.h" +#include "fe.h" +#include "modes.h" +#include "notify.h" +#include "outbound.h" +#include "inbound.h" +#include "server.h" +#include "servlist.h" +#include "text.h" +#include "ctcp.h" +#include "plugin.h" +#include "xchatc.h" + + +void +clear_channel (session *sess) +{ + if (sess->channel[0]) + strcpy (sess->waitchannel, sess->channel); + sess->channel[0] = 0; + sess->doing_who = FALSE; + sess->done_away_check = FALSE; + + log_close (sess); + + if (sess->current_modes) + { + free (sess->current_modes); + sess->current_modes = NULL; + } + + if (sess->mode_timeout_tag) + { + fe_timeout_remove (sess->mode_timeout_tag); + sess->mode_timeout_tag = 0; + } + + fe_clear_channel (sess); + userlist_clear (sess); + fe_set_nonchannel (sess, FALSE); + fe_set_title (sess); +} + +void +set_topic (session *sess, char *topic, char *stripped_topic) +{ + if (sess->topic) + free (sess->topic); + sess->topic = strdup (stripped_topic); + fe_set_topic (sess, topic, stripped_topic); +} + +static session * +find_session_from_nick (char *nick, server *serv) +{ + session *sess; + GSList *list = sess_list; + + sess = find_dialog (serv, nick); + if (sess) + return sess; + + if (serv->front_session) + { + if (userlist_find (serv->front_session, nick)) + return serv->front_session; + } + + if (current_sess && current_sess->server == serv) + { + if (userlist_find (current_sess, nick)) + return current_sess; + } + + while (list) + { + sess = list->data; + if (sess->server == serv) + { + if (userlist_find (sess, nick)) + return sess; + } + list = list->next; + } + return 0; +} + +static session * +inbound_open_dialog (server *serv, char *from) +{ + session *sess; + + sess = new_ircwindow (serv, from, SESS_DIALOG, 0); + /* for playing sounds */ + EMIT_SIGNAL (XP_TE_OPENDIALOG, sess, NULL, NULL, NULL, NULL, 0); + + return sess; +} + +static void +inbound_make_idtext (server *serv, char *idtext, int max, int id) +{ + idtext[0] = 0; + if (serv->have_idmsg) + { + if (id) + { + safe_strcpy (idtext, prefs.irc_id_ytext, max); + } else + { + safe_strcpy (idtext, prefs.irc_id_ntext, max); + } + /* convert codes like %C,%U to the proper ones */ + check_special_chars (idtext, TRUE); + } +} + +void +inbound_privmsg (server *serv, char *from, char *ip, char *text, int id) +{ + session *sess; + char idtext[64]; + + sess = find_dialog (serv, from); + + if (sess || prefs.autodialog) + { + /*0=ctcp 1=priv will set autodialog=0 here is flud detected */ + if (!sess) + { + if (flood_check (from, ip, serv, current_sess, 1)) + /* Create a dialog session */ + sess = inbound_open_dialog (serv, from); + else + sess = serv->server_session; + if (!sess) + return; /* ?? */ + } + + if (ip && ip[0]) + { + if (prefs.logging && sess->logfd != -1 && + (!sess->topic || strcmp(sess->topic, ip))) + { + char tbuf[1024]; + snprintf (tbuf, sizeof (tbuf), "[%s has address %s]\n", from, ip); + write (sess->logfd, tbuf, strlen (tbuf)); + } + set_topic (sess, ip, ip); + } + inbound_chanmsg (serv, NULL, NULL, from, text, FALSE, id); + return; + } + + inbound_make_idtext (serv, idtext, sizeof (idtext), id); + + sess = find_session_from_nick (from, serv); + if (!sess) + { + sess = serv->front_session; + EMIT_SIGNAL (XP_TE_PRIVMSG, sess, from, text, idtext, NULL, 0); + return; + } + + if (sess->type == SESS_DIALOG) + EMIT_SIGNAL (XP_TE_DPRIVMSG, sess, from, text, idtext, NULL, 0); + else + EMIT_SIGNAL (XP_TE_PRIVMSG, sess, from, text, idtext, NULL, 0); +} + +/* used for Alerts section. Masks can be separated by commas and spaces. */ + +gboolean +alert_match_word (char *word, char *masks) +{ + char *p = masks; + char endchar; + int res; + + if (masks[0] == 0) + return FALSE; + + while (1) + { + /* if it's a 0, space or comma, the word has ended. */ + if (*p == 0 || *p == ' ' || *p == ',') + { + endchar = *p; + *p = 0; + res = match (masks, word); + *p = endchar; + + if (res) + return TRUE; /* yes, matched! */ + + masks = p + 1; + if (*p == 0) + return FALSE; + } + p++; + } +} + +gboolean +alert_match_text (char *text, char *masks) +{ + unsigned char *p = text; + unsigned char endchar; + int res; + + if (masks[0] == 0) + return FALSE; + + while (1) + { + if (*p >= '0' && *p <= '9') + { + p++; + continue; + } + + /* if it's RFC1459 <special>, it can be inside a word */ + switch (*p) + { + case '-': case '[': case ']': case '\\': + case '`': case '^': case '{': case '}': + case '_': case '|': + p++; + continue; + } + + /* if it's a 0, space or comma, the word has ended. */ + if (*p == 0 || *p == ' ' || *p == ',' || + /* if it's anything BUT a letter, the word has ended. */ + (!g_unichar_isalpha (g_utf8_get_char (p)))) + { + endchar = *p; + *p = 0; + res = alert_match_word (text, masks); + *p = endchar; + + if (res) + return TRUE; /* yes, matched! */ + + text = p + g_utf8_skip [p[0]]; + if (*p == 0) + return FALSE; + } + + p += g_utf8_skip [p[0]]; + } +} + +static int +is_hilight (char *from, char *text, session *sess, server *serv) +{ + if (alert_match_word (from, prefs.irc_no_hilight)) + return 0; + + text = strip_color (text, -1, STRIP_ALL); + + if (alert_match_text (text, serv->nick) || + alert_match_text (text, prefs.irc_extra_hilight) || + alert_match_word (from, prefs.irc_nick_hilight)) + { + g_free (text); + if (sess != current_tab) + sess->nick_said = TRUE; + fe_set_hilight (sess); + return 1; + } + + g_free (text); + return 0; +} + +void +inbound_action (session *sess, char *chan, char *from, char *ip, char *text, int fromme, int id) +{ + session *def = sess; + server *serv = sess->server; + struct User *user; + char nickchar[2] = "\000"; + char idtext[64]; + int privaction = FALSE; + + if (!fromme) + { + if (is_channel (serv, chan)) + { + sess = find_channel (serv, chan); + } else + { + /* it's a private action! */ + privaction = TRUE; + /* find a dialog tab for it */ + sess = find_dialog (serv, from); + /* if non found, open a new one */ + if (!sess && prefs.autodialog) + { + /* but only if it wouldn't flood */ + if (flood_check (from, ip, serv, current_sess, 1)) + sess = inbound_open_dialog (serv, from); + else + sess = serv->server_session; + } + if (!sess) + { + sess = find_session_from_nick (from, serv); + /* still not good? */ + if (!sess) + sess = serv->front_session; + } + } + } + + if (!sess) + sess = def; + + if (sess != current_tab) + { + if (fromme) + { + sess->msg_said = FALSE; + sess->new_data = TRUE; + } else + { + sess->msg_said = TRUE; + sess->new_data = FALSE; + } + } + + user = userlist_find (sess, from); + if (user) + { + nickchar[0] = user->prefix[0]; + user->lasttalk = time (0); + } + + inbound_make_idtext (serv, idtext, sizeof (idtext), id); + + if (!fromme && !privaction) + { + if (is_hilight (from, text, sess, serv)) + { + EMIT_SIGNAL (XP_TE_HCHANACTION, sess, from, text, nickchar, idtext, 0); + return; + } + } + + if (fromme) + EMIT_SIGNAL (XP_TE_UACTION, sess, from, text, nickchar, idtext, 0); + else if (!privaction) + EMIT_SIGNAL (XP_TE_CHANACTION, sess, from, text, nickchar, idtext, 0); + else if (sess->type == SESS_DIALOG) + EMIT_SIGNAL (XP_TE_DPRIVACTION, sess, from, text, idtext, NULL, 0); + else + EMIT_SIGNAL (XP_TE_PRIVACTION, sess, from, text, idtext, NULL, 0); +} + +void +inbound_chanmsg (server *serv, session *sess, char *chan, char *from, char *text, char fromme, int id) +{ + struct User *user; + int hilight = FALSE; + char nickchar[2] = "\000"; + char idtext[64]; + + if (!sess) + { + if (chan) + { + sess = find_channel (serv, chan); + if (!sess && !is_channel (serv, chan)) + sess = find_dialog (serv, chan); + } else + { + sess = find_dialog (serv, from); + } + if (!sess) + return; + } + + if (sess != current_tab) + { + sess->msg_said = TRUE; + sess->new_data = FALSE; + } + + user = userlist_find (sess, from); + if (user) + { + nickchar[0] = user->prefix[0]; + user->lasttalk = time (0); + } + + if (fromme) + { + if (prefs.auto_unmark_away && serv->is_away) + sess->server->p_set_back (sess->server); + EMIT_SIGNAL (XP_TE_UCHANMSG, sess, from, text, nickchar, NULL, 0); + return; + } + + inbound_make_idtext (serv, idtext, sizeof (idtext), id); + + if (is_hilight (from, text, sess, serv)) + hilight = TRUE; + + if (sess->type == SESS_DIALOG) + EMIT_SIGNAL (XP_TE_DPRIVMSG, sess, from, text, idtext, NULL, 0); + else if (hilight) + EMIT_SIGNAL (XP_TE_HCHANMSG, sess, from, text, nickchar, idtext, 0); + else + EMIT_SIGNAL (XP_TE_CHANMSG, sess, from, text, nickchar, idtext, 0); +} + +void +inbound_newnick (server *serv, char *nick, char *newnick, int quiet) +{ + int me = FALSE; + session *sess; + GSList *list = sess_list; + + if (!serv->p_cmp (nick, serv->nick)) + { + me = TRUE; + safe_strcpy (serv->nick, newnick, NICKLEN); + } + + while (list) + { + sess = list->data; + if (sess->server == serv) + { + if (userlist_change (sess, nick, newnick) || (me && sess->type == SESS_SERVER)) + { + if (!quiet) + { + if (me) + EMIT_SIGNAL (XP_TE_UCHANGENICK, sess, nick, newnick, NULL, + NULL, 0); + else + EMIT_SIGNAL (XP_TE_CHANGENICK, sess, nick, newnick, NULL, + NULL, 0); + } + } + if (sess->type == SESS_DIALOG && !serv->p_cmp (sess->channel, nick)) + { + safe_strcpy (sess->channel, newnick, CHANLEN); + fe_set_channel (sess); + } + fe_set_title (sess); + } + list = list->next; + } + + dcc_change_nick (serv, nick, newnick); + + if (me) + fe_set_nick (serv, newnick); +} + +/* find a "<none>" tab */ +static session * +find_unused_session (server *serv) +{ + session *sess; + GSList *list = sess_list; + while (list) + { + sess = (session *) list->data; + if (sess->type == SESS_CHANNEL && sess->channel[0] == 0 && + sess->server == serv) + { + if (sess->waitchannel[0] == 0) + return sess; + } + list = list->next; + } + return 0; +} + +static session * +find_session_from_waitchannel (char *chan, struct server *serv) +{ + session *sess; + GSList *list = sess_list; + while (list) + { + sess = (session *) list->data; + if (sess->server == serv && sess->channel[0] == 0 && sess->type == SESS_CHANNEL) + { + if (!serv->p_cmp (chan, sess->waitchannel)) + return sess; + } + list = list->next; + } + return 0; +} + +void +inbound_ujoin (server *serv, char *chan, char *nick, char *ip) +{ + session *sess; + + /* already joined? probably a bnc */ + sess = find_channel (serv, chan); + if (!sess) + { + /* see if a window is waiting to join this channel */ + sess = find_session_from_waitchannel (chan, serv); + if (!sess) + { + /* find a "<none>" tab and use that */ + sess = find_unused_session (serv); + if (!sess) + /* last resort, open a new tab/window */ + sess = new_ircwindow (serv, chan, SESS_CHANNEL, 1); + } + } + + safe_strcpy (sess->channel, chan, CHANLEN); + + fe_set_channel (sess); + fe_set_title (sess); + fe_set_nonchannel (sess, TRUE); + userlist_clear (sess); + + log_open_or_close (sess); + + sess->waitchannel[0] = 0; + sess->ignore_date = TRUE; + sess->ignore_mode = TRUE; + sess->ignore_names = TRUE; + sess->end_of_names = FALSE; + + /* sends a MODE */ + serv->p_join_info (sess->server, chan); + + EMIT_SIGNAL (XP_TE_UJOIN, sess, nick, chan, ip, NULL, 0); + + if (prefs.userhost) + { + /* sends WHO #channel */ + serv->p_user_list (sess->server, chan); + sess->doing_who = TRUE; + } +} + +void +inbound_ukick (server *serv, char *chan, char *kicker, char *reason) +{ + session *sess = find_channel (serv, chan); + if (sess) + { + EMIT_SIGNAL (XP_TE_UKICK, sess, serv->nick, chan, kicker, reason, 0); + clear_channel (sess); + if (prefs.autorejoin) + { + serv->p_join (serv, chan, sess->channelkey); + safe_strcpy (sess->waitchannel, chan, CHANLEN); + } + } +} + +void +inbound_upart (server *serv, char *chan, char *ip, char *reason) +{ + session *sess = find_channel (serv, chan); + if (sess) + { + if (*reason) + EMIT_SIGNAL (XP_TE_UPARTREASON, sess, serv->nick, ip, chan, reason, + 0); + else + EMIT_SIGNAL (XP_TE_UPART, sess, serv->nick, ip, chan, NULL, 0); + clear_channel (sess); + } +} + +void +inbound_nameslist (server *serv, char *chan, char *names) +{ + session *sess; + char name[NICKLEN]; + int pos = 0; + + sess = find_channel (serv, chan); + if (!sess) + { + EMIT_SIGNAL (XP_TE_USERSONCHAN, serv->server_session, chan, names, NULL, + NULL, 0); + return; + } + if (!sess->ignore_names) + EMIT_SIGNAL (XP_TE_USERSONCHAN, sess, chan, names, NULL, NULL, 0); + + if (sess->end_of_names) + { + sess->end_of_names = FALSE; + userlist_clear (sess); + } + + while (1) + { + switch (*names) + { + case 0: + name[pos] = 0; + if (pos != 0) + userlist_add (sess, name, 0); + return; + case ' ': + name[pos] = 0; + pos = 0; + userlist_add (sess, name, 0); + break; + default: + name[pos] = *names; + if (pos < (NICKLEN-1)) + pos++; + } + names++; + } +} + +void +inbound_topic (server *serv, char *chan, char *topic_text) +{ + session *sess = find_channel (serv, chan); + char *stripped_topic; + + if (sess) + { + stripped_topic = strip_color (topic_text, -1, STRIP_ALL); + set_topic (sess, topic_text, stripped_topic); + g_free (stripped_topic); + } else + sess = serv->server_session; + + EMIT_SIGNAL (XP_TE_TOPIC, sess, chan, topic_text, NULL, NULL, 0); +} + +void +inbound_topicnew (server *serv, char *nick, char *chan, char *topic) +{ + session *sess; + char *stripped_topic; + + sess = find_channel (serv, chan); + if (sess) + { + stripped_topic = strip_color (topic, -1, STRIP_ALL); + set_topic (sess, topic, stripped_topic); + g_free (stripped_topic); + EMIT_SIGNAL (XP_TE_NEWTOPIC, sess, nick, topic, chan, NULL, 0); + } +} + +void +inbound_join (server *serv, char *chan, char *user, char *ip) +{ + session *sess = find_channel (serv, chan); + if (sess) + { + EMIT_SIGNAL (XP_TE_JOIN, sess, user, chan, ip, NULL, 0); + userlist_add (sess, user, ip); + } +} + +void +inbound_kick (server *serv, char *chan, char *user, char *kicker, char *reason) +{ + session *sess = find_channel (serv, chan); + if (sess) + { + EMIT_SIGNAL (XP_TE_KICK, sess, kicker, user, chan, reason, 0); + userlist_remove (sess, user); + } +} + +void +inbound_part (server *serv, char *chan, char *user, char *ip, char *reason) +{ + session *sess = find_channel (serv, chan); + if (sess) + { + if (*reason) + EMIT_SIGNAL (XP_TE_PARTREASON, sess, user, ip, chan, reason, 0); + else + EMIT_SIGNAL (XP_TE_PART, sess, user, ip, chan, NULL, 0); + userlist_remove (sess, user); + } +} + +void +inbound_topictime (server *serv, char *chan, char *nick, time_t stamp) +{ + char *tim = ctime (&stamp); + session *sess = find_channel (serv, chan); + + if (!sess) + sess = serv->server_session; + + tim[24] = 0; /* get rid of the \n */ + EMIT_SIGNAL (XP_TE_TOPICDATE, sess, chan, nick, tim, NULL, 0); +} + +void +inbound_quit (server *serv, char *nick, char *ip, char *reason) +{ + GSList *list = sess_list; + session *sess; + int was_on_front_session = FALSE; + + while (list) + { + sess = (session *) list->data; + if (sess->server == serv) + { + if (sess == current_sess) + was_on_front_session = TRUE; + if (userlist_remove (sess, nick)) + { + EMIT_SIGNAL (XP_TE_QUIT, sess, nick, reason, ip, NULL, 0); + } else if (sess->type == SESS_DIALOG && !serv->p_cmp (sess->channel, nick)) + { + EMIT_SIGNAL (XP_TE_QUIT, sess, nick, reason, ip, NULL, 0); + } + } + list = list->next; + } + + notify_set_offline (serv, nick, was_on_front_session); +} + +void +inbound_ping_reply (session *sess, char *timestring, char *from) +{ + unsigned long tim, nowtim, dif; + int lag = 0; + char outbuf[64]; + + if (strncmp (timestring, "LAG", 3) == 0) + { + timestring += 3; + lag = 1; + } + + tim = strtoul (timestring, NULL, 10); + nowtim = make_ping_time (); + dif = nowtim - tim; + + sess->server->ping_recv = time (0); + + if (lag) + { + sess->server->lag_sent = 0; + sess->server->lag = dif / 1000; + fe_set_lag (sess->server, dif / 100000); + return; + } + + if (atol (timestring) == 0) + { + if (sess->server->lag_sent) + sess->server->lag_sent = 0; + else + EMIT_SIGNAL (XP_TE_PINGREP, sess, from, "?", NULL, NULL, 0); + } else + { + snprintf (outbuf, sizeof (outbuf), "%ld.%ld%ld", dif / 1000000, (dif / 100000) % 10, dif % 10); + EMIT_SIGNAL (XP_TE_PINGREP, sess, from, outbuf, NULL, NULL, 0); + } +} + +static session * +find_session_from_type (int type, server *serv) +{ + session *sess; + GSList *list = sess_list; + while (list) + { + sess = list->data; + if (sess->type == type && serv == sess->server) + return sess; + list = list->next; + } + return 0; +} + +void +inbound_notice (server *serv, char *to, char *nick, char *msg, char *ip, int id) +{ + char *po,*ptr=to; + session *sess = 0; + int server_notice = FALSE; + + if (is_channel (serv, ptr)) + sess = find_channel (serv, ptr); + + if (!sess && ptr[0] == '@') + { + ptr++; + sess = find_channel (serv, ptr); + } + + if (!sess && ptr[0] == '%') + { + ptr++; + sess = find_channel (serv, ptr); + } + + if (!sess && ptr[0] == '+') + { + ptr++; + sess = find_channel (serv, ptr); + } + + if (strcmp (nick, ip) == 0) + server_notice = TRUE; + + if (!sess) + { + ptr = 0; + if (prefs.notices_tabs) + { + int stype = server_notice ? SESS_SNOTICES : SESS_NOTICES; + sess = find_session_from_type (stype, serv); + if (!sess) + { + if (stype == SESS_NOTICES) + sess = new_ircwindow (serv, "(notices)", SESS_NOTICES, 0); + else + sess = new_ircwindow (serv, "(snotices)", SESS_SNOTICES, 0); + fe_set_channel (sess); + fe_set_title (sess); + fe_set_nonchannel (sess, FALSE); + userlist_clear (sess); + log_open_or_close (sess); + } + /* Avoid redundancy with some Undernet notices */ + if (!strncmp (msg, "*** Notice -- ", 14)) + msg += 14; + } else + { + /* paranoia check */ + if (msg[0] == '[' && (!serv->have_idmsg || id)) + { + /* guess where chanserv meant to post this -sigh- */ + if (!strcasecmp (nick, "ChanServ") && !find_dialog (serv, nick)) + { + char *dest = strdup (msg + 1); + char *end = strchr (dest, ']'); + if (end) + { + *end = 0; + sess = find_channel (serv, dest); + } + free (dest); + } + } + if (!sess) + sess = find_session_from_nick (nick, serv); + } + if (!sess) + { + if (server_notice) + sess = serv->server_session; + else + sess = serv->front_session; + } + } + + if (msg[0] == 1) + { + msg++; + if (!strncmp (msg, "PING", 4)) + { + inbound_ping_reply (sess, msg + 5, nick); + return; + } + } + po = strchr (msg, '\001'); + if (po) + po[0] = 0; + + if (server_notice) + EMIT_SIGNAL (XP_TE_SERVNOTICE, sess, msg, nick, NULL, NULL, 0); + else if (ptr) + EMIT_SIGNAL (XP_TE_CHANNOTICE, sess, nick, to, msg, NULL, 0); + else + EMIT_SIGNAL (XP_TE_NOTICE, sess, nick, msg, NULL, NULL, 0); +} + +void +inbound_away (server *serv, char *nick, char *msg) +{ + struct away_msg *away = server_away_find_message (serv, nick); + session *sess = NULL; + GSList *list; + + if (away && !strcmp (msg, away->message)) /* Seen the msg before? */ + { + if (prefs.show_away_once && !serv->inside_whois) + return; + } else + { + server_away_save_message (serv, nick, msg); + } + + if (prefs.irc_whois_front) + sess = serv->front_session; + else + { + if (!serv->inside_whois) + sess = find_session_from_nick (nick, serv); + if (!sess) + sess = serv->server_session; + } + + /* possibly hide the output */ + if (!serv->inside_whois || !serv->skip_next_whois) + EMIT_SIGNAL (XP_TE_WHOIS5, sess, nick, msg, NULL, NULL, 0); + + list = sess_list; + while (list) + { + sess = list->data; + if (sess->server == serv) + userlist_set_away (sess, nick, TRUE); + list = list->next; + } +} + +int +inbound_nameslist_end (server *serv, char *chan) +{ + session *sess; + GSList *list; + + if (!strcmp (chan, "*")) + { + list = sess_list; + while (list) + { + sess = list->data; + if (sess->server == serv) + { + sess->end_of_names = TRUE; + sess->ignore_names = FALSE; + } + list = list->next; + } + return TRUE; + } + sess = find_channel (serv, chan); + if (sess) + { + sess->end_of_names = TRUE; + sess->ignore_names = FALSE; + return TRUE; + } + return FALSE; +} + +static gboolean +check_autojoin_channels (server *serv) +{ + char *po; + session *sess; + GSList *list = sess_list; + int i = 0; + GSList *channels, *keys; + + /* shouldnt really happen, the io tag is destroyed in server.c */ + if (!is_server (serv)) + return FALSE; + + /* send auto join list */ + if (serv->autojoin) + { + joinlist_split (serv->autojoin, &channels, &keys); + serv->p_join_list (serv, channels, keys); + joinlist_free (channels, keys); + + free (serv->autojoin); + serv->autojoin = NULL; + } + + /* this is really only for re-connects when you + * join channels not in the auto-join list. */ + while (list) + { + sess = list->data; + if (sess->server == serv) + { + if (sess->willjoinchannel[0] != 0) + { + strcpy (sess->waitchannel, sess->willjoinchannel); + sess->willjoinchannel[0] = 0; + serv->p_join (serv, sess->waitchannel, sess->channelkey); + po = strchr (sess->waitchannel, ','); + if (po) + *po = 0; + po = strchr (sess->waitchannel, ' '); + if (po) + *po = 0; + i++; + } + } + list = list->next; + } + serv->joindelay_tag = 0; + fe_server_event (serv, FE_SE_LOGGEDIN, i); + return FALSE; +} + +void +inbound_next_nick (session *sess, char *nick) +{ + char *newnick; + server *serv = sess->server; + ircnet *net; + + serv->nickcount++; + + switch (serv->nickcount) + { + case 2: + newnick = prefs.nick2; + net = serv->network; + /* use network specific "Second choice"? */ + if (net && !(net->flags & FLAG_USE_GLOBAL) && net->nick2) + newnick = net->nick2; + serv->p_change_nick (serv, newnick); + EMIT_SIGNAL (XP_TE_NICKCLASH, sess, nick, newnick, NULL, NULL, 0); + break; + + case 3: + serv->p_change_nick (serv, prefs.nick3); + EMIT_SIGNAL (XP_TE_NICKCLASH, sess, nick, prefs.nick3, NULL, NULL, 0); + break; + + default: + EMIT_SIGNAL (XP_TE_NICKFAIL, sess, NULL, NULL, NULL, NULL, 0); + } +} + +void +do_dns (session *sess, char *nick, char *host) +{ + char *po; + char tbuf[1024]; + + po = strrchr (host, '@'); + if (po) + host = po + 1; + EMIT_SIGNAL (XP_TE_RESOLVINGUSER, sess, nick, host, NULL, NULL, 0); + snprintf (tbuf, sizeof (tbuf), "exec -d %s %s", prefs.dnsprogram, host); + handle_command (sess, tbuf, FALSE); +} + +static void +set_default_modes (server *serv) +{ + char modes[8]; + + modes[0] = '+'; + modes[1] = '\0'; + + if (prefs.wallops) + strcat (modes, "w"); + if (prefs.servernotice) + strcat (modes, "s"); + if (prefs.invisible) + strcat (modes, "i"); + + if (modes[1] != '\0') + { + serv->p_mode (serv, serv->nick, modes); + } +} + +void +inbound_login_start (session *sess, char *nick, char *servname) +{ + inbound_newnick (sess->server, sess->server->nick, nick, TRUE); + server_set_name (sess->server, servname); + if (sess->type == SESS_SERVER) + log_open_or_close (sess); + /* reset our away status */ + if (sess->server->reconnect_away) + { + handle_command (sess->server->server_session, "away", FALSE); + sess->server->reconnect_away = FALSE; + } +} + +static void +inbound_set_all_away_status (server *serv, char *nick, unsigned int status) +{ + GSList *list; + session *sess; + + list = sess_list; + while (list) + { + sess = list->data; + if (sess->server == serv) + userlist_set_away (sess, nick, status); + list = list->next; + } +} + +void +inbound_uaway (server *serv) +{ + serv->is_away = TRUE; + serv->away_time = time (NULL); + fe_set_away (serv); + + inbound_set_all_away_status (serv, serv->nick, 1); +} + +void +inbound_uback (server *serv) +{ + serv->is_away = FALSE; + serv->reconnect_away = FALSE; + fe_set_away (serv); + + inbound_set_all_away_status (serv, serv->nick, 0); +} + +void +inbound_foundip (session *sess, char *ip) +{ + struct hostent *HostAddr; + + HostAddr = gethostbyname (ip); + if (HostAddr) + { + prefs.dcc_ip = ((struct in_addr *) HostAddr->h_addr)->s_addr; + EMIT_SIGNAL (XP_TE_FOUNDIP, sess, + inet_ntoa (*((struct in_addr *) HostAddr->h_addr)), + NULL, NULL, NULL, 0); + } +} + +void +inbound_user_info_start (session *sess, char *nick) +{ + /* set away to FALSE now, 301 may turn it back on */ + inbound_set_all_away_status (sess->server, nick, 0); +} + +/* reporting new information found about this user. chan may be NULL. + * away may be 0xff to indicate UNKNOWN. */ + +void +inbound_user_info (session *sess, char *chan, char *user, char *host, + char *servname, char *nick, char *realname, + unsigned int away) +{ + server *serv = sess->server; + session *who_sess; + GSList *list; + char *uhost = NULL; + + if (user && host) + { + uhost = g_malloc (strlen (user) + strlen (host) + 2); + sprintf (uhost, "%s@%s", user, host); + } + + if (chan) + { + who_sess = find_channel (serv, chan); + if (who_sess) + userlist_add_hostname (who_sess, nick, uhost, realname, servname, away); + else + { + if (serv->doing_dns && nick && host) + do_dns (sess, nick, host); + } + } + else + { + /* came from WHOIS, not channel specific */ + for (list = sess_list; list; list = list->next) + { + sess = list->data; + if (sess->type == SESS_CHANNEL && sess->server == serv) + { + userlist_add_hostname (sess, nick, uhost, realname, servname, away); + } + } + } + + g_free (uhost); +} + +int +inbound_banlist (session *sess, time_t stamp, char *chan, char *mask, char *banner, int is_exemption) +{ + char *time_str = ctime (&stamp); + server *serv = sess->server; + + time_str[19] = 0; /* get rid of the \n */ + if (stamp == 0) + time_str = ""; + + sess = find_channel (serv, chan); + if (!sess) + { + sess = serv->front_session; + goto nowindow; + } + + if (!fe_is_banwindow (sess)) + { +nowindow: + /* let proto-irc.c do the 'goto def' for exemptions */ + if (is_exemption) + return FALSE; + + EMIT_SIGNAL (XP_TE_BANLIST, sess, chan, mask, banner, time_str, 0); + return TRUE; + } + + fe_add_ban_list (sess, mask, banner, time_str, is_exemption); + return TRUE; +} + +/* execute 1 end-of-motd command */ + +static int +inbound_exec_eom_cmd (char *str, void *sess) +{ + handle_command (sess, (str[0] == '/') ? str + 1 : str, TRUE); + return 1; +} + +void +inbound_login_end (session *sess, char *text) +{ + server *serv = sess->server; + + if (!serv->end_of_motd) + { + if (prefs.ip_from_server && serv->use_who) + { + serv->skip_next_userhost = TRUE; + serv->p_get_ip_uh (serv, serv->nick); /* sends USERHOST mynick */ + } + set_default_modes (serv); + + if (serv->network) + { + /* there may be more than 1, separated by \n */ + if (((ircnet *)serv->network)->command) + token_foreach (((ircnet *)serv->network)->command, '\n', + inbound_exec_eom_cmd, sess); + + /* send nickserv password */ + if (((ircnet *)serv->network)->nickserv) + serv->p_ns_identify (serv, ((ircnet *)serv->network)->nickserv); + } + + /* send JOIN now or wait? */ + if (serv->network && ((ircnet *)serv->network)->nickserv && + prefs.irc_join_delay) + serv->joindelay_tag = fe_timeout_add (prefs.irc_join_delay * 1000, + check_autojoin_channels, serv); + else + check_autojoin_channels (serv); + if (serv->supports_watch) + notify_send_watches (serv); + serv->end_of_motd = TRUE; + } + if (prefs.skipmotd && !serv->motd_skipped) + { + serv->motd_skipped = TRUE; + EMIT_SIGNAL (XP_TE_MOTDSKIP, serv->server_session, NULL, NULL, + NULL, NULL, 0); + return; + } + EMIT_SIGNAL (XP_TE_MOTD, serv->server_session, text, NULL, + NULL, NULL, 0); +} + +void +inbound_identified (server *serv) /* 'MODE +e MYSELF' on freenode */ +{ + if (serv->joindelay_tag) + { + /* stop waiting, just auto JOIN now */ + fe_timeout_remove (serv->joindelay_tag); + serv->joindelay_tag = 0; + check_autojoin_channels (serv); + } +} |