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  	}