static void process_numeric (session * sess, int n, char *word[], char *word_eol[], char *text, const message_tags_data *tags_data) { server *serv = sess->server; /* show whois is the server tab */ session *whois_sess = serv->server_session; /* unless this setting is on */ if (prefs.hex_irc_whois_front) whois_sess = serv->front_session; switch (n) { case 1: inbound_login_start (sess, word[3], word[1], tags_data); /* 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.hex_dcc_ip_from_server) inbound_foundip (sess, strrchr(word[10], '@')+1, tags_data); } 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, tags_data); 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[4], FE_MSG_ERROR); } goto def; case 301: inbound_away (serv, word[4], (word_eol[5][0] == ':') ? word_eol[5] + 1 : word_eol[5], tags_data); 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, tags_data); } } serv->skip_next_userhost = FALSE; break; } else goto def; case 303: word[4]++; notify_markonline (serv, word, tags_data); break; case 305: inbound_uback (serv, tags_data); goto def; case 306: inbound_uaway (serv, tags_data); goto def; case 312: if (!serv->skip_next_whois) EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS3, whois_sess, word[4], word_eol[5], NULL, NULL, 0, tags_data->timestamp); else inbound_user_info (sess, NULL, NULL, NULL, word[5], word[4], NULL, NULL, 0xff, tags_data); break; case 311: /* WHOIS 1st line */ serv->inside_whois = 1; inbound_user_info_start (sess, word[4], tags_data); if (!serv->skip_next_whois) EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS1, whois_sess, word[4], word[5], word[6], (word_eol[8][0] == ':') ? word_eol[8] + 1 : word_eol[8], 0, tags_data->timestamp); else inbound_user_info (sess, NULL, word[5], word[6], NULL, word[4], word_eol[8][0] == ':' ? word_eol[8] + 1 : word_eol[8], NULL, 0xff, tags_data); break; case 314: /* WHOWAS */ inbound_user_info_start (sess, word[4], tags_data); EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS1, whois_sess, word[4], word[5], word[6], word_eol[8] + 1, 0, tags_data->timestamp); 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]; g_snprintf (outbuf, sizeof (outbuf), "%02ld:%02ld:%02ld", idle / 3600, (idle / 60) % 60, idle % 60); if (timestamp == 0) EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS4, whois_sess, word[4], outbuf, NULL, NULL, 0, tags_data->timestamp); else { tim = ctime (×tamp); tim[19] = 0; /* get rid of the \n */ EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS4T, whois_sess, word[4], outbuf, tim, NULL, 0, tags_data->timestamp); } } break; case 318: /* END OF WHOIS */ if (!serv->skip_next_whois) EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS6, whois_sess, word[4], NULL, NULL, NULL, 0, tags_data->timestamp); serv->skip_next_whois = 0; serv->inside_whois = 0; break; case 313: case 319: if (!serv->skip_next_whois) EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS2, whois_sess, word[4], word_eol[5] + 1, NULL, NULL, 0, tags_data->timestamp); break; case 307: /* dalnet version */ case 320: /* :is an identified user */ if (!serv->skip_next_whois) EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS_ID, whois_sess, word[4], word_eol[5] + 1, NULL, NULL, 0, tags_data->timestamp); break; case 321: if (!fe_is_chanwindow (sess->server)) EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANLISTHEAD, serv->server_session, NULL, NULL, NULL, NULL, 0, tags_data->timestamp); break; case 322: if (fe_is_chanwindow (sess->server)) { fe_add_chan_list (sess->server, word[4], word[5], word_eol[6] + 1); } else { PrintTextTimeStampf (serv->server_session, tags_data->timestamp, "%-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_TIMESTAMP (XP_TE_SERVTEXT, serv->server_session, text, word[1], word[2], NULL, 0, tags_data->timestamp); 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_TIMESTAMP (XP_TE_CHANMODES, sess, word[4], (word_eol[5][0] == ':') ? word_eol[5] + 1 : word_eol[5], NULL, NULL, 0, tags_data->timestamp); fe_update_mode_buttons (sess, 'c', '-'); fe_update_mode_buttons (sess, 't', '-'); fe_update_mode_buttons (sess, 'n', '-'); fe_update_mode_buttons (sess, 'i', '-'); 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, tags_data); break; case 328: /* channel url */ sess = find_channel (serv, word[4]); if (sess) { EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANURL, sess, word[4], (word_eol[5][0] == ':') ? word_eol[5] + 1 : word_eol[5], NULL, NULL, 0, tags_data->timestamp); } 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][0] == ':') ? word[5] + 1 : word[5], tags_data); } break; case 330: if (!serv->skip_next_whois) EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS_AUTH, whois_sess, word[4], word_eol[6] + 1, word[5], NULL, 0, tags_data->timestamp); inbound_user_info (sess, NULL, NULL, NULL, NULL, word[4], NULL, word[5], 0xff, tags_data); break; case 332: inbound_topic (serv, word[4], (word_eol[5][0] == ':') ? word_eol[5] + 1 : word_eol[5], tags_data); break; case 333: inbound_topictime (serv, word[4], word[5], atol (word[6]), tags_data); break; #if 0 case 338: /* Undernet Real user@host, Real IP */ EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS_REALHOST, sess, word[4], word[5], word[6], (word_eol[7][0]==':') ? word_eol[7]+1 : word_eol[7], 0, tags_data->timestamp); break; #endif case 341: /* INVITE ACK */ EMIT_SIGNAL_TIMESTAMP (XP_TE_UINVITE, sess, word[4], word[5], serv->servername, NULL, 0, tags_data->timestamp); 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], NULL, away, tags_data); /* try to show only user initiated whos */ if (!who_sess || !who_sess->doing_who) EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVTEXT, serv->server_session, text, word[1], word[2], NULL, 0, tags_data->timestamp); } break; case 354: /* undernet WHOX: used as a reply for irc_away_status */ { unsigned int away = 0; session *who_sess; /* irc_away_status and irc_user_list sends out a "152" */ if (!strcmp (word[4], "152")) { who_sess = find_channel (serv, word[5]); if (*word[10] == 'G') away = 1; /* :server 354 yournick 152 #channel ~ident host servname nick H account :realname */ inbound_user_info (sess, word[5], word[6], word[7], word[8], word[9], word_eol[12]+1, word[11], away, tags_data); /* try to show only user initiated whos */ if (!who_sess || !who_sess->doing_who) EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVTEXT, serv->server_session, text, word[1], word[2], NULL, 0, tags_data->timestamp); } 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_TIMESTAMP (XP_TE_SERVTEXT, serv->server_session, text, word[1], word[2], NULL, 0, tags_data->timestamp); who_sess->doing_who = FALSE; } else { if (!serv->doing_dns) EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVTEXT, serv->server_session, text, word[1], word[2], NULL, 0, tags_data->timestamp); serv->doing_dns = FALSE; } } break; case 346: /* +I-list entry */ if (!inbound_banlist (sess, atol (word[7]), word[4], word[5], word[6], 346, tags_data)) goto def; break; case 347: /* end of invite list */ if (!fe_ban_list_end (sess, 347)) goto def; break; case 348: /* +e-list entry */ if (!inbound_banlist (sess, atol (word[7]), word[4], word[5], word[6], 348, tags_data)) goto def; break; case 349: /* end of exemption list */ sess = find_channel (serv, word[4]); if (!sess) goto def; if (!fe_ban_list_end (sess, 349)) goto def; break; case 353: /* NAMES */ inbound_nameslist (serv, word[5], (word_eol[6][0] == ':') ? word_eol[6] + 1 : word_eol[6], tags_data); break; case 366: if (!inbound_nameslist_end (serv, word[4], tags_data)) goto def; break; case 367: /* banlist entry */ if (!inbound_banlist (sess, atol (word[7]), word[4], word[5], word[6], 367, tags_data)) goto def; break; case 368: sess = find_channel (serv, word[4]); if (!sess) goto def; if (!fe_ban_list_end (sess, 368)) goto def; break; case 369: /* WHOWAS end */ case 406: /* WHOWAS error */ EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVTEXT, whois_sess, text, word[1], word[2], NULL, 0, tags_data->timestamp); serv->inside_whois = 0; break; case 372: /* motd text */ case 375: /* motd start */ if (!prefs.hex_irc_skip_motd || serv->motd_skipped) EMIT_SIGNAL_TIMESTAMP (XP_TE_MOTD, serv->server_session, text, NULL, NULL, NULL, 0, tags_data->timestamp); break; case 376: /* end of motd */ case 422: /* motd file is missing */ inbound_login_end (sess, text, tags_data); break; case 432: /* erroneous nickname */ if (serv->end_of_motd) { goto def; } inbound_next_nick (sess, word[4], 1, tags_data); break; case 433: /* nickname in use */ if (serv->end_of_motd) { goto def; } inbound_next_nick (sess, word[4], 0, tags_data); break; case 437: if (serv->end_of_motd || is_channel (serv, word[4])) goto def; inbound_next_nick (sess, word[4], 0, tags_data); break; case 471: EMIT_SIGNAL_TIMESTAMP (XP_TE_USERLIMIT, sess, word[4], NULL, NULL, NULL, 0, tags_data->timestamp); break; case 473: EMIT_SIGNAL_TIMESTAMP (XP_TE_INVITE, sess, word[4], NULL, NULL, NULL, 0, tags_data->timestamp); break; case 474: EMIT_SIGNAL_TIMESTAMP (XP_TE_BANNED, sess, word[4], NULL, NULL, NULL, 0, tags_data->timestamp); break; case 475: EMIT_SIGNAL_TIMESTAMP (XP_TE_KEYWORD, sess, word[4], NULL, NULL, NULL, 0, tags_data->timestamp); break; case 601: notify_set_offline (serv, word[4], FALSE, tags_data); break; case 605: notify_set_offline (serv, word[4], TRUE, tags_data); break; case 600: case 604: notify_set_online (serv, word[4], tags_data); break; case 728: /* +q-list entry */ /* NOTE: FREENODE returns these results inconsistent with e.g. +b */ /* Who else has imlemented MODE_QUIET, I wonder? */ if (!inbound_banlist (sess, atol (word[8]), word[4], word[6], word[7], 728, tags_data)) goto def; break; case 729: /* end of quiet list */ if (!fe_ban_list_end (sess, 729)) goto def; break; case 730: /* RPL_MONONLINE */ notify_set_online_list (serv, word[4] + 1, tags_data); break; case 731: /* RPL_MONOFFLINE */ notify_set_offline_list (serv, word[4] + 1, FALSE, tags_data); break; case 900: /* successful SASL 'logged in as ' */ EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVTEXT, serv->server_session, word_eol[6]+1, word[1], word[2], NULL, 0, tags_data->timestamp); break; case 904: /* failed SASL auth */ inbound_sasl_error (serv); case 903: /* successful SASL auth */ case 905: /* failed SASL auth */ case 906: /* aborted */ case 907: /* attempting to re-auth after a successful auth */ EMIT_SIGNAL_TIMESTAMP (XP_TE_SASLRESPONSE, serv->server_session, word[1], word[2], word[3], ++word_eol[4], 0, tags_data->timestamp); if (!serv->sent_capend) { serv->sent_capend = TRUE; tcp_send_len (serv, "CAP END\r\n", 9); } break; case 908: /* Supported SASL Mechs */ /* ignored for now, SASL 3.2 is a better solution and we only do PLAIN atm */ 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_TIMESTAMP (XP_TE_WHOIS_SPECIAL, whois_sess, word[4], (word_eol[5][0] == ':') ? word_eol[5] + 1 : word_eol[5], word[2], NULL, 0, tags_data->timestamp); return; } def: { session *sess; if (is_channel (serv, word[4])) { sess = find_channel (serv, word[4]); if (!sess) sess = serv->server_session; } else if ((sess=find_dialog (serv,word[4]))) /* user with an open dialog */ ; else sess=serv->server_session; EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVTEXT, sess, text, word[1], word[2], NULL, 0, tags_data->timestamp); } } }
void inbound_notice (server *serv, char *to, char *nick, char *msg, char *ip, int id, const message_tags_data *tags_data) { 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.hex_irc_notice_pos == 0) { /* paranoia check */ if (msg[0] == '[' && (!serv->have_idmsg || id)) { /* guess where chanserv meant to post this -sigh- */ if (!g_ascii_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); } else if (prefs.hex_irc_notice_pos == 1) { 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 { sess = serv->front_session; } 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, tags_data); return; } } po = strchr (msg, '\001'); if (po) po[0] = 0; if (server_notice) EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVNOTICE, sess, msg, nick, NULL, NULL, 0, tags_data->timestamp); else if (ptr) EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANNOTICE, sess, nick, to, msg, NULL, 0, tags_data->timestamp); else EMIT_SIGNAL_TIMESTAMP (XP_TE_NOTICE, sess, nick, msg, NULL, NULL, 0, tags_data->timestamp); }
static void process_named_msg (session *sess, char *type, char *word[], char *word_eol[], const message_tags_data *tags_data) { 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]; char *account = word[4]; char *realname = word_eol[5]; if (account && strcmp (account, "*") == 0) account = NULL; if (realname && *realname == ':') realname++; if (*chan == ':') chan++; if (!serv->p_cmp (nick, serv->nick)) inbound_ujoin (serv, chan, nick, ip, tags_data); else inbound_join (serv, chan, nick, ip, account, realname, tags_data); } 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, tags_data); else inbound_kick (serv, word[3], kicked, nick, reason, tags_data); } } return; case WORDL('K','I','L','L'): { char *reason = word_eol[4]; if (*reason == ':') reason++; EMIT_SIGNAL_TIMESTAMP (XP_TE_KILL, sess, nick, reason, NULL, NULL, 0, tags_data->timestamp); } return; case WORDL('M','O','D','E'): handle_mode (serv, word, word_eol, nick, FALSE, tags_data); /* 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, tags_data); 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, tags_data); else inbound_part (serv, chan, nick, ip, reason, tags_data); } return; case WORDL('P', 'I', 'N', 'G'): tcp_sendf (sess->server, "PONG %s\r\n", word_eol[3]); return; case WORDL('P','O','N','G'): inbound_ping_reply (serv->server_session, (word[4][0] == ':') ? word[4] + 1 : word[4], word[3], tags_data); return; case WORDL('Q','U','I','T'): inbound_quit (serv, nick, ip, (word_eol[3][0] == ':') ? word_eol[3] + 1 : word_eol[3], tags_data); return; case WORDL('A','W','A','Y'): inbound_away_notify (serv, nick, (word_eol[3][0] == ':') ? word_eol[3] + 1 : NULL, tags_data); 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('A','C','C','O'): inbound_account (serv, nick, word[3], tags_data); return; case WORDL('A', 'U', 'T', 'H'): inbound_sasl_authenticate (sess->server, word_eol[3]); return; case WORDL('C', 'H', 'G', 'H'): inbound_user_info (sess, NULL, word[3], word[4], NULL, nick, NULL, NULL, 0xff, tags_data); return; case WORDL('I','N','V','I'): if (ignore_check (word[1], IG_INVI)) return; if (word[4][0] == ':') EMIT_SIGNAL_TIMESTAMP (XP_TE_INVITED, sess, word[4] + 1, nick, serv->servername, NULL, 0, tags_data->timestamp); else EMIT_SIGNAL_TIMESTAMP (XP_TE_INVITED, sess, word[4], nick, serv->servername, NULL, 0, tags_data->timestamp); return; case WORDL('N','O','T','I'): { int id = FALSE; /* identified */ text = word_eol[4]; if (*text == ':') { text++; } #ifdef USE_OPENSSL /* QuakeNet CHALLENGE upon our request */ if (serv->loginmethod == LOGIN_CHALLENGEAUTH && !serv->p_cmp (word[1], CHALLENGEAUTH_FULLHOST) && !strncmp (text, "CHALLENGE ", 10) && *serv->password) { char *response; ircnet *net = serv->network; char *user = net && net->user ? net->user : prefs.hex_irc_user_name; response = challengeauth_response (user, serv->password, word[5]); tcp_sendf (serv, "PRIVMSG %s :CHALLENGEAUTH %s %s %s\r\n", CHALLENGEAUTH_NICK, user, response, CHALLENGEAUTH_ALGO); g_free (response); return; /* omit the CHALLENGE <hash> ALGOS message */ } #endif 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, tags_data); } return; case WORDL('P','R','I','V'): { char *to = word[3]; int len; int id = FALSE; /* identified */ if (*to) { /* Handle limited channel messages, for now no special event */ if (strchr (serv->chantypes, to[0]) == NULL && strchr (serv->nick_prefixes, to[0]) != NULL) 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 (g_ascii_strncasecmp (text, "ACTION", 6) != 0) flood_check (nick, ip, serv, sess, 0); if (g_ascii_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, tags_data); } else { if (is_channel (serv, to)) { if (ignore_check (word[1], IG_CHAN)) return; inbound_chanmsg (serv, NULL, to, nick, text, FALSE, id, tags_data); } else { if (ignore_check (word[1], IG_PRIV)) return; inbound_privmsg (serv, nick, ip, text, id, tags_data); } } } } return; case WORDL('T','O','P','I'): inbound_topicnew (serv, nick, word[3], (word_eol[4][0] == ':') ? word_eol[4] + 1 : word_eol[4], tags_data); return; case WORDL('W','A','L','L'): text = word_eol[3]; if (*text == ':') text++; EMIT_SIGNAL_TIMESTAMP (XP_TE_WALLOPS, sess, nick, text, NULL, NULL, 0, tags_data->timestamp); return; } } else if (len == 3) { guint32 t; t = WORDL((guint8)type[0], (guint8)type[1], (guint8)type[2], (guint8)type[3]); switch (t) { case WORDL('C','A','P','\0'): if (strncasecmp (word[4], "ACK", 3) == 0) { inbound_cap_ack (serv, word[1], word[5][0] == ':' ? word_eol[5] + 1 : word_eol[5], tags_data); } else if (strncasecmp (word[4], "LS", 2) == 0 || strncasecmp (word[4], "NEW", 3) == 0) { inbound_cap_ls (serv, word[1], word[5][0] == ':' ? word_eol[5] + 1 : word_eol[5], tags_data); } else if (strncasecmp (word[4], "NAK", 3) == 0) { inbound_cap_nak (serv, tags_data); } else if (strncasecmp (word[4], "LIST", 4) == 0) { inbound_cap_list (serv, word[1], word[5][0] == ':' ? word_eol[5] + 1 : word_eol[5], tags_data); } else if (strncasecmp (word[4], "DEL", 3) == 0) { inbound_cap_del (serv, word[1], word[5][0] == ':' ? word_eol[5] + 1 : word_eol[5], tags_data); } return; } } garbage: /* unknown message */ PrintTextTimeStampf (sess, tags_data->timestamp, "GARBAGE: %s\n", word_eol[1]); }
void inbound_action (session *sess, char *chan, char *from, char *ip, char *text, int fromme, int id, const message_tags_data *tags_data) { 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.hex_gui_autoopen_dialog) { /* but only if it wouldn't flood */ if (flood_check (from, ip, serv, current_sess, 1)) sess = inbound_open_dialog (serv, from, tags_data); 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; } lastact_update (sess); } user = userlist_find (sess, from); if (user) { nickchar[0] = user->prefix[0]; user->lasttalk = time (0); if (user->account) id = TRUE; } inbound_make_idtext (serv, idtext, sizeof (idtext), id); if (!fromme && !privaction) { if (is_hilight (from, text, sess, serv)) { EMIT_SIGNAL_TIMESTAMP (XP_TE_HCHANACTION, sess, from, text, nickchar, idtext, 0, tags_data->timestamp); return; } } if (fromme) EMIT_SIGNAL_TIMESTAMP (XP_TE_UACTION, sess, from, text, nickchar, idtext, 0, tags_data->timestamp); else if (!privaction) EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANACTION, sess, from, text, nickchar, idtext, 0, tags_data->timestamp); else if (sess->type == SESS_DIALOG) EMIT_SIGNAL_TIMESTAMP (XP_TE_DPRIVACTION, sess, from, text, idtext, NULL, 0, tags_data->timestamp); else EMIT_SIGNAL_TIMESTAMP (XP_TE_PRIVACTION, sess, from, text, idtext, NULL, 0, tags_data->timestamp); }
void inbound_chanmsg (server *serv, session *sess, char *chan, char *from, char *text, char fromme, int id, const message_tags_data *tags_data) { 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; lastact_update (sess); } user = userlist_find (sess, from); if (user) { if (user->account) id = TRUE; nickchar[0] = user->prefix[0]; user->lasttalk = time (0); } if (fromme) { if (prefs.hex_away_auto_unmark && serv->is_away) sess->server->p_set_back (sess->server); EMIT_SIGNAL_TIMESTAMP (XP_TE_UCHANMSG, sess, from, text, nickchar, NULL, 0, tags_data->timestamp); 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_TIMESTAMP (XP_TE_DPRIVMSG, sess, from, text, idtext, NULL, 0, tags_data->timestamp); else if (hilight) EMIT_SIGNAL_TIMESTAMP (XP_TE_HCHANMSG, sess, from, text, nickchar, idtext, 0, tags_data->timestamp); else EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANMSG, sess, from, text, nickchar, idtext, 0, tags_data->timestamp); }
void inbound_privmsg (server *serv, char *from, char *ip, char *text, int id, const message_tags_data *tags_data) { session *sess; struct User *user; char idtext[64]; gboolean nodiag = FALSE; sess = find_dialog (serv, from); if (sess || prefs.hex_gui_autoopen_dialog) { /*0=ctcp 1=priv will set hex_gui_autoopen_dialog=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, tags_data); else sess = serv->server_session; if (!sess) return; /* ?? */ } if (ip && ip[0]) { if (prefs.hex_irc_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, tags_data); return; } sess = find_session_from_nick (from, serv); if (!sess) { sess = serv->front_session; nodiag = TRUE; /* We don't want it to look like a normal message in front sess */ } user = userlist_find (sess, from); if (user) { user->lasttalk = time (0); if (user->account) id = TRUE; } inbound_make_idtext (serv, idtext, sizeof (idtext), id); if (sess->type == SESS_DIALOG && !nodiag) EMIT_SIGNAL_TIMESTAMP (XP_TE_DPRIVMSG, sess, from, text, idtext, NULL, 0, tags_data->timestamp); else EMIT_SIGNAL_TIMESTAMP (XP_TE_PRIVMSG, sess, from, text, idtext, NULL, 0, tags_data->timestamp); }
void inbound_cap_ls (server *serv, char *nick, char *extensions_str, const message_tags_data *tags_data) { char buffer[256]; /* buffer for requesting capabilities and emitting the signal */ guint32 want_cap; /* format the CAP REQ string based on previous capabilities being requested or not */ guint32 want_sasl; /* CAP END shouldn't be sent when SASL is requested, it needs further responses */ char **extensions; int i; EMIT_SIGNAL_TIMESTAMP (XP_TE_CAPLIST, serv->server_session, nick, extensions_str, NULL, NULL, 0, tags_data->timestamp); want_cap = 0; want_sasl = 0; extensions = g_strsplit (extensions_str, " ", 0); strcpy (buffer, "CAP REQ :"); for (i=0; extensions[i]; i++) { const char *extension = extensions[i]; if (!strcmp (extension, "identify-msg")) { strcat (buffer, "identify-msg "); want_cap = 1; } if (!strcmp (extension, "multi-prefix")) { strcat (buffer, "multi-prefix "); want_cap = 1; } if (!strcmp (extension, "away-notify")) { strcat (buffer, "away-notify "); want_cap = 1; } if (!strcmp (extension, "account-notify")) { strcat (buffer, "account-notify "); want_cap = 1; } if (!strcmp (extension, "extended-join")) { strcat (buffer, "extended-join "); want_cap = 1; } /* bouncers can prefix a name space to the extension so we should use. * znc <= 1.0 uses "znc.in/server-time" and newer use "znc.in/server-time-iso". */ if (!strcmp (extension, "znc.in/server-time-iso")) { strcat (buffer, "znc.in/server-time-iso "); } if (!strcmp (extension, "znc.in/server-time")) { strcat (buffer, "znc.in/server-time "); } if (prefs.hex_irc_cap_server_time && !strcmp (extension, "server-time")) { strcat (buffer, "server-time "); } /* if the SASL password is set AND auth mode is set to SASL, request SASL auth */ if (serv->loginmethod == LOGIN_SASL && strcmp (extension, "sasl") != 0 && strlen (serv->password) != 0) { strcat (buffer, "sasl "); want_cap = 1; want_sasl = 1; } } g_strfreev (extensions); if (want_cap) { /* buffer + 9 = emit buffer without "CAP REQ :" */ EMIT_SIGNAL_TIMESTAMP (XP_TE_CAPREQ, serv->server_session, buffer + 9, NULL, NULL, NULL, 0, tags_data->timestamp); tcp_sendf (serv, "%s\r\n", buffer); } if (!want_sasl) { /* if we use SASL, CAP END is dealt via raw numerics */ tcp_send_len (serv, "CAP END\r\n", 9); } }
void inbound_login_end (session *sess, char *text, const message_tags_data *tags_data) { GSList *cmdlist; commandentry *cmd; server *serv = sess->server; if (!serv->end_of_motd) { if (prefs.hex_dcc_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 */ cmdlist = ((ircnet *)serv->network)->commandlist; while (cmdlist) { cmd = cmdlist->data; inbound_exec_eom_cmd (cmd->command, sess); cmdlist = cmdlist->next; } /* send nickserv password */ if (((ircnet *)serv->network)->pass && inbound_nickserv_login (serv)) { serv->p_ns_identify (serv, ((ircnet *)serv->network)->pass); } } /* wait for join if command or nickserv set */ if (serv->network && prefs.hex_irc_join_delay && ((((ircnet *)serv->network)->pass && inbound_nickserv_login (serv)) || ((ircnet *)serv->network)->commandlist)) { serv->joindelay_tag = fe_timeout_add (prefs.hex_irc_join_delay * 1000, check_autojoin_channels, serv); } else { check_autojoin_channels (serv); } if (serv->supports_watch || serv->supports_monitor) { notify_send_watches (serv); } serv->end_of_motd = TRUE; } if (prefs.hex_irc_skip_motd && !serv->motd_skipped) { serv->motd_skipped = TRUE; EMIT_SIGNAL_TIMESTAMP (XP_TE_MOTDSKIP, serv->server_session, NULL, NULL, NULL, NULL, 0, tags_data->timestamp); return; } EMIT_SIGNAL_TIMESTAMP (XP_TE_MOTD, serv->server_session, text, NULL, NULL, NULL, 0, tags_data->timestamp); }
void inbound_cap_ls (server *serv, char *nick, char *extensions_str, const message_tags_data *tags_data) { char buffer[500]; /* buffer for requesting capabilities and emitting the signal */ gboolean want_cap = FALSE; /* format the CAP REQ string based on previous capabilities being requested or not */ gboolean want_sasl = FALSE; /* CAP END shouldn't be sent when SASL is requested, it needs further responses */ char **extensions; int i; if (g_str_has_prefix (extensions_str, "* ")) { serv->waiting_on_cap = TRUE; extensions_str += 2; extensions_str += extensions_str[0] == ':' ? 1 : 0; } else { serv->waiting_on_cap = FALSE; } EMIT_SIGNAL_TIMESTAMP (XP_TE_CAPLIST, serv->server_session, nick, extensions_str, NULL, NULL, 0, tags_data->timestamp); extensions = g_strsplit (extensions_str, " ", 0); strcpy (buffer, "CAP REQ :"); for (i=0; extensions[i]; i++) { char *extension = extensions[i]; char *value; gsize x; /* CAP 3.2 can provide values */ if ((value = strchr (extension, '='))) { *value = '\0'; value++; } /* if the SASL password is set AND auth mode is set to SASL, request SASL auth */ if (!g_strcmp0 (extension, "sasl") && ((serv->loginmethod == LOGIN_SASL && strlen (serv->password) != 0) || (serv->loginmethod == LOGIN_SASLEXTERNAL && serv->have_cert))) { if (value) { int sasl_mech = get_supported_mech (serv, value); if (sasl_mech == -1) /* No supported mech */ continue; serv->sasl_mech = sasl_mech; } want_cap = TRUE; want_sasl = TRUE; g_strlcat (buffer, "sasl ", sizeof(buffer)); continue; } for (x = 0; x < G_N_ELEMENTS(supported_caps); ++x) { if (!g_strcmp0 (extension, supported_caps[x])) { g_strlcat (buffer, extension, sizeof(buffer)); g_strlcat (buffer, " ", sizeof(buffer)); want_cap = TRUE; } } } g_strfreev (extensions); if (want_cap) { /* buffer + 9 = emit buffer without "CAP REQ :" */ EMIT_SIGNAL_TIMESTAMP (XP_TE_CAPREQ, serv->server_session, buffer + 9, NULL, NULL, NULL, 0, tags_data->timestamp); tcp_sendf (serv, "%s\r\n", g_strchomp (buffer)); } if (!want_sasl && !serv->waiting_on_cap) { /* if we use SASL, CAP END is dealt via raw numerics */ serv->sent_capend = TRUE; tcp_send_len (serv, "CAP END\r\n", 9); } }
void ctcp_handle (session *sess, char *to, char *nick, char *ip, char *msg, char *word[], char *word_eol[], int id, const message_tags_data *tags_data) { char *po; session *chansess; server *serv = sess->server; char outbuf[1024]; int ctcp_offset = 2; if (serv->have_idmsg && (word[4][1] == '+' || word[4][1] == '-') ) ctcp_offset = 3; /* consider DCC to be different from other CTCPs */ if (!g_ascii_strncasecmp (msg, "DCC", 3)) { /* but still let CTCP replies override it */ if (!ctcp_check (sess, nick, word, word_eol, word[4] + ctcp_offset)) { if (!ignore_check (word[1], IG_DCC)) handle_dcc (sess, nick, word, word_eol, tags_data); } return; } /* consider ACTION to be different from other CTCPs. Check ignore as if it was a PRIV/CHAN. */ if (!g_ascii_strncasecmp (msg, "ACTION ", 7)) { if (is_channel (serv, to)) { /* treat a channel action as a CHAN */ if (ignore_check (word[1], IG_CHAN)) return; } else { /* treat a private action as a PRIV */ if (ignore_check (word[1], IG_PRIV)) return; } /* but still let CTCP replies override it */ if (ctcp_check (sess, nick, word, word_eol, word[4] + ctcp_offset)) goto generic; inbound_action (sess, to, nick, ip, msg + 7, FALSE, id, tags_data); return; } if (ignore_check (word[1], IG_CTCP)) return; if (!g_ascii_strcasecmp (msg, "VERSION") && !prefs.hex_irc_hide_version) { #ifdef WIN32 g_snprintf (outbuf, sizeof (outbuf), "VERSION HexChat "PACKAGE_VERSION" [x%d] / %s", get_cpu_arch (), get_sys_str (1)); #else g_snprintf (outbuf, sizeof (outbuf), "VERSION HexChat "PACKAGE_VERSION" / %s", get_sys_str (1)); #endif serv->p_nctcp (serv, nick, outbuf); } if (word[4][1] == '\0') return; if (!ctcp_check (sess, nick, word, word_eol, word[4] + ctcp_offset)) { if (!g_ascii_strncasecmp (msg, "SOUND", 5)) { po = strchr (word[5], '\001'); if (po) po[0] = 0; if (is_channel (sess->server, to)) { chansess = find_channel (sess->server, to); if (!chansess) chansess = sess; EMIT_SIGNAL_TIMESTAMP (XP_TE_CTCPSNDC, chansess, word[5], nick, to, NULL, 0, tags_data->timestamp); } else { EMIT_SIGNAL_TIMESTAMP (XP_TE_CTCPSND, sess->server->front_session, word[5], nick, NULL, NULL, 0, tags_data->timestamp); } /* don't let IRCers specify path */ #ifdef WIN32 if (strchr (word[5], '/') == NULL && strchr (word[5], '\\') == NULL) #else if (strchr (word[5], '/') == NULL) #endif sound_play (word[5], TRUE); return; } } generic: po = strchr (msg, '\001'); if (po) po[0] = 0; if (!is_channel (sess->server, to)) { EMIT_SIGNAL_TIMESTAMP (XP_TE_CTCPGEN, sess->server->front_session, msg, nick, NULL, NULL, 0, tags_data->timestamp); } else { chansess = find_channel (sess->server, to); if (!chansess) chansess = sess; EMIT_SIGNAL_TIMESTAMP (XP_TE_CTCPGENC, chansess, msg, nick, to, NULL, 0, tags_data->timestamp); } }
void handle_mode (server * serv, char *word[], char *word_eol[], char *nick, int numeric_324, const message_tags_data *tags_data) { session *sess; char *chan; char *modes; char *argstr; char sign; int len; size_t arg; size_t i, num_args; int num_modes; size_t offset = 3; int all_modes_have_args = FALSE; int using_front_tab = FALSE; mode_run mr; mr.serv = serv; mr.op = mr.deop = mr.voice = mr.devoice = NULL; /* numeric 324 has everything 1 word later (as opposed to MODE) */ if (numeric_324) offset++; chan = word[offset]; modes = word[offset + 1]; if (*modes == ':') modes++; if (*modes == 0) return; /* beyondirc's blank modes */ sess = find_channel (serv, chan); if (!sess) { sess = serv->front_session; using_front_tab = TRUE; } /* remove trailing space */ len = strlen (word_eol[offset]) - 1; if (word_eol[offset][len] == ' ') word_eol[offset][len] = 0; if (prefs.hex_irc_raw_modes && !numeric_324) EMIT_SIGNAL_TIMESTAMP (XP_TE_RAWMODES, sess, nick, word_eol[offset], 0, 0, 0, tags_data->timestamp); if (numeric_324 && !using_front_tab) { if (sess->current_modes) free (sess->current_modes); sess->current_modes = strdup (word_eol[offset+1]); } sign = *modes; modes++; arg = 1; /* count the number of arguments (e.g. after the -o+v) */ num_args = 0; i = 1; while ((i + offset + 1) < PDIWORDS) { i++; if (!(*word[i + offset])) break; num_args++; } /* count the number of modes (without the -/+ chars */ num_modes = 0; i = 0; while (i < strlen (modes)) { if (modes[i] != '+' && modes[i] != '-') num_modes++; i++; } if (num_args == num_modes) all_modes_have_args = TRUE; while (*modes) { switch (*modes) { case '-': case '+': /* print all the grouped Op/Deops */ mode_print_grouped (sess, nick, &mr, tags_data); sign = *modes; break; default: argstr = ""; if ((all_modes_have_args || mode_has_arg (serv, sign, *modes)) && arg < (num_args + 1)) { arg++; argstr = word[arg + offset]; } handle_single_mode (&mr, sign, *modes, nick, chan, argstr, numeric_324 || prefs.hex_irc_raw_modes, numeric_324, tags_data); } modes++; } /* update the title at the end, now that the mode update is internal now */ if (!using_front_tab) fe_set_title (sess); /* print all the grouped Op/Deops */ mode_print_grouped (sess, nick, &mr, tags_data); }
static void handle_single_mode (mode_run *mr, char sign, char mode, char *nick, char *chan, char *arg, int quiet, int is_324, const message_tags_data *tags_data) { session *sess; server *serv = mr->serv; char outbuf[4]; char *cm = serv->chanmodes; gboolean supportsq = FALSE; outbuf[0] = sign; outbuf[1] = 0; outbuf[2] = mode; outbuf[3] = 0; sess = find_channel (serv, chan); if (!sess || !is_channel (serv, chan)) { /* got modes for a chan we're not in! probably nickmode +isw etc */ sess = serv->front_session; goto genmode; } /* is this a nick mode? */ if (strchr (serv->nick_modes, mode)) { /* update the user in the userlist */ userlist_update_mode (sess, /*nickname */ arg, mode, sign); } else { if (!is_324 && !sess->ignore_mode && mode_chanmode_type(serv, mode) >= 1) record_chan_mode (sess, sign, mode, arg); } /* Is q a chanmode on this server? */ if (cm) while (*cm) { if (*cm == ',') break; if (*cm == 'q') supportsq = TRUE; cm++; } switch (sign) { case '+': switch (mode) { case 'k': safe_strcpy (sess->channelkey, arg, sizeof (sess->channelkey)); fe_update_channel_key (sess); fe_update_mode_buttons (sess, mode, sign); if (!quiet) EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANSETKEY, sess, nick, arg, NULL, NULL, 0, tags_data->timestamp); return; case 'l': sess->limit = atoi (arg); fe_update_channel_limit (sess); fe_update_mode_buttons (sess, mode, sign); if (!quiet) EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANSETLIMIT, sess, nick, arg, NULL, NULL, 0, tags_data->timestamp); return; case 'o': if (!quiet) mr->op = mode_cat (mr->op, arg); return; case 'h': if (!quiet) EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANHOP, sess, nick, arg, NULL, NULL, 0, tags_data->timestamp); return; case 'v': if (!quiet) mr->voice = mode_cat (mr->voice, arg); return; case 'b': if (!quiet) EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANBAN, sess, nick, arg, NULL, NULL, 0, tags_data->timestamp); return; case 'e': if (!quiet) EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANEXEMPT, sess, nick, arg, NULL, NULL, 0, tags_data->timestamp); return; case 'I': if (!quiet) EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANINVITE, sess, nick, arg, NULL, NULL, 0, tags_data->timestamp); return; case 'q': if (!supportsq) break; /* +q is owner on this server */ if (!quiet) EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANQUIET, sess, nick, arg, NULL, NULL, 0, tags_data->timestamp); return; } break; case '-': switch (mode) { case 'k': sess->channelkey[0] = 0; fe_update_channel_key (sess); fe_update_mode_buttons (sess, mode, sign); if (!quiet) EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANRMKEY, sess, nick, NULL, NULL, NULL, 0, tags_data->timestamp); return; case 'l': sess->limit = 0; fe_update_channel_limit (sess); fe_update_mode_buttons (sess, mode, sign); if (!quiet) EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANRMLIMIT, sess, nick, NULL, NULL, NULL, 0, tags_data->timestamp); return; case 'o': if (!quiet) mr->deop = mode_cat (mr->deop, arg); return; case 'h': if (!quiet) EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANDEHOP, sess, nick, arg, NULL, NULL, 0, tags_data->timestamp); return; case 'v': if (!quiet) mr->devoice = mode_cat (mr->devoice, arg); return; case 'b': if (!quiet) EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANUNBAN, sess, nick, arg, NULL, NULL, 0, tags_data->timestamp); return; case 'e': if (!quiet) EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANRMEXEMPT, sess, nick, arg, NULL, NULL, 0, tags_data->timestamp); return; case 'I': if (!quiet) EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANRMINVITE, sess, nick, arg, NULL, NULL, 0, tags_data->timestamp); return; case 'q': if (!supportsq) break; /* -q is owner on this server */ if (!quiet) EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANUNQUIET, sess, nick, arg, NULL, NULL, 0, tags_data->timestamp); return; } } fe_update_mode_buttons (sess, mode, sign); genmode: /* Received umode +e. If we're waiting to send JOIN then send now! */ if (mode == 'e' && sign == '+' && !serv->p_cmp (chan, serv->nick)) inbound_identified (serv); if (!quiet) { if (*arg) { char *buf = malloc (strlen (chan) + strlen (arg) + 2); sprintf (buf, "%s %s", chan, arg); EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANMODEGEN, sess, nick, outbuf, outbuf + 2, buf, 0, tags_data->timestamp); free (buf); } else EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANMODEGEN, sess, nick, outbuf, outbuf + 2, chan, 0, tags_data->timestamp); } }