libpurple/protocols/irc/parse.c

changeset 35265
77664079d0f0
parent 35029
f9f672dcaadf
parent 35253
4d9be297d399
child 35297
2d76d38118a8
equal deleted inserted replaced
35176:b0659f31989d 35265:77664079d0f0
48 48
49 /*typedef void (*IRCMsgCallback)(struct irc_conn *irc, char *from, char *name, char **args);*/ 49 /*typedef void (*IRCMsgCallback)(struct irc_conn *irc, char *from, char *name, char **args);*/
50 static struct _irc_msg { 50 static struct _irc_msg {
51 char *name; 51 char *name;
52 char *format; 52 char *format;
53
54 /** The required parameter count, based on values we use, not protocol
55 * specification. */
56 int req_cnt;
57
53 void (*cb)(struct irc_conn *irc, const char *name, const char *from, char **args); 58 void (*cb)(struct irc_conn *irc, const char *name, const char *from, char **args);
54 } _irc_msgs[] = { 59 } _irc_msgs[] = {
55 { "005", "n*", irc_msg_features }, /* Feature list */ 60 { "005", "n*", 2, irc_msg_features }, /* Feature list */
56 { "251", "n:", irc_msg_luser }, /* Client & Server count */ 61 { "251", "n:", 1, irc_msg_luser }, /* Client & Server count */
57 { "255", "n:", irc_msg_luser }, /* Client & Server count Mk. II */ 62 { "255", "n:", 1, irc_msg_luser }, /* Client & Server count Mk. II */
58 { "301", "nn:", irc_msg_away }, /* User is away */ 63 { "301", "nn:", 3, irc_msg_away }, /* User is away */
59 { "303", "n:", irc_msg_ison }, /* ISON reply */ 64 { "303", "n:", 2, irc_msg_ison }, /* ISON reply */
60 { "311", "nnvvv:", irc_msg_whois }, /* Whois user */ 65 { "311", "nnvvv:", 6, irc_msg_whois }, /* Whois user */
61 { "312", "nnv:", irc_msg_whois }, /* Whois server */ 66 { "312", "nnv:", 4, irc_msg_whois }, /* Whois server */
62 { "313", "nn:", irc_msg_whois }, /* Whois ircop */ 67 { "313", "nn:", 2, irc_msg_whois }, /* Whois ircop */
63 { "317", "nnvv", irc_msg_whois }, /* Whois idle */ 68 { "317", "nnvv", 4, irc_msg_whois }, /* Whois idle */
64 { "318", "nt:", irc_msg_endwhois }, /* End of WHOIS */ 69 { "318", "nt:", 2, irc_msg_endwhois }, /* End of WHOIS */
65 { "319", "nn:", irc_msg_whois }, /* Whois channels */ 70 { "319", "nn:", 3, irc_msg_whois }, /* Whois channels */
66 { "320", "nn:", irc_msg_whois }, /* Whois (fn ident) */ 71 { "320", "nn:", 2, irc_msg_whois }, /* Whois (fn ident) */
67 { "314", "nnnvv:", irc_msg_whois }, /* Whowas user */ 72 { "314", "nnnvv:", 6, irc_msg_whois }, /* Whowas user */
68 { "315", "nt:", irc_msg_who }, /* end of WHO channel */ 73 { "315", "nt:", 0, irc_msg_who }, /* end of WHO channel */
69 { "369", "nt:", irc_msg_endwhois }, /* End of WHOWAS */ 74 { "369", "nt:", 2, irc_msg_endwhois }, /* End of WHOWAS */
70 { "321", "*", irc_msg_list }, /* Start of list */ 75 { "321", "*", 0, irc_msg_list }, /* Start of list */
71 { "322", "ncv:", irc_msg_list }, /* List. */ 76 { "322", "ncv:", 4, irc_msg_list }, /* List. */
72 { "323", ":", irc_msg_list }, /* End of list. */ 77 { "323", ":", 0, irc_msg_list }, /* End of list. */
73 { "324", "ncv:", irc_msg_chanmode }, /* Channel modes */ 78 { "324", "ncv:", 3, irc_msg_chanmode }, /* Channel modes */
74 { "331", "nc:", irc_msg_topic }, /* No channel topic */ 79 { "331", "nc:", 3, irc_msg_topic }, /* No channel topic */
75 { "332", "nc:", irc_msg_topic }, /* Channel topic */ 80 { "332", "nc:", 3, irc_msg_topic }, /* Channel topic */
76 { "333", "ncvv", irc_msg_topicinfo }, /* Topic setter stuff */ 81 { "333", "ncvv", 4, irc_msg_topicinfo }, /* Topic setter stuff */
77 { "352", "ncvvvnv:", irc_msg_who }, /* Channel WHO */ 82 { "352", "ncvvvnv:", 8, irc_msg_who }, /* Channel WHO */
78 { "353", "nvc:", irc_msg_names }, /* Names list */ 83 { "353", "nvc:", 4, irc_msg_names }, /* Names list */
79 { "366", "nc:", irc_msg_names }, /* End of names */ 84 { "366", "nc:", 2, irc_msg_names }, /* End of names */
80 { "367", "ncnnv", irc_msg_ban }, /* Ban list */ 85 { "367", "ncnnv", 3, irc_msg_ban }, /* Ban list */
81 { "368", "nc:", irc_msg_ban }, /* End of ban list */ 86 { "368", "nc:", 2, irc_msg_ban }, /* End of ban list */
82 { "372", "n:", irc_msg_motd }, /* MOTD */ 87 { "372", "n:", 1, irc_msg_motd }, /* MOTD */
83 { "375", "n:", irc_msg_motd }, /* Start MOTD */ 88 { "375", "n:", 1, irc_msg_motd }, /* Start MOTD */
84 { "376", "n:", irc_msg_motd }, /* End of MOTD */ 89 { "376", "n:", 1, irc_msg_motd }, /* End of MOTD */
85 { "391", "nv:", irc_msg_time }, /* Time reply */ 90 { "391", "nv:", 3, irc_msg_time }, /* Time reply */
86 { "401", "nt:", irc_msg_nonick }, /* No such nick/chan */ 91 { "401", "nt:", 2, irc_msg_nonick }, /* No such nick/chan */
87 { "406", "nt:", irc_msg_nonick }, /* No such nick for WHOWAS */ 92 { "406", "nt:", 2, irc_msg_nonick }, /* No such nick for WHOWAS */
88 { "403", "nc:", irc_msg_nochan }, /* No such channel */ 93 { "403", "nc:", 2, irc_msg_nochan }, /* No such channel */
89 { "404", "nt:", irc_msg_nosend }, /* Cannot send to chan */ 94 { "404", "nt:", 3, irc_msg_nosend }, /* Cannot send to chan */
90 { "421", "nv:", irc_msg_unknown }, /* Unknown command */ 95 { "421", "nv:", 2, irc_msg_unknown }, /* Unknown command */
91 { "422", "n:", irc_msg_motd }, /* MOTD file missing */ 96 { "422", "n:", 1, irc_msg_motd }, /* MOTD file missing */
92 { "432", "vn:", irc_msg_badnick }, /* Erroneous nickname */ 97 { "432", "vn:", 0, irc_msg_badnick }, /* Erroneous nickname */
93 { "433", "vn:", irc_msg_nickused }, /* Nickname already in use */ 98 { "433", "vn:", 2, irc_msg_nickused }, /* Nickname already in use */
94 { "437", "nc:", irc_msg_unavailable }, /* Nick/channel is unavailable */ 99 { "437", "nc:", 2, irc_msg_unavailable }, /* Nick/channel is unavailable */
95 { "438", "nn:", irc_msg_nochangenick }, /* Nick may not change */ 100 { "438", "nn:", 3, irc_msg_nochangenick }, /* Nick may not change */
96 { "442", "nc:", irc_msg_notinchan }, /* Not in channel */ 101 { "442", "nc:", 3, irc_msg_notinchan }, /* Not in channel */
97 { "473", "nc:", irc_msg_inviteonly }, /* Tried to join invite-only */ 102 { "473", "nc:", 2, irc_msg_inviteonly }, /* Tried to join invite-only */
98 { "474", "nc:", irc_msg_banned }, /* Banned from channel */ 103 { "474", "nc:", 2, irc_msg_banned }, /* Banned from channel */
99 { "477", "nc:", irc_msg_regonly }, /* Registration Required */ 104 { "477", "nc:", 3, irc_msg_regonly }, /* Registration Required */
100 { "478", "nct:", irc_msg_banfull }, /* Banlist is full */ 105 { "478", "nct:", 3, irc_msg_banfull }, /* Banlist is full */
101 { "482", "nc:", irc_msg_notop }, /* Need to be op to do that */ 106 { "482", "nc:", 3, irc_msg_notop }, /* Need to be op to do that */
102 { "501", "n:", irc_msg_badmode }, /* Unknown mode flag */ 107 { "501", "n:", 2, irc_msg_badmode }, /* Unknown mode flag */
103 { "506", "nc:", irc_msg_nosend }, /* Must identify to send */ 108 { "506", "nc:", 3, irc_msg_nosend }, /* Must identify to send */
104 { "515", "nc:", irc_msg_regonly }, /* Registration required */ 109 { "515", "nc:", 3, irc_msg_regonly }, /* Registration required */
105 #ifdef HAVE_CYRUS_SASL 110 #ifdef HAVE_CYRUS_SASL
106 { "903", "*", irc_msg_authok}, /* SASL auth successful */ 111 { "903", "*", 0, irc_msg_authok}, /* SASL auth successful */
107 { "904", "*", irc_msg_authtryagain }, /* SASL auth failed, can recover */ 112 { "904", "*", 0, irc_msg_authtryagain }, /* SASL auth failed, can recover*/
108 { "905", "*", irc_msg_authfail }, /* SASL auth failed */ 113 { "905", "*", 0, irc_msg_authfail }, /* SASL auth failed */
109 { "906", "*", irc_msg_authfail }, /* SASL auth failed */ 114 { "906", "*", 0, irc_msg_authfail }, /* SASL auth failed */
110 { "907", "*", irc_msg_authfail }, /* SASL auth failed */ 115 { "907", "*", 0, irc_msg_authfail }, /* SASL auth failed */
111 { "cap", "vv:", irc_msg_cap }, /* SASL capable */ 116 { "cap", "vv:", 3, irc_msg_cap }, /* SASL capable */
112 #endif 117 #endif
113 { "invite", "n:", irc_msg_invite }, /* Invited */ 118 { "invite", "n:", 2, irc_msg_invite }, /* Invited */
114 { "join", ":", irc_msg_join }, /* Joined a channel */ 119 { "join", ":", 1, irc_msg_join }, /* Joined a channel */
115 { "kick", "cn:", irc_msg_kick }, /* KICK */ 120 { "kick", "cn:", 3, irc_msg_kick }, /* KICK */
116 { "mode", "tv:", irc_msg_mode }, /* MODE for channel */ 121 { "mode", "tv:", 2, irc_msg_mode }, /* MODE for channel */
117 { "nick", ":", irc_msg_nick }, /* Nick change */ 122 { "nick", ":", 1, irc_msg_nick }, /* Nick change */
118 { "notice", "t:", irc_msg_notice }, /* NOTICE recv */ 123 { "notice", "t:", 2, irc_msg_notice }, /* NOTICE recv */
119 { "part", "c:", irc_msg_part }, /* Parted a channel */ 124 { "part", "c:", 1, irc_msg_part }, /* Parted a channel */
120 { "ping", ":", irc_msg_ping }, /* Received PING from server */ 125 { "ping", ":", 1, irc_msg_ping }, /* Received PING from server */
121 { "pong", "v:", irc_msg_pong }, /* Received PONG from server */ 126 { "pong", "v:", 2, irc_msg_pong }, /* Received PONG from server */
122 { "privmsg", "t:", irc_msg_privmsg }, /* Received private message */ 127 { "privmsg", "t:", 2, irc_msg_privmsg }, /* Received private message */
123 { "topic", "c:", irc_msg_topic }, /* TOPIC command */ 128 { "topic", "c:", 2, irc_msg_topic }, /* TOPIC command */
124 { "quit", ":", irc_msg_quit }, /* QUIT notice */ 129 { "quit", ":", 1, irc_msg_quit }, /* QUIT notice */
125 { "wallops", ":", irc_msg_wallops }, /* WALLOPS command */ 130 { "wallops", ":", 1, irc_msg_wallops }, /* WALLOPS command */
126 { NULL, NULL, NULL } 131 { NULL, NULL, 0, NULL }
127 }; 132 };
128 133
129 static struct _irc_user_cmd { 134 static struct _irc_user_cmd {
130 char *name; 135 char *name;
131 char *format; 136 char *format;
662 { 667 {
663 struct _irc_msg *msgent; 668 struct _irc_msg *msgent;
664 char *cur, *end, *tmp, *from, *msgname, *fmt, **args, *msg; 669 char *cur, *end, *tmp, *from, *msgname, *fmt, **args, *msg;
665 guint i; 670 guint i;
666 PurpleConnection *gc = purple_account_get_connection(irc->account); 671 PurpleConnection *gc = purple_account_get_connection(irc->account);
672 gboolean fmt_valid;
673 int args_cnt;
667 674
668 irc->recv_time = time(NULL); 675 irc->recv_time = time(NULL);
669 676
670 /* 677 /*
671 * The data passed to irc-receiving-text is the raw protocol data. 678 * The data passed to irc-receiving-text is the raw protocol data.
718 g_free(from); 725 g_free(from);
719 return; 726 return;
720 } 727 }
721 g_free(msgname); 728 g_free(msgname);
722 729
730 fmt_valid = TRUE;
723 args = g_new0(char *, strlen(msgent->format)); 731 args = g_new0(char *, strlen(msgent->format));
732 args_cnt = 0;
724 for (cur = end, fmt = msgent->format, i = 0; fmt[i] && *cur++; i++) { 733 for (cur = end, fmt = msgent->format, i = 0; fmt[i] && *cur++; i++) {
725 switch (fmt[i]) { 734 switch (fmt[i]) {
726 case 'v': 735 case 'v':
727 if (!(end = strchr(cur, ' '))) end = cur + strlen(cur); 736 if (!(end = strchr(cur, ' '))) end = cur + strlen(cur);
728 /* This is a string of unknown encoding which we do not 737 /* This is a string of unknown encoding which we do not
755 args[i] = purple_utf8_salvage(cur); 764 args[i] = purple_utf8_salvage(cur);
756 cur = cur + strlen(cur); 765 cur = cur + strlen(cur);
757 break; 766 break;
758 default: 767 default:
759 purple_debug(PURPLE_DEBUG_ERROR, "irc", "invalid message format character '%c'\n", fmt[i]); 768 purple_debug(PURPLE_DEBUG_ERROR, "irc", "invalid message format character '%c'\n", fmt[i]);
769 fmt_valid = FALSE;
760 break; 770 break;
761 } 771 }
762 } 772 if (fmt_valid)
763 tmp = irc_recv_convert(irc, from); 773 args_cnt = i + 1;
764 (msgent->cb)(irc, msgent->name, tmp, args); 774 }
765 g_free(tmp); 775 if (G_UNLIKELY(!fmt_valid)) {
776 purple_debug_error("irc", "message format was invalid");
777 } else if (G_LIKELY(args_cnt >= msgent->req_cnt)) {
778 tmp = irc_recv_convert(irc, from);
779 (msgent->cb)(irc, msgent->name, tmp, args);
780 g_free(tmp);
781 } else {
782 purple_debug_error("irc", "args count (%d) doesn't reach "
783 "expected value of %d for the '%s' command",
784 args_cnt, msgent->req_cnt, msgent->name);
785 }
766 for (i = 0; i < strlen(msgent->format); i++) { 786 for (i = 0; i < strlen(msgent->format); i++) {
767 g_free(args[i]); 787 g_free(args[i]);
768 } 788 }
769 g_free(args); 789 g_free(args);
770 g_free(from); 790 g_free(from);

mercurial