diff -up pidgin-2.10.7/libpurple/protocols/irc/msgs.c.CVE-2014-0020 pidgin-2.10.7/libpurple/protocols/irc/msgs.c
--- pidgin-2.10.7/libpurple/protocols/irc/msgs.c.CVE-2014-0020 2013-02-11 04:16:52.000000000 -0500
+++ pidgin-2.10.7/libpurple/protocols/irc/msgs.c 2014-01-29 23:28:32.833335259 -0500
@@ -20,6 +20,12 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
*/
+/*
+ * Note: If you change any of these functions to use additional args you
+ * MUST ensure the arg count is correct in parse.c. Otherwise it may be
+ * possible for a malicious server or man-in-the-middle to trigger a crash.
+ */
+
#include "internal.h"
#include "conversation.h"
@@ -203,9 +209,6 @@ void irc_msg_features(struct irc_conn *i
gchar **features;
int i;
- if (!args || !args[0] || !args[1])
- return;
-
features = g_strsplit(args[1], " ", -1);
for (i = 0; features[i]; i++) {
char *val;
@@ -220,9 +223,6 @@ void irc_msg_features(struct irc_conn *i
void irc_msg_luser(struct irc_conn *irc, const char *name, const char *from, char **args)
{
- if (!args || !args[0])
- return;
-
if (!strcmp(name, "251")) {
/* 251 is required, so we pluck our nick from here and
* finalize connection */
@@ -238,9 +238,6 @@ void irc_msg_away(struct irc_conn *irc,
PurpleConnection *gc;
char *msg;
- if (!args || !args[1])
- return;
-
if (irc->whois.nick && !purple_utf8_strcasecmp(irc->whois.nick, args[1])) {
/* We're doing a whois, show this in the whois dialog */
irc_msg_whois(irc, name, from, args);
@@ -259,8 +256,7 @@ void irc_msg_badmode(struct irc_conn *ir
{
PurpleConnection *gc = purple_account_get_connection(irc->account);
- if (!args || !args[1] || !gc)
- return;
+ g_return_if_fail(gc);
purple_notify_error(gc, NULL, _("Bad mode"), args[1]);
}
@@ -269,17 +265,13 @@ void irc_msg_ban(struct irc_conn *irc, c
{
PurpleConversation *convo;
- if (!args || !args[0] || !args[1])
- return;
-
convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,
args[1], irc->account);
if (!strcmp(name, "367")) {
char *msg = NULL;
/* Ban list entry */
- if (!args[2])
- return;
+ g_return_if_fail(args[2]);
if (args[3] && args[4]) {
/* This is an extended syntax, not in RFC 1459 */
int t1 = atoi(args[4]);
@@ -315,8 +307,7 @@ void irc_msg_banned(struct irc_conn *irc
PurpleConnection *gc = purple_account_get_connection(irc->account);
char *buf;
- if (!args || !args[1] || !gc)
- return;
+ g_return_if_fail(gc);
buf = g_strdup_printf(_("You are banned from %s."), args[1]);
purple_notify_error(gc, _("Banned"), _("Banned"), buf);
@@ -328,9 +319,6 @@ void irc_msg_banfull(struct irc_conn *ir
PurpleConversation *convo;
char *buf, *nick;
- if (!args || !args[0] || !args[1] || !args[2])
- return;
-
convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, args[1], irc->account);
if (!convo)
return;
@@ -349,9 +337,6 @@ void irc_msg_chanmode(struct irc_conn *i
PurpleConversation *convo;
char *buf, *escaped;
- if (!args || !args[1] || !args[2])
- return;
-
convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, args[1], irc->account);
if (!convo) /* XXX punt on channels we are not in for now */
return;
@@ -489,13 +474,6 @@ void irc_msg_who(struct irc_conn *irc, c
PurpleConvChatBuddyFlags flags;
GList *keys = NULL, *values = NULL;
- if (!args || !args[0] || !args[1] || !args[2] || !args[3]
- || !args[4] || !args[5] || !args[6] || !args[7]) {
- purple_debug(PURPLE_DEBUG_ERROR, "irc",
- "Got a WHO response with not enough arguments\n");
- return;
- }
-
conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, args[1], irc->account);
if (!conv) {
purple_debug(PURPLE_DEBUG_ERROR, "irc","Got a WHO response for %s, which doesn't exist\n", args[1]);
@@ -571,9 +549,6 @@ void irc_msg_list(struct irc_conn *irc,
PurpleRoomlistRoom *room;
char *topic;
- if (!args[0] || !args[1] || !args[2] || !args[3])
- return;
-
if (!purple_roomlist_get_in_progress(irc->roomlist)) {
purple_debug_warning("irc", "Buggy server didn't send RPL_LISTSTART.\n");
purple_roomlist_set_in_progress(irc->roomlist, TRUE);
@@ -595,13 +570,13 @@ void irc_msg_topic(struct irc_conn *irc,
PurpleConversation *convo;
if (!strcmp(name, "topic")) {
- if (!args[0] || !args[1])
- return;
+ g_return_if_fail(args[0]);
+ g_return_if_fail(args[1]);
chan = args[0];
topic = irc_mirc2txt (args[1]);
} else {
- if (!args[0] || !args[1] || !args[2])
- return;
+ g_return_if_fail(args[1]);
+ g_return_if_fail(args[2]);
chan = args[1];
topic = irc_mirc2txt (args[2]);
}
@@ -652,9 +627,6 @@ void irc_msg_topicinfo(struct irc_conn *
struct tm *tm;
time_t t;
char *msg, *timestamp, *datestamp;
-
- if (!args || !args[1] || !args[2] || !args[3])
- return;
convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, args[1], irc->account);
if (!convo) {
@@ -683,8 +655,7 @@ void irc_msg_unknown(struct irc_conn *ir
PurpleConnection *gc = purple_account_get_connection(irc->account);
char *buf;
- if (!args || !args[1] || !gc)
- return;
+ g_return_if_fail(gc);
buf = g_strdup_printf(_("Unknown message '%s'"), args[1]);
purple_notify_error(gc, _("Unknown message"), buf, _("The IRC server received a message it did not understand."));
@@ -776,9 +747,6 @@ void irc_msg_motd(struct irc_conn *irc,
{
char *escaped;
- if (!args || !args[0])
- return;
-
if (!strcmp(name, "375")) {
if (irc->motd)
g_string_free(irc->motd, TRUE);
@@ -815,11 +783,9 @@ void irc_msg_motd(struct irc_conn *irc,
void irc_msg_time(struct irc_conn *irc, const char *name, const char *from, char **args)
{
- PurpleConnection *gc;
+ PurpleConnection *gc = purple_account_get_connection(irc->account);
- gc = purple_account_get_connection(irc->account);
- if (gc == NULL || args == NULL || args[2] == NULL)
- return;
+ g_return_if_fail(gc);
purple_notify_message(gc, PURPLE_NOTIFY_MSG_INFO, _("Time Response"),
_("The IRC server's local time is:"),
@@ -830,8 +796,7 @@ void irc_msg_nochan(struct irc_conn *irc
{
PurpleConnection *gc = purple_account_get_connection(irc->account);
- if (gc == NULL || args == NULL || args[1] == NULL)
- return;
+ g_return_if_fail(gc);
purple_notify_error(gc, NULL, _("No such channel"), args[1]);
}
@@ -892,9 +857,6 @@ void irc_msg_notop(struct irc_conn *irc,
{
PurpleConversation *convo;
- if (!args || !args[1] || !args[2])
- return;
-
convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, args[1], irc->account);
if (!convo)
return;
@@ -908,8 +870,7 @@ void irc_msg_invite(struct irc_conn *irc
GHashTable *components;
gchar *nick;
- if (!args || !args[1] || !gc)
- return;
+ g_return_if_fail(gc);
components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
nick = irc_mask_nick(from);
@@ -925,8 +886,7 @@ void irc_msg_inviteonly(struct irc_conn
PurpleConnection *gc = purple_account_get_connection(irc->account);
char *buf;
- if (!args || !args[1] || !gc)
- return;
+ g_return_if_fail(gc);
buf = g_strdup_printf(_("Joining %s requires an invitation."), args[1]);
purple_notify_error(gc, _("Invitation only"), _("Invitation only"), buf);
@@ -939,9 +899,6 @@ void irc_msg_ison(struct irc_conn *irc,
struct irc_buddy *ib;
int i;
- if (!args || !args[1])
- return;
-
nicks = g_strsplit(args[1], " ", -1);
for (i = 0; nicks[i]; i++) {
if ((ib = g_hash_table_lookup(irc->buddies, (gconstpointer)nicks[i])) == NULL) {
@@ -982,14 +939,13 @@ void irc_msg_join(struct irc_conn *irc,
PurpleConvChat *chat;
PurpleConvChatBuddy *cb;
- char *nick = irc_mask_nick(from), *userhost, *buf;
+ char *nick, *userhost, *buf;
struct irc_buddy *ib;
static int id = 1;
- if (!gc) {
- g_free(nick);
- return;
- }
+ g_return_if_fail(gc);
+
+ nick = irc_mask_nick(from);
if (!purple_utf8_strcasecmp(nick, purple_connection_get_display_name(gc))) {
/* We are joining a channel for the first time */
@@ -1049,12 +1005,11 @@ void irc_msg_kick(struct irc_conn *irc,
{
PurpleConnection *gc = purple_account_get_connection(irc->account);
PurpleConversation *convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, args[0], irc->account);
- char *nick = irc_mask_nick(from), *buf;
+ char *nick, *buf;
- if (!gc) {
- g_free(nick);
- return;
- }
+ g_return_if_fail(gc);
+
+ nick = irc_mask_nick(from);
if (!convo) {
purple_debug(PURPLE_DEBUG_ERROR, "irc", "Received a KICK for unknown channel %s\n", args[0]);
@@ -1197,9 +1152,6 @@ void irc_msg_nickused(struct irc_conn *i
char *newnick, *buf, *end;
PurpleConnection *gc = purple_account_get_connection(irc->account);
- if (!args || !args[1])
- return;
-
if (gc && purple_connection_get_state(gc) == PURPLE_CONNECTED) {
/* We only want to do the following dance if the connection
has not been successfully completed. If it has, just
@@ -1238,9 +1190,6 @@ void irc_msg_nickused(struct irc_conn *i
void irc_msg_notice(struct irc_conn *irc, const char *name, const char *from, char **args)
{
- if (!args || !args[0] || !args[1])
- return;
-
irc_msg_handle_privmsg(irc, name, from, args[0], args[1], TRUE);
}
@@ -1248,8 +1197,7 @@ void irc_msg_nochangenick(struct irc_con
{
PurpleConnection *gc = purple_account_get_connection(irc->account);
- if (!args || !args[2] || !gc)
- return;
+ g_return_if_fail(gc);
purple_notify_error(gc, _("Cannot change nick"), _("Could not change nick"), args[2]);
}
@@ -1260,8 +1208,7 @@ void irc_msg_part(struct irc_conn *irc,
PurpleConversation *convo;
char *nick, *msg, *channel;
- if (!args || !args[0] || !gc)
- return;
+ g_return_if_fail(gc);
/* Undernet likes to :-quote the channel name, for no good reason
* that I can see. This catches that. */
@@ -1294,8 +1241,6 @@ void irc_msg_part(struct irc_conn *irc,
void irc_msg_ping(struct irc_conn *irc, const char *name, const char *from, char **args)
{
char *buf;
- if (!args || !args[0])
- return;
buf = irc_format(irc, "v:", "PONG", args[0]);
irc_send(irc, buf);
@@ -1309,9 +1254,6 @@ void irc_msg_pong(struct irc_conn *irc,
char **parts, *msg;
time_t oldstamp;
- if (!args || !args[1])
- return;
-
parts = g_strsplit(args[1], " ", 2);
if (!parts[0] || !parts[1]) {
@@ -1345,9 +1287,6 @@ void irc_msg_pong(struct irc_conn *irc,
void irc_msg_privmsg(struct irc_conn *irc, const char *name, const char *from, char **args)
{
- if (!args || !args[0] || !args[1])
- return;
-
irc_msg_handle_privmsg(irc, name, from, args[0], args[1], FALSE);
}
@@ -1401,8 +1340,7 @@ void irc_msg_regonly(struct irc_conn *ir
PurpleConversation *convo;
char *msg;
- if (!args || !args[1] || !args[2] || !gc)
- return;
+ g_return_if_fail(gc);
convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, args[1], irc->account);
if (convo) {
@@ -1424,8 +1362,7 @@ void irc_msg_quit(struct irc_conn *irc,
struct irc_buddy *ib;
char *data[2];
- if (!args || !args[0] || !gc)
- return;
+ g_return_if_fail(gc);
data[0] = irc_mask_nick(from);
data[1] = args[0];
@@ -1445,9 +1382,6 @@ void irc_msg_unavailable(struct irc_conn
{
PurpleConnection *gc = purple_account_get_connection(irc->account);
- if (!args || !args[1])
- return;
-
purple_notify_error(gc, NULL, _("Nick or channel is temporarily unavailable."), args[1]);
}
@@ -1456,8 +1390,7 @@ void irc_msg_wallops(struct irc_conn *ir
PurpleConnection *gc = purple_account_get_connection(irc->account);
char *nick, *msg;
- if (!args || !args[0] || !gc)
- return;
+ g_return_if_fail(gc);
nick = irc_mask_nick(from);
msg = g_strdup_printf (_("Wallops from %s"), nick);
@@ -1633,7 +1566,7 @@ irc_msg_cap(struct irc_conn *irc, const
PurpleConnection *gc = purple_account_get_connection(irc->account);
const char *mech_list = NULL;
- if (!args[1] || !args[2] || strncmp(args[2], "sasl ", 6))
+ if (strncmp(args[2], "sasl ", 6))
return;
if (strncmp(args[1], "ACK", 4)) {
const char *tmp = _("SASL authentication failed: Server does not support SASL authentication.");
diff -up pidgin-2.10.7/libpurple/protocols/irc/parse.c.CVE-2014-0020 pidgin-2.10.7/libpurple/protocols/irc/parse.c
--- pidgin-2.10.7/libpurple/protocols/irc/parse.c.CVE-2014-0020 2013-02-11 04:16:52.000000000 -0500
+++ pidgin-2.10.7/libpurple/protocols/irc/parse.c 2014-01-29 23:28:32.834335227 -0500
@@ -50,80 +50,85 @@ extern PurplePlugin *_irc_plugin;
static struct _irc_msg {
char *name;
char *format;
+
+ /** The required parameter count, based on values we use, not protocol
+ * specification. */
+ int req_cnt;
+
void (*cb)(struct irc_conn *irc, const char *name, const char *from, char **args);
} _irc_msgs[] = {
- { "005", "n*", irc_msg_features }, /* Feature list */
- { "251", "n:", irc_msg_luser }, /* Client & Server count */
- { "255", "n:", irc_msg_luser }, /* Client & Server count Mk. II */
- { "301", "nn:", irc_msg_away }, /* User is away */
- { "303", "n:", irc_msg_ison }, /* ISON reply */
- { "311", "nnvvv:", irc_msg_whois }, /* Whois user */
- { "312", "nnv:", irc_msg_whois }, /* Whois server */
- { "313", "nn:", irc_msg_whois }, /* Whois ircop */
- { "317", "nnvv", irc_msg_whois }, /* Whois idle */
- { "318", "nt:", irc_msg_endwhois }, /* End of WHOIS */
- { "319", "nn:", irc_msg_whois }, /* Whois channels */
- { "320", "nn:", irc_msg_whois }, /* Whois (fn ident) */
- { "314", "nnnvv:", irc_msg_whois }, /* Whowas user */
- { "315", "nt:", irc_msg_who }, /* end of WHO channel */
- { "369", "nt:", irc_msg_endwhois }, /* End of WHOWAS */
- { "321", "*", irc_msg_list }, /* Start of list */
- { "322", "ncv:", irc_msg_list }, /* List. */
- { "323", ":", irc_msg_list }, /* End of list. */
- { "324", "ncv:", irc_msg_chanmode }, /* Channel modes */
- { "331", "nc:", irc_msg_topic }, /* No channel topic */
- { "332", "nc:", irc_msg_topic }, /* Channel topic */
- { "333", "ncvv", irc_msg_topicinfo }, /* Topic setter stuff */
- { "352", "ncvvvnv:", irc_msg_who }, /* Channel WHO */
- { "353", "nvc:", irc_msg_names }, /* Names list */
- { "366", "nc:", irc_msg_names }, /* End of names */
- { "367", "ncnnv", irc_msg_ban }, /* Ban list */
- { "368", "nc:", irc_msg_ban }, /* End of ban list */
- { "372", "n:", irc_msg_motd }, /* MOTD */
- { "375", "n:", irc_msg_motd }, /* Start MOTD */
- { "376", "n:", irc_msg_motd }, /* End of MOTD */
- { "391", "nv:", irc_msg_time }, /* Time reply */
- { "401", "nt:", irc_msg_nonick }, /* No such nick/chan */
- { "406", "nt:", irc_msg_nonick }, /* No such nick for WHOWAS */
- { "403", "nc:", irc_msg_nochan }, /* No such channel */
- { "404", "nt:", irc_msg_nosend }, /* Cannot send to chan */
- { "421", "nv:", irc_msg_unknown }, /* Unknown command */
- { "422", "n:", irc_msg_motd }, /* MOTD file missing */
- { "432", "vn:", irc_msg_badnick }, /* Erroneous nickname */
- { "433", "vn:", irc_msg_nickused }, /* Nickname already in use */
- { "437", "nc:", irc_msg_unavailable }, /* Nick/channel is unavailable */
- { "438", "nn:", irc_msg_nochangenick }, /* Nick may not change */
- { "442", "nc:", irc_msg_notinchan }, /* Not in channel */
- { "473", "nc:", irc_msg_inviteonly }, /* Tried to join invite-only */
- { "474", "nc:", irc_msg_banned }, /* Banned from channel */
- { "477", "nc:", irc_msg_regonly }, /* Registration Required */
- { "478", "nct:", irc_msg_banfull }, /* Banlist is full */
- { "482", "nc:", irc_msg_notop }, /* Need to be op to do that */
- { "501", "n:", irc_msg_badmode }, /* Unknown mode flag */
- { "506", "nc:", irc_msg_nosend }, /* Must identify to send */
- { "515", "nc:", irc_msg_regonly }, /* Registration required */
+ { "005", "n*", 2, irc_msg_features }, /* Feature list */
+ { "251", "n:", 1, irc_msg_luser }, /* Client & Server count */
+ { "255", "n:", 1, irc_msg_luser }, /* Client & Server count Mk. II */
+ { "301", "nn:", 3, irc_msg_away }, /* User is away */
+ { "303", "n:", 2, irc_msg_ison }, /* ISON reply */
+ { "311", "nnvvv:", 6, irc_msg_whois }, /* Whois user */
+ { "312", "nnv:", 4, irc_msg_whois }, /* Whois server */
+ { "313", "nn:", 2, irc_msg_whois }, /* Whois ircop */
+ { "317", "nnvv", 4, irc_msg_whois }, /* Whois idle */
+ { "318", "nt:", 2, irc_msg_endwhois }, /* End of WHOIS */
+ { "319", "nn:", 3, irc_msg_whois }, /* Whois channels */
+ { "320", "nn:", 2, irc_msg_whois }, /* Whois (fn ident) */
+ { "314", "nnnvv:", 6, irc_msg_whois }, /* Whowas user */
+ { "315", "nt:", 0, irc_msg_who }, /* end of WHO channel */
+ { "369", "nt:", 2, irc_msg_endwhois }, /* End of WHOWAS */
+ { "321", "*", 0, irc_msg_list }, /* Start of list */
+ { "322", "ncv:", 4, irc_msg_list }, /* List. */
+ { "323", ":", 0, irc_msg_list }, /* End of list. */
+ { "324", "ncv:", 3, irc_msg_chanmode }, /* Channel modes */
+ { "331", "nc:", 3, irc_msg_topic }, /* No channel topic */
+ { "332", "nc:", 3, irc_msg_topic }, /* Channel topic */
+ { "333", "ncvv", 4, irc_msg_topicinfo }, /* Topic setter stuff */
+ { "352", "ncvvvnv:", 8, irc_msg_who }, /* Channel WHO */
+ { "353", "nvc:", 4, irc_msg_names }, /* Names list */
+ { "366", "nc:", 2, irc_msg_names }, /* End of names */
+ { "367", "ncnnv", 3, irc_msg_ban }, /* Ban list */
+ { "368", "nc:", 2, irc_msg_ban }, /* End of ban list */
+ { "372", "n:", 1, irc_msg_motd }, /* MOTD */
+ { "375", "n:", 1, irc_msg_motd }, /* Start MOTD */
+ { "376", "n:", 1, irc_msg_motd }, /* End of MOTD */
+ { "391", "nv:", 3, irc_msg_time }, /* Time reply */
+ { "401", "nt:", 2, irc_msg_nonick }, /* No such nick/chan */
+ { "406", "nt:", 2, irc_msg_nonick }, /* No such nick for WHOWAS */
+ { "403", "nc:", 2, irc_msg_nochan }, /* No such channel */
+ { "404", "nt:", 3, irc_msg_nosend }, /* Cannot send to chan */
+ { "421", "nv:", 2, irc_msg_unknown }, /* Unknown command */
+ { "422", "n:", 1, irc_msg_motd }, /* MOTD file missing */
+ { "432", "vn:", 0, irc_msg_badnick }, /* Erroneous nickname */
+ { "433", "vn:", 2, irc_msg_nickused }, /* Nickname already in use */
+ { "437", "nc:", 2, irc_msg_unavailable }, /* Nick/channel is unavailable */
+ { "438", "nn:", 3, irc_msg_nochangenick }, /* Nick may not change */
+ { "442", "nc:", 3, irc_msg_notinchan }, /* Not in channel */
+ { "473", "nc:", 2, irc_msg_inviteonly }, /* Tried to join invite-only */
+ { "474", "nc:", 2, irc_msg_banned }, /* Banned from channel */
+ { "477", "nc:", 3, irc_msg_regonly }, /* Registration Required */
+ { "478", "nct:", 3, irc_msg_banfull }, /* Banlist is full */
+ { "482", "nc:", 3, irc_msg_notop }, /* Need to be op to do that */
+ { "501", "n:", 2, irc_msg_badmode }, /* Unknown mode flag */
+ { "506", "nc:", 3, irc_msg_nosend }, /* Must identify to send */
+ { "515", "nc:", 3, irc_msg_regonly }, /* Registration required */
#ifdef HAVE_CYRUS_SASL
- { "903", "*", irc_msg_authok}, /* SASL auth successful */
- { "904", "*", irc_msg_authtryagain }, /* SASL auth failed, can recover */
- { "905", "*", irc_msg_authfail }, /* SASL auth failed */
- { "906", "*", irc_msg_authfail }, /* SASL auth failed */
- { "907", "*", irc_msg_authfail }, /* SASL auth failed */
- { "cap", "vv:", irc_msg_cap }, /* SASL capable */
+ { "903", "*", 0, irc_msg_authok}, /* SASL auth successful */
+ { "904", "*", 0, irc_msg_authtryagain }, /* SASL auth failed, can recover*/
+ { "905", "*", 0, irc_msg_authfail }, /* SASL auth failed */
+ { "906", "*", 0, irc_msg_authfail }, /* SASL auth failed */
+ { "907", "*", 0, irc_msg_authfail }, /* SASL auth failed */
+ { "cap", "vv:", 3, irc_msg_cap }, /* SASL capable */
#endif
- { "invite", "n:", irc_msg_invite }, /* Invited */
- { "join", ":", irc_msg_join }, /* Joined a channel */
- { "kick", "cn:", irc_msg_kick }, /* KICK */
- { "mode", "tv:", irc_msg_mode }, /* MODE for channel */
- { "nick", ":", irc_msg_nick }, /* Nick change */
- { "notice", "t:", irc_msg_notice }, /* NOTICE recv */
- { "part", "c:", irc_msg_part }, /* Parted a channel */
- { "ping", ":", irc_msg_ping }, /* Received PING from server */
- { "pong", "v:", irc_msg_pong }, /* Received PONG from server */
- { "privmsg", "t:", irc_msg_privmsg }, /* Received private message */
- { "topic", "c:", irc_msg_topic }, /* TOPIC command */
- { "quit", ":", irc_msg_quit }, /* QUIT notice */
- { "wallops", ":", irc_msg_wallops }, /* WALLOPS command */
- { NULL, NULL, NULL }
+ { "invite", "n:", 2, irc_msg_invite }, /* Invited */
+ { "join", ":", 1, irc_msg_join }, /* Joined a channel */
+ { "kick", "cn:", 3, irc_msg_kick }, /* KICK */
+ { "mode", "tv:", 2, irc_msg_mode }, /* MODE for channel */
+ { "nick", ":", 1, irc_msg_nick }, /* Nick change */
+ { "notice", "t:", 2, irc_msg_notice }, /* NOTICE recv */
+ { "part", "c:", 1, irc_msg_part }, /* Parted a channel */
+ { "ping", ":", 1, irc_msg_ping }, /* Received PING from server */
+ { "pong", "v:", 2, irc_msg_pong }, /* Received PONG from server */
+ { "privmsg", "t:", 2, irc_msg_privmsg }, /* Received private message */
+ { "topic", "c:", 2, irc_msg_topic }, /* TOPIC command */
+ { "quit", ":", 1, irc_msg_quit }, /* QUIT notice */
+ { "wallops", ":", 1, irc_msg_wallops }, /* WALLOPS command */
+ { NULL, NULL, 0, NULL }
};
static struct _irc_user_cmd {
@@ -660,6 +665,8 @@ void irc_parse_msg(struct irc_conn *irc,
char *cur, *end, *tmp, *from, *msgname, *fmt, **args, *msg;
guint i;
PurpleConnection *gc = purple_account_get_connection(irc->account);
+ gboolean fmt_valid;
+ int args_cnt;
irc->recv_time = time(NULL);
@@ -716,7 +723,9 @@ void irc_parse_msg(struct irc_conn *irc,
}
g_free(msgname);
+ fmt_valid = TRUE;
args = g_new0(char *, strlen(msgent->format));
+ args_cnt = 0;
for (cur = end, fmt = msgent->format, i = 0; fmt[i] && *cur++; i++) {
switch (fmt[i]) {
case 'v':
@@ -753,12 +762,23 @@ void irc_parse_msg(struct irc_conn *irc,
break;
default:
purple_debug(PURPLE_DEBUG_ERROR, "irc", "invalid message format character '%c'\n", fmt[i]);
+ fmt_valid = FALSE;
break;
}
+ if (fmt_valid)
+ args_cnt = i + 1;
+ }
+ if (G_UNLIKELY(!fmt_valid)) {
+ purple_debug_error("irc", "message format was invalid");
+ } else if (G_LIKELY(args_cnt >= msgent->req_cnt)) {
+ tmp = irc_recv_convert(irc, from);
+ (msgent->cb)(irc, msgent->name, tmp, args);
+ g_free(tmp);
+ } else {
+ purple_debug_error("irc", "args count (%d) doesn't reach "
+ "expected value of %d for the '%s' command",
+ args_cnt, msgent->req_cnt, msgent->name);
}
- tmp = irc_recv_convert(irc, from);
- (msgent->cb)(irc, msgent->name, tmp, args);
- g_free(tmp);
for (i = 0; i < strlen(msgent->format); i++) {
g_free(args[i]);
}