IRC: implement support for required args checking in message parser release-2.x.y
authorTomasz Wasilczyk <twasilczyk@pidgin.im>
Thu, 16 Jan 2014 02:04:48 +0100
branchrelease-2.x.y
changeseta167504359e5 pushlog
parent 2bb66ef1475e
child 900c8ac8b4fb
IRC: implement support for required args checking in message parser
libpurple/protocols/irc/parse.c
      1.1 --- a/libpurple/protocols/irc/parse.c
      1.2 +++ b/libpurple/protocols/irc/parse.c
      1.3 @@ -50,80 +50,81 @@
      1.4  static struct _irc_msg {
      1.5  	char *name;
      1.6  	char *format;
      1.7 +	int req_cnt;
      1.8  	void (*cb)(struct irc_conn *irc, const char *name, const char *from, char **args);
      1.9  } _irc_msgs[] = {
     1.10 -	{ "005", "n*", irc_msg_features },	/* Feature list			*/
     1.11 -	{ "251", "n:", irc_msg_luser },		/* Client & Server count	*/
     1.12 -	{ "255", "n:", irc_msg_luser },		/* Client & Server count Mk. II	*/
     1.13 -	{ "301", "nn:", irc_msg_away },		/* User is away			*/
     1.14 -	{ "303", "n:", irc_msg_ison },		/* ISON reply			*/
     1.15 -	{ "311", "nnvvv:", irc_msg_whois },	/* Whois user			*/
     1.16 -	{ "312", "nnv:", irc_msg_whois },	/* Whois server			*/
     1.17 -	{ "313", "nn:", irc_msg_whois },	/* Whois ircop			*/
     1.18 -	{ "317", "nnvv", irc_msg_whois },	/* Whois idle			*/
     1.19 -	{ "318", "nt:", irc_msg_endwhois },	/* End of WHOIS			*/
     1.20 -	{ "319", "nn:", irc_msg_whois },	/* Whois channels		*/
     1.21 -	{ "320", "nn:", irc_msg_whois },	/* Whois (fn ident)		*/
     1.22 -	{ "314", "nnnvv:", irc_msg_whois },	/* Whowas user			*/
     1.23 -	{ "315", "nt:", irc_msg_who },      /* end of WHO channel   */
     1.24 -	{ "369", "nt:", irc_msg_endwhois },	/* End of WHOWAS		*/
     1.25 -	{ "321", "*", irc_msg_list },		/* Start of list		*/
     1.26 -	{ "322", "ncv:", irc_msg_list },	/* List.			*/
     1.27 -	{ "323", ":", irc_msg_list },		/* End of list.			*/
     1.28 -	{ "324", "ncv:", irc_msg_chanmode },	/* Channel modes		*/
     1.29 -	{ "331", "nc:",	irc_msg_topic },	/* No channel topic		*/
     1.30 -	{ "332", "nc:", irc_msg_topic },	/* Channel topic		*/
     1.31 -	{ "333", "ncvv", irc_msg_topicinfo },	/* Topic setter stuff		*/
     1.32 -	{ "352", "ncvvvnv:", irc_msg_who },	/* Channel WHO			*/
     1.33 -	{ "353", "nvc:", irc_msg_names },	/* Names list			*/
     1.34 -	{ "366", "nc:", irc_msg_names },	/* End of names			*/
     1.35 -	{ "367", "ncnnv", irc_msg_ban },	/* Ban list			*/
     1.36 -	{ "368", "nc:", irc_msg_ban },		/* End of ban list		*/
     1.37 -	{ "372", "n:", irc_msg_motd },		/* MOTD				*/
     1.38 -	{ "375", "n:", irc_msg_motd },		/* Start MOTD			*/
     1.39 -	{ "376", "n:", irc_msg_motd },		/* End of MOTD			*/
     1.40 -	{ "391", "nv:", irc_msg_time },		/* Time reply			*/
     1.41 -	{ "401", "nt:", irc_msg_nonick },	/* No such nick/chan		*/
     1.42 -	{ "406", "nt:", irc_msg_nonick },	/* No such nick for WHOWAS	*/
     1.43 -	{ "403", "nc:", irc_msg_nochan },	/* No such channel		*/
     1.44 -	{ "404", "nt:", irc_msg_nosend },	/* Cannot send to chan		*/
     1.45 -	{ "421", "nv:", irc_msg_unknown },	/* Unknown command		*/
     1.46 -	{ "422", "n:", irc_msg_motd },		/* MOTD file missing		*/
     1.47 -	{ "432", "vn:", irc_msg_badnick },	/* Erroneous nickname		*/
     1.48 -	{ "433", "vn:", irc_msg_nickused },	/* Nickname already in use	*/
     1.49 -	{ "437", "nc:", irc_msg_unavailable },  /* Nick/channel is unavailable */
     1.50 -	{ "438", "nn:", irc_msg_nochangenick },	/* Nick may not change		*/
     1.51 -	{ "442", "nc:", irc_msg_notinchan },	/* Not in channel		*/
     1.52 -	{ "473", "nc:", irc_msg_inviteonly },	/* Tried to join invite-only	*/
     1.53 -	{ "474", "nc:", irc_msg_banned },	/* Banned from channel		*/
     1.54 -	{ "477", "nc:", irc_msg_regonly },	/* Registration Required	*/
     1.55 -	{ "478", "nct:", irc_msg_banfull },	/* Banlist is full		*/
     1.56 -	{ "482", "nc:", irc_msg_notop },	/* Need to be op to do that	*/
     1.57 -	{ "501", "n:", irc_msg_badmode },	/* Unknown mode flag		*/
     1.58 -	{ "506", "nc:", irc_msg_nosend },	/* Must identify to send	*/
     1.59 -	{ "515", "nc:", irc_msg_regonly },	/* Registration required	*/
     1.60 +	{ "005", "n*", -1, irc_msg_features },		/* Feature list			*/
     1.61 +	{ "251", "n:", -1, irc_msg_luser },		/* Client & Server count	*/
     1.62 +	{ "255", "n:", -1, irc_msg_luser },		/* Client & Server count Mk. II	*/
     1.63 +	{ "301", "nn:", -1, irc_msg_away },		/* User is away			*/
     1.64 +	{ "303", "n:", -1, irc_msg_ison },		/* ISON reply			*/
     1.65 +	{ "311", "nnvvv:", -1, irc_msg_whois },		/* Whois user			*/
     1.66 +	{ "312", "nnv:", -1, irc_msg_whois },		/* Whois server			*/
     1.67 +	{ "313", "nn:", -1, irc_msg_whois },		/* Whois ircop			*/
     1.68 +	{ "317", "nnvv", -1, irc_msg_whois },		/* Whois idle			*/
     1.69 +	{ "318", "nt:", -1, irc_msg_endwhois },		/* End of WHOIS			*/
     1.70 +	{ "319", "nn:", -1, irc_msg_whois },		/* Whois channels		*/
     1.71 +	{ "320", "nn:", -1, irc_msg_whois },		/* Whois (fn ident)		*/
     1.72 +	{ "314", "nnnvv:", -1, irc_msg_whois },		/* Whowas user			*/
     1.73 +	{ "315", "nt:", -1, irc_msg_who },		/* end of WHO channel		*/
     1.74 +	{ "369", "nt:", -1, irc_msg_endwhois },		/* End of WHOWAS		*/
     1.75 +	{ "321", "*", -1, irc_msg_list },		/* Start of list		*/
     1.76 +	{ "322", "ncv:", -1, irc_msg_list },		/* List.			*/
     1.77 +	{ "323", ":", -1, irc_msg_list },		/* End of list.			*/
     1.78 +	{ "324", "ncv:", -1, irc_msg_chanmode },	/* Channel modes		*/
     1.79 +	{ "331", "nc:", -1,	irc_msg_topic },	/* No channel topic		*/
     1.80 +	{ "332", "nc:", -1, irc_msg_topic },		/* Channel topic		*/
     1.81 +	{ "333", "ncvv", -1, irc_msg_topicinfo },	/* Topic setter stuff		*/
     1.82 +	{ "352", "ncvvvnv:", -1, irc_msg_who },		/* Channel WHO			*/
     1.83 +	{ "353", "nvc:", -1, irc_msg_names },		/* Names list			*/
     1.84 +	{ "366", "nc:", -1, irc_msg_names },		/* End of names			*/
     1.85 +	{ "367", "ncnnv", -1, irc_msg_ban },		/* Ban list			*/
     1.86 +	{ "368", "nc:", -1, irc_msg_ban },		/* End of ban list		*/
     1.87 +	{ "372", "n:", -1, irc_msg_motd },		/* MOTD				*/
     1.88 +	{ "375", "n:", -1, irc_msg_motd },		/* Start MOTD			*/
     1.89 +	{ "376", "n:", -1, irc_msg_motd },		/* End of MOTD			*/
     1.90 +	{ "391", "nv:", -1, irc_msg_time },		/* Time reply			*/
     1.91 +	{ "401", "nt:", -1, irc_msg_nonick },		/* No such nick/chan		*/
     1.92 +	{ "406", "nt:", -1, irc_msg_nonick },		/* No such nick for WHOWAS	*/
     1.93 +	{ "403", "nc:", -1, irc_msg_nochan },		/* No such channel		*/
     1.94 +	{ "404", "nt:", -1, irc_msg_nosend },		/* Cannot send to chan		*/
     1.95 +	{ "421", "nv:", -1, irc_msg_unknown },		/* Unknown command		*/
     1.96 +	{ "422", "n:", -1, irc_msg_motd },		/* MOTD file missing		*/
     1.97 +	{ "432", "vn:", -1, irc_msg_badnick },		/* Erroneous nickname		*/
     1.98 +	{ "433", "vn:", -1, irc_msg_nickused },		/* Nickname already in use	*/
     1.99 +	{ "437", "nc:", -1, irc_msg_unavailable },	/* Nick/channel is unavailable	*/
    1.100 +	{ "438", "nn:", -1, irc_msg_nochangenick },	/* Nick may not change		*/
    1.101 +	{ "442", "nc:", -1, irc_msg_notinchan },	/* Not in channel		*/
    1.102 +	{ "473", "nc:", -1, irc_msg_inviteonly },	/* Tried to join invite-only	*/
    1.103 +	{ "474", "nc:", -1, irc_msg_banned },		/* Banned from channel		*/
    1.104 +	{ "477", "nc:", -1, irc_msg_regonly },		/* Registration Required	*/
    1.105 +	{ "478", "nct:", -1, irc_msg_banfull },		/* Banlist is full		*/
    1.106 +	{ "482", "nc:", -1, irc_msg_notop },		/* Need to be op to do that	*/
    1.107 +	{ "501", "n:", -1, irc_msg_badmode },		/* Unknown mode flag		*/
    1.108 +	{ "506", "nc:", -1, irc_msg_nosend },		/* Must identify to send	*/
    1.109 +	{ "515", "nc:", -1, irc_msg_regonly },		/* Registration required	*/
    1.110  #ifdef HAVE_CYRUS_SASL
    1.111 -	{ "903", "*", irc_msg_authok},		/* SASL auth successful		*/
    1.112 -	{ "904", "*", irc_msg_authtryagain },	/* SASL auth failed, can recover		*/
    1.113 -	{ "905", "*", irc_msg_authfail },	/* SASL auth failed		*/
    1.114 -	{ "906", "*", irc_msg_authfail },	/* SASL auth failed		*/
    1.115 -	{ "907", "*", irc_msg_authfail },	/* SASL auth failed		*/
    1.116 -	{ "cap", "vv:", irc_msg_cap },		/* SASL capable			*/
    1.117 +	{ "903", "*", -1, irc_msg_authok},		/* SASL auth successful		*/
    1.118 +	{ "904", "*", -1, irc_msg_authtryagain },	/* SASL auth failed, can recover*/
    1.119 +	{ "905", "*", -1, irc_msg_authfail },		/* SASL auth failed		*/
    1.120 +	{ "906", "*", -1, irc_msg_authfail },		/* SASL auth failed		*/
    1.121 +	{ "907", "*", -1, irc_msg_authfail },		/* SASL auth failed		*/
    1.122 +	{ "cap", "vv:", -1, irc_msg_cap },		/* SASL capable			*/
    1.123  #endif
    1.124 -	{ "invite", "n:", irc_msg_invite },	/* Invited			*/
    1.125 -	{ "join", ":", irc_msg_join },		/* Joined a channel		*/
    1.126 -	{ "kick", "cn:", irc_msg_kick },	/* KICK				*/
    1.127 -	{ "mode", "tv:", irc_msg_mode },	/* MODE for channel		*/
    1.128 -	{ "nick", ":", irc_msg_nick },		/* Nick change			*/
    1.129 -	{ "notice", "t:", irc_msg_notice },	/* NOTICE recv			*/
    1.130 -	{ "part", "c:", irc_msg_part },		/* Parted a channel		*/
    1.131 -	{ "ping", ":", irc_msg_ping },		/* Received PING from server	*/
    1.132 -	{ "pong", "v:", irc_msg_pong },		/* Received PONG from server	*/
    1.133 -	{ "privmsg", "t:", irc_msg_privmsg },	/* Received private message	*/
    1.134 -	{ "topic", "c:", irc_msg_topic },	/* TOPIC command		*/
    1.135 -	{ "quit", ":", irc_msg_quit },		/* QUIT notice			*/
    1.136 -	{ "wallops", ":", irc_msg_wallops },	/* WALLOPS command		*/
    1.137 -	{ NULL, NULL, NULL }
    1.138 +	{ "invite", "n:", -1, irc_msg_invite },		/* Invited			*/
    1.139 +	{ "join", ":", -1, irc_msg_join },		/* Joined a channel		*/
    1.140 +	{ "kick", "cn:", -1, irc_msg_kick },		/* KICK				*/
    1.141 +	{ "mode", "tv:", -1, irc_msg_mode },		/* MODE for channel		*/
    1.142 +	{ "nick", ":", -1, irc_msg_nick },		/* Nick change			*/
    1.143 +	{ "notice", "t:", -1, irc_msg_notice },		/* NOTICE recv			*/
    1.144 +	{ "part", "c:", -1, irc_msg_part },		/* Parted a channel		*/
    1.145 +	{ "ping", ":", -1, irc_msg_ping },		/* Received PING from server	*/
    1.146 +	{ "pong", "v:", -1, irc_msg_pong },		/* Received PONG from server	*/
    1.147 +	{ "privmsg", "t:", -1, irc_msg_privmsg },	/* Received private message	*/
    1.148 +	{ "topic", "c:", -1, irc_msg_topic },		/* TOPIC command		*/
    1.149 +	{ "quit", ":", -1, irc_msg_quit },		/* QUIT notice			*/
    1.150 +	{ "wallops", ":", -1, irc_msg_wallops },	/* WALLOPS command		*/
    1.151 +	{ NULL, NULL, 0, NULL }
    1.152  };
    1.153  
    1.154  static struct _irc_user_cmd {
    1.155 @@ -662,6 +663,8 @@
    1.156  	char *cur, *end, *tmp, *from, *msgname, *fmt, **args, *msg;
    1.157  	guint i;
    1.158  	PurpleConnection *gc = purple_account_get_connection(irc->account);
    1.159 +	gboolean fmt_valid;
    1.160 +	int args_cnt;
    1.161  
    1.162  	irc->recv_time = time(NULL);
    1.163  
    1.164 @@ -718,7 +721,9 @@
    1.165  	}
    1.166  	g_free(msgname);
    1.167  
    1.168 +	fmt_valid = TRUE;
    1.169  	args = g_new0(char *, strlen(msgent->format));
    1.170 +	args_cnt = 0;
    1.171  	for (cur = end, fmt = msgent->format, i = 0; fmt[i] && *cur++; i++) {
    1.172  		switch (fmt[i]) {
    1.173  		case 'v':
    1.174 @@ -755,12 +760,23 @@
    1.175  			break;
    1.176  		default:
    1.177  			purple_debug(PURPLE_DEBUG_ERROR, "irc", "invalid message format character '%c'\n", fmt[i]);
    1.178 +			fmt_valid = FALSE;
    1.179  			break;
    1.180  		}
    1.181 +		if (fmt_valid)
    1.182 +			args_cnt = i + 1;
    1.183  	}
    1.184 -	tmp = irc_recv_convert(irc, from);
    1.185 -	(msgent->cb)(irc, msgent->name, tmp, args);
    1.186 -	g_free(tmp);
    1.187 +	if (G_UNLIKELY(!fmt_valid)) {
    1.188 +		purple_debug_error("irc", "message format was invalid");
    1.189 +	} else if (G_LIKELY(args_cnt >= msgent->req_cnt)) {
    1.190 +		tmp = irc_recv_convert(irc, from);
    1.191 +		(msgent->cb)(irc, msgent->name, tmp, args);
    1.192 +		g_free(tmp);
    1.193 +	} else {
    1.194 +		purple_debug_error("irc", "args count (%d) doesn't reach "
    1.195 +			"expected value of %d for the '%s' command",
    1.196 +			args_cnt, msgent->req_cnt, msgent->name);
    1.197 +	}
    1.198  	for (i = 0; i < strlen(msgent->format); i++) {
    1.199  		g_free(args[i]);
    1.200  	}