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; } } 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) { if (strncasecmp(word[5][0]==':' ? word[5]+1 : word[5], "identify-msg", 12) == 0) { serv->have_idmsg = TRUE; tcp_send_len(serv, "CAP END\r\n", 9); } } else if (strncasecmp(word[4], "LS", 2) == 0) { if (strstr(word_eol[5], "identify-msg") != 0) tcp_send_len(serv, "CAP REQ :identify-msg\r\n", 23); else tcp_send_len(serv, "CAP END\r\n", 9); } else if (strncasecmp(word[4], "NAK",3) == 0) { tcp_send_len(serv, "CAP END\r\n", 9); } return; } } garbage: /* unknown message */ PrintTextf (sess, "GARBAGE: %s\n", word_eol[1]); }
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; /* 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); }
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','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('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 if (!strncmp (text, "CHALLENGE ", 10)) /* QuakeNet CHALLENGE upon our request */ { char *response = challengeauth_response (((ircnet *)serv->network)->user ? ((ircnet *)serv->network)->user : prefs.hex_irc_user_name, serv->password, word[5]); tcp_sendf (serv, "PRIVMSG %s :CHALLENGEAUTH %s %s %s\r\n", CHALLENGEAUTH_NICK, ((ircnet *)serv->network)->user ? ((ircnet *)serv->network)->user : prefs.hex_irc_user_name, 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) { 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); } return; } } garbage: /* unknown message */ PrintTextTimeStampf (sess, tags_data->timestamp, "GARBAGE: %s\n", word_eol[1]); }
/* irc_inline() - 1 single line received from serv */ void server::p_inline (const boost::string_ref& text) { session *sess; char *type; char *word[PDIWORDS+1]; char *word_eol[PDIWORDS+1]; message_tags_data tags_data = message_tags_data(); std::string pdibuf(text.size(), '\0'); sess = this->front_session; /* Python relies on this */ word[PDIWORDS] = NULL; word_eol[PDIWORDS] = NULL; std::string buf; if (text.starts_with('@')) { auto sep = text.find_first_of(' '); if (sep == boost::string_ref::npos) return; /* skip the '@' */ auto tags = text.substr(1, sep - 1); buf = text.substr(sep + 1).to_string(); handle_message_tags(*this, tags, tags_data); } else { buf = text.to_string(); } url_check_line(buf.data(), buf.size()); /* split line into words and words_to_end_of_line */ process_data_init (&pdibuf[0], &buf[0], word, word_eol, false, false); if (buf[0] == ':') { /* find a context for this message */ if (this->is_channel_name (word[3])) { auto tmp = find_channel (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[0]; /* keep the ":" for plugins */ if (plugin_emit_server(sess, type, word, word_eol, tags_data.timestamp)) { return; } word[1]++; word_eol[1] = &buf[1]; /* but not for HexChat internally */ } else { word[0] = type = word[1]; if (plugin_emit_server(sess, type, word, word_eol, tags_data.timestamp)) { return; } } if (buf[0] != ':') { process_named_servermsg (sess, &buf[0], word[0], word_eol, &tags_data); return; } /* see if the second word is a numeric */ std::locale locale; if (std::isdigit (word[2][0], locale)) { char* t = word_eol[4]; if (*t == ':') t++; process_numeric (sess, atoi (word[2]), word, word_eol, t, &tags_data); } else { process_named_msg (sess, type, word, word_eol, &tags_data); } }
/* 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; message_tags_data tags_data = MESSAGE_TAGS_DATA_INIT; pdibuf = g_malloc (len + 1); sess = serv->front_session; /* Python relies on this */ word[PDIWORDS] = NULL; word_eol[PDIWORDS] = NULL; if (*buf == '@') { char *tags = buf + 1; /* skip the '@' */ char *sep = strchr (buf, ' '); if (!sep) goto xit; *sep = '\0'; buf = sep + 1; handle_message_tags(serv, tags, &tags_data); } url_check_line (buf); /* split line into words and words_to_end_of_line */ process_data_init (pdibuf, buf, word, word_eol, FALSE, FALSE); if (buf[0] == ':') { /* 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, tags_data.timestamp)) goto xit; word[1]++; word_eol[1] = buf + 1; /* but not for HexChat internally */ } else { word[0] = type = word[1]; if (plugin_emit_server (sess, type, word, word_eol, tags_data.timestamp)) goto xit; } if (buf[0] != ':') { process_named_servermsg (sess, buf, word[0], word_eol, &tags_data); 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, &tags_data); } else { process_named_msg (sess, type, word, word_eol, &tags_data); } xit: g_free (pdibuf); }
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 (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); } 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; } } else if (len == 3) { guint32 t; 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 *pass; /* buffer for SASL password */ char buffer[256]; /* buffer for requesting capabilities and emitting the signal */ 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) { EMIT_SIGNAL (XP_TE_CAPACK, sess->server->server_session, word[1], word[5][0]==':' ? ++word_eol[5] : word_eol[5], NULL, NULL, 0); if (strstr (word_eol[5], "identify-msg") != 0) { serv->have_idmsg = TRUE; } if (strstr (word_eol[5], "multi-prefix") != 0) { serv->have_namesx = TRUE; } if (strstr (word_eol[5], "sasl") != 0) { serv->have_sasl = TRUE; EMIT_SIGNAL (XP_TE_SASLAUTH, serv->server_session, sess->server->sasluser, NULL, NULL, NULL, 0); tcp_send_len (serv, "AUTHENTICATE PLAIN\r\n", 20); pass = encode_sasl_pass (sess->server->sasluser, sess->server->saslpassword); tcp_sendf (sess->server, "AUTHENTICATE %s\r\n", pass); free (pass); } } else if (strncasecmp (word[4], "LS", 2) == 0) { EMIT_SIGNAL (XP_TE_CAPLIST, serv->server_session, word[1], word[5][0]==':' ? ++word_eol[5] : word_eol[5], NULL, NULL, 0); want_cap = 0; want_sasl = 0; if (strstr (word_eol[5], "identify-msg") != 0) { strcpy (buffer, "CAP REQ :identify-msg"); want_cap = 1; } if (strstr (word_eol[5], "multi-prefix") != 0) { want_cap ? strcat (buffer, " multi-prefix") : strcpy (buffer, "CAP REQ :multi-prefix"); want_cap = 1; } /* if the SASL password is set, request SASL auth */ if (strstr (word_eol[5], "sasl") != 0 && strlen (sess->server->saslpassword) != 0) { want_cap ? strcat (buffer, " sasl") : strcpy (buffer, "CAP REQ :sasl"); want_sasl = 1; } if (want_cap) { /* buffer + 9 = emit buffer without "CAP REQ :" */ EMIT_SIGNAL (XP_TE_CAPREQ, sess->server->server_session, buffer + 9, NULL, NULL, NULL, 0); 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); } } else if (strncasecmp (word[4], "NAK", 3) == 0) { tcp_send_len (serv, "CAP END\r\n", 9); } return; } } garbage: /* unknown message */ PrintTextf (sess, "GARBAGE: %s\n", word_eol[1]); }