diff options
author | LemonBoy <thatlemon@gmail.com> | 2017-10-21 11:23:44 +0200 |
---|---|---|
committer | LemonBoy <thatlemon@gmail.com> | 2018-01-07 12:36:19 +0100 |
commit | 8c87766132b7dbb75d8a49548ff7c97037ea983b (patch) | |
tree | 5e6f1923f8485c1c530b1285ab0c3fc8822ae0f5 /src/irc | |
parent | 57827ca743e95a6b6ad830fab03f46efaf1d9069 (diff) | |
download | irssi-8c87766132b7dbb75d8a49548ff7c97037ea983b.zip |
Parse multiline responses to CAP LS
The parsing logic isn't too elegant because of the optional parameter
used for signaling if a response has a continuation one.
Diffstat (limited to 'src/irc')
-rw-r--r-- | src/irc/core/irc-cap.c | 79 |
1 files changed, 52 insertions, 27 deletions
diff --git a/src/irc/core/irc-cap.c b/src/irc/core/irc-cap.c index 9ac232b5..602a7b06 100644 --- a/src/irc/core/irc-cap.c +++ b/src/irc/core/irc-cap.c @@ -110,13 +110,31 @@ static void event_cap (IRC_SERVER_REC *server, char *args, char *nick, char *add { GSList *tmp; GString *cmd; - char *params, *evt, *list, **caps; - int i, caps_length, disable, avail_caps; + char *params, *evt, *list, *star, **caps; + int i, caps_length, disable, avail_caps, multiline; - params = event_get_params(args, 3, NULL, &evt, &list); + params = event_get_params(args, 4, NULL, &evt, &star, &list); if (params == NULL) return; + /* Multiline responses have an additional parameter and we have to do + * this stupid dance to parse them */ + if (evt[0] == 'L' && !strcmp(star, "*")) { + multiline = TRUE; + } + /* This branch covers the '*' parameter isn't present, adjust the + * parameter pointer to compensate for this */ + else if (list[0] == '\0') { + multiline = FALSE; + list = star; + } + /* Malformed request, terminate the negotiation */ + else { + cap_finish_negotiation(server); + g_warn_if_reached(); + return; + } + /* Strip the trailing whitespaces before splitting the string, some servers send responses with * superfluous whitespaces that g_strsplit the interprets as tokens */ caps = g_strsplit(g_strchomp(list), " ", -1); @@ -149,37 +167,41 @@ static void event_cap (IRC_SERVER_REC *server, char *args, char *nick, char *add } - /* Request the required caps, if any */ - if (server->cap_queue == NULL) { - cap_finish_negotiation(server); - } - else { - cmd = g_string_new("CAP REQ :"); + /* A multiline response is always terminated by a normal one, + * wait until we receive that one to require any CAP */ + if (multiline == FALSE) { + /* No CAP has been requested */ + if (server->cap_queue == NULL) { + cap_finish_negotiation(server); + } + else { + cmd = g_string_new("CAP REQ :"); - avail_caps = 0; + avail_caps = 0; - /* Check whether the cap is supported by the server */ - for (tmp = server->cap_queue; tmp != NULL; tmp = tmp->next) { - if (g_hash_table_lookup_extended(server->cap_supported, tmp->data, NULL, NULL)) { - if (avail_caps > 0) - g_string_append_c(cmd, ' '); - g_string_append(cmd, tmp->data); + /* Check whether the cap is supported by the server */ + for (tmp = server->cap_queue; tmp != NULL; tmp = tmp->next) { + if (g_hash_table_lookup_extended(server->cap_supported, tmp->data, NULL, NULL)) { + if (avail_caps > 0) + g_string_append_c(cmd, ' '); + g_string_append(cmd, tmp->data); - avail_caps++; + avail_caps++; + } } - } - /* Clear the queue here */ - gslist_free_full(server->cap_queue, (GDestroyNotify) g_free); - server->cap_queue = NULL; + /* Clear the queue here */ + gslist_free_full(server->cap_queue, (GDestroyNotify) g_free); + server->cap_queue = NULL; - /* If the server doesn't support any cap we requested close the negotiation here */ - if (avail_caps > 0) - irc_send_cmd_now(server, cmd->str); - else - cap_finish_negotiation(server); + /* If the server doesn't support any cap we requested close the negotiation here */ + if (avail_caps > 0) + irc_send_cmd_now(server, cmd->str); + else + cap_finish_negotiation(server); - g_string_free(cmd, TRUE); + g_string_free(cmd, TRUE); + } } } else if (!g_strcmp0(evt, "ACK")) { @@ -214,6 +236,9 @@ static void event_cap (IRC_SERVER_REC *server, char *args, char *nick, char *add for (i = 0; i < caps_length; i++) cap_emit_signal(server, "nak", caps[i]); } + else { + g_warning("Unhandled CAP subcommand %s", evt); + } g_strfreev(caps); g_free(params); |