From 453434644a7d09c2e97d727f35b75670dc20d445 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Sun, 13 Dec 2015 10:45:11 +0200 Subject: [PATCH 1/7] irc: add hashtables to keep track of all capabilities --- src/plugins/irc/irc-channel.c | 4 ++-- src/plugins/irc/irc-nick.c | 2 +- src/plugins/irc/irc-protocol.c | 37 ++++++++++--------------------- src/plugins/irc/irc-server.c | 40 +++++++++++++++++++--------------- src/plugins/irc/irc-server.h | 5 ++--- src/plugins/irc/irc-upgrade.c | 12 +++++++--- 6 files changed, 49 insertions(+), 51 deletions(-) diff --git a/src/plugins/irc/irc-channel.c b/src/plugins/irc/irc-channel.c index 72bfaeeab..b184a5330 100644 --- a/src/plugins/irc/irc-channel.c +++ b/src/plugins/irc/irc-channel.c @@ -689,8 +689,8 @@ irc_channel_check_whox (struct t_irc_server *server, { if ((channel->type == IRC_CHANNEL_TYPE_CHANNEL) && channel->nicks) { - if (server->cap_away_notify - || server->cap_account_notify + if (weechat_hashtable_has_key (server->cap_list, "away-notify") + || weechat_hashtable_has_key (server->cap_list, "account-notify") || ((IRC_SERVER_OPTION_INTEGER(server, IRC_SERVER_OPTION_AWAY_CHECK) > 0) && ((IRC_SERVER_OPTION_INTEGER(server, IRC_SERVER_OPTION_AWAY_CHECK_MAX_NICKS) == 0) || (channel->nicks_count <= IRC_SERVER_OPTION_INTEGER(server, IRC_SERVER_OPTION_AWAY_CHECK_MAX_NICKS))))) diff --git a/src/plugins/irc/irc-nick.c b/src/plugins/irc/irc-nick.c index cf3b294c2..6559fc2ca 100644 --- a/src/plugins/irc/irc-nick.c +++ b/src/plugins/irc/irc-nick.c @@ -755,7 +755,7 @@ irc_nick_set_away (struct t_irc_server *server, struct t_irc_channel *channel, struct t_irc_nick *nick, int is_away) { if (!is_away - || server->cap_away_notify + || weechat_hashtable_has_key (server->cap_list, "away-notify") || ((IRC_SERVER_OPTION_INTEGER(server, IRC_SERVER_OPTION_AWAY_CHECK) > 0) && ((IRC_SERVER_OPTION_INTEGER(server, IRC_SERVER_OPTION_AWAY_CHECK_MAX_NICKS) == 0) || (channel->nicks_count <= IRC_SERVER_OPTION_INTEGER(server, IRC_SERVER_OPTION_AWAY_CHECK_MAX_NICKS))))) diff --git a/src/plugins/irc/irc-protocol.c b/src/plugins/irc/irc-protocol.c index 67b0109cd..de3717f28 100644 --- a/src/plugins/irc/irc-protocol.c +++ b/src/plugins/irc/irc-protocol.c @@ -207,11 +207,14 @@ IRC_PROTOCOL_CALLBACK(account) struct t_irc_channel *ptr_channel; struct t_irc_nick *ptr_nick; char *pos_account; + int cap_account_notify; IRC_PROTOCOL_MIN_ARGS(3); pos_account = (strcmp (argv[2], "*") != 0) ? argv[2] : NULL; + cap_account_notify = weechat_hashtable_has_key (server->cap_list, "account-notify"); + for (ptr_channel = server->channels; ptr_channel; ptr_channel = ptr_channel->next_channel) { @@ -220,7 +223,7 @@ IRC_PROTOCOL_CALLBACK(account) { if (ptr_nick->account) free (ptr_nick->account); - ptr_nick->account = (server->cap_account_notify && pos_account) ? + ptr_nick->account = (cap_account_notify && pos_account) ? strdup (pos_account) : NULL; } } @@ -478,23 +481,13 @@ IRC_PROTOCOL_CALLBACK(cap) { for (i = 0; i < num_caps_supported; i++) { + weechat_hashtable_set (server->cap_list, caps_supported[i], NULL); + if (strcmp (caps_supported[i], "sasl") == 0) { sasl_to_do = 1; break; } - else if (strcmp (caps_supported[i], "away-notify") == 0) - { - server->cap_away_notify = 1; - } - else if (strcmp (caps_supported[i], "account-notify") == 0) - { - server->cap_account_notify = 1; - } - else if (strcmp (caps_supported[i], "extended-join") == 0) - { - server->cap_extended_join = 1; - } } weechat_string_free_split (caps_supported); } @@ -620,14 +613,7 @@ IRC_PROTOCOL_CALLBACK(cap) { for (i = 0; i < num_caps_removed; i++) { - if (strcmp (caps_removed[i], "away-notify") == 0) - { - server->cap_away_notify = 0; - } - else if (strcmp (caps_removed[i], "account-notify") == 0) - { - server->cap_account_notify = 0; - } + weechat_hashtable_remove (server->cap_list, caps_removed[i]); } weechat_string_free_split (caps_removed); } @@ -4229,7 +4215,8 @@ IRC_PROTOCOL_CALLBACK(352) { if (ptr_nick->realname) free (ptr_nick->realname); - ptr_nick->realname = (pos_realname && server->cap_extended_join) ? + ptr_nick->realname = (pos_realname && + weechat_hashtable_has_key (server->cap_list, "extended-join")) ? strdup (pos_realname) : NULL; } @@ -4456,7 +4443,7 @@ IRC_PROTOCOL_CALLBACK(354) if (ptr_channel && ptr_nick) { if (pos_attr - && (server->cap_away_notify + && (weechat_hashtable_has_key (server->cap_list, "away-notify") || ((IRC_SERVER_OPTION_INTEGER( server, IRC_SERVER_OPTION_AWAY_CHECK) > 0) && ((IRC_SERVER_OPTION_INTEGER( @@ -4479,7 +4466,7 @@ IRC_PROTOCOL_CALLBACK(354) if (ptr_nick->account) free (ptr_nick->account); ptr_nick->account = (ptr_channel && pos_account - && server->cap_account_notify) ? + && weechat_hashtable_has_key (server->cap_list, "account-notify")) ? strdup (pos_account) : NULL; } @@ -4489,7 +4476,7 @@ IRC_PROTOCOL_CALLBACK(354) if (ptr_nick->realname) free (ptr_nick->realname); ptr_nick->realname = (ptr_channel && pos_realname - && server->cap_extended_join) ? + && weechat_hashtable_has_key (server->cap_list, "extended-join")) ? strdup (pos_realname) : NULL; } diff --git a/src/plugins/irc/irc-server.c b/src/plugins/irc/irc-server.c index 30f75d32f..7776175dd 100644 --- a/src/plugins/irc/irc-server.c +++ b/src/plugins/irc/irc-server.c @@ -1167,9 +1167,16 @@ irc_server_alloc (const char *name) new_server->nick_alternate_number = -1; new_server->nick = NULL; new_server->nick_modes = NULL; - new_server->cap_away_notify = 0; - new_server->cap_account_notify = 0; - new_server->cap_extended_join = 0; + new_server->cap_ls = weechat_hashtable_new (32, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING, + NULL, + NULL); + new_server->cap_list = weechat_hashtable_new (32, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING, + NULL, + NULL); new_server->isupport = NULL; new_server->prefix_modes = NULL; new_server->prefix_chars = NULL; @@ -3216,7 +3223,7 @@ irc_server_timer_cb (const void *pointer, void *data, int remaining_calls) /* check away (only if lag check was not done) */ away_check = IRC_SERVER_OPTION_INTEGER( ptr_server, IRC_SERVER_OPTION_AWAY_CHECK); - if (!ptr_server->cap_away_notify + if (!weechat_hashtable_has_key (ptr_server->cap_list, "away-notify") && (away_check > 0) && ((ptr_server->last_away_check == 0) || (current_time >= ptr_server->last_away_check + (away_check * 60)))) @@ -4889,9 +4896,8 @@ irc_server_disconnect (struct t_irc_server *server, int switch_address, weechat_bar_item_update ("input_prompt"); weechat_bar_item_update ("irc_nick_modes"); } - server->cap_away_notify = 0; - server->cap_account_notify = 0; - server->cap_extended_join = 0; + weechat_hashtable_remove_all (server->cap_ls); + weechat_hashtable_remove_all (server->cap_list); server->is_away = 0; server->away_time = 0; server->lag = 0; @@ -5440,9 +5446,8 @@ irc_server_hdata_server_cb (const void *pointer, void *data, WEECHAT_HDATA_VAR(struct t_irc_server, nick_alternate_number, INTEGER, 0, NULL, NULL); WEECHAT_HDATA_VAR(struct t_irc_server, nick, STRING, 0, NULL, NULL); WEECHAT_HDATA_VAR(struct t_irc_server, nick_modes, STRING, 0, NULL, NULL); - WEECHAT_HDATA_VAR(struct t_irc_server, cap_away_notify, INTEGER, 0, NULL, NULL); - WEECHAT_HDATA_VAR(struct t_irc_server, cap_account_notify, INTEGER, 0, NULL, NULL); - WEECHAT_HDATA_VAR(struct t_irc_server, cap_extended_join, INTEGER, 0, NULL, NULL); + WEECHAT_HDATA_VAR(struct t_irc_server, cap_ls, HASHTABLE, 0, NULL, NULL); + WEECHAT_HDATA_VAR(struct t_irc_server, cap_list, HASHTABLE, 0, NULL, NULL); WEECHAT_HDATA_VAR(struct t_irc_server, isupport, STRING, 0, NULL, NULL); WEECHAT_HDATA_VAR(struct t_irc_server, prefix_modes, STRING, 0, NULL, NULL); WEECHAT_HDATA_VAR(struct t_irc_server, prefix_chars, STRING, 0, NULL, NULL); @@ -5664,11 +5669,9 @@ irc_server_add_to_infolist (struct t_infolist *infolist, return 0; if (!weechat_infolist_new_var_string (ptr_item, "nick_modes", server->nick_modes)) return 0; - if (!weechat_infolist_new_var_integer (ptr_item, "cap_away_notify", server->cap_away_notify)) + if (!weechat_hashtable_add_to_infolist (server->cap_ls, ptr_item, "cap_ls")) return 0; - if (!weechat_infolist_new_var_integer (ptr_item, "cap_account_notify", server->cap_account_notify)) - return 0; - if (!weechat_infolist_new_var_integer (ptr_item, "cap_extended_join", server->cap_extended_join)) + if (!weechat_hashtable_add_to_infolist (server->cap_list, ptr_item, "cap_list")) return 0; if (!weechat_infolist_new_var_string (ptr_item, "isupport", server->isupport)) return 0; @@ -6048,9 +6051,12 @@ irc_server_print_log () weechat_log_printf (" nick_alternate_number: %d", ptr_server->nick_alternate_number); weechat_log_printf (" nick . . . . . . . . : '%s'", ptr_server->nick); weechat_log_printf (" nick_modes . . . . . : '%s'", ptr_server->nick_modes); - weechat_log_printf (" cap_away_notify. . . : %d", ptr_server->cap_away_notify); - weechat_log_printf (" cap_account_notify . : %d", ptr_server->cap_account_notify); - weechat_log_printf (" cap_extended_join. . : %d", ptr_server->cap_extended_join); + weechat_log_printf (" cap_ls . . . . . . . : 0x%lx (hashtable: '%s')", + ptr_server->cap_ls, + weechat_hashtable_get_string (ptr_server->cap_ls, "keys_values")); + weechat_log_printf (" cap_list . . . . . . : 0x%lx (hashtable: '%s')", + ptr_server->cap_list, + weechat_hashtable_get_string (ptr_server->cap_list, "keys_values")); weechat_log_printf (" isupport . . . . . . : '%s'", ptr_server->isupport); weechat_log_printf (" prefix_modes . . . . : '%s'", ptr_server->prefix_modes); weechat_log_printf (" prefix_chars . . . . : '%s'", ptr_server->prefix_chars); diff --git a/src/plugins/irc/irc-server.h b/src/plugins/irc/irc-server.h index 8c5fc4212..14593710f 100644 --- a/src/plugins/irc/irc-server.h +++ b/src/plugins/irc/irc-server.h @@ -188,9 +188,8 @@ struct t_irc_server /* (nick____1, nick____2, ...) */ char *nick; /* current nickname */ char *nick_modes; /* nick modes */ - int cap_away_notify; /* 1 if capability away-notify is enabled*/ - int cap_account_notify; /* 1 if CAP account-notify is enabled */ - int cap_extended_join; /* 1 if CAP extended-join is enabled */ + struct t_hashtable *cap_ls; /* list of supported capabilities */ + struct t_hashtable *cap_list; /* list of enabled capabilities */ char *isupport; /* copy of message 005 (ISUPPORT) */ char *prefix_modes; /* prefix modes from msg 005 (eg "ohv") */ char *prefix_chars; /* prefix chars from msg 005 (eg "@%+") */ diff --git a/src/plugins/irc/irc-upgrade.c b/src/plugins/irc/irc-upgrade.c index 0ec3b9e49..58f41e6cb 100644 --- a/src/plugins/irc/irc-upgrade.c +++ b/src/plugins/irc/irc-upgrade.c @@ -375,9 +375,15 @@ irc_upgrade_read_cb (const void *pointer, void *data, str = weechat_infolist_string (infolist, "nick_modes"); if (str) irc_upgrade_current_server->nick_modes = strdup (str); - irc_upgrade_current_server->cap_away_notify = weechat_infolist_integer (infolist, "cap_away_notify"); - irc_upgrade_current_server->cap_account_notify = weechat_infolist_integer (infolist, "cap_account_notify"); - irc_upgrade_current_server->cap_extended_join = weechat_infolist_integer (infolist, "cap_extended_join"); + /* TODO: "cap_list" is new in WeeChat x.y.z */ + if (weechat_infolist_integer (infolist, "cap_away_notify")) + weechat_hashtable_set (irc_upgrade_current_server->cap_list, "away-notify", NULL); + if (weechat_infolist_integer (infolist, "cap_account_notify")) + weechat_hashtable_set (irc_upgrade_current_server->cap_list, "account-notify", NULL); + if (weechat_infolist_integer (infolist, "cap_extended_join")) + weechat_hashtable_set (irc_upgrade_current_server->cap_list, "extended-join", NULL); + /* TODO: transfer all of "cap_ls" and "cap_list" */ + str = weechat_infolist_string (infolist, "isupport"); if (str) irc_upgrade_current_server->isupport = strdup (str); From bdfd984d72d6d8ac962d13d071bb5cedb137273c Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Sun, 13 Dec 2015 16:09:20 +0200 Subject: [PATCH 2/7] irc: add support for IRCv3.2 Client Capability Negotiation (closes #586) --- src/plugins/irc/irc-command.c | 2 +- src/plugins/irc/irc-protocol.c | 472 ++++++++++++++++++++++----------- src/plugins/irc/irc-server.c | 14 +- src/plugins/irc/irc-server.h | 2 + 4 files changed, 337 insertions(+), 153 deletions(-) diff --git a/src/plugins/irc/irc-command.c b/src/plugins/irc/irc-command.c index 3741687b2..12eafc35a 100644 --- a/src/plugins/irc/irc-command.c +++ b/src/plugins/irc/irc-command.c @@ -1223,7 +1223,7 @@ IRC_COMMAND_CALLBACK(cap) * enabled */ irc_server_sendf (ptr_server, IRC_SERVER_SEND_OUTQ_PRIO_HIGH, NULL, - "CAP LS"); + "CAP LS 302"); irc_server_sendf (ptr_server, IRC_SERVER_SEND_OUTQ_PRIO_HIGH, NULL, "CAP LIST"); } diff --git a/src/plugins/irc/irc-protocol.c b/src/plugins/irc/irc-protocol.c index de3717f28..1b4fce045 100644 --- a/src/plugins/irc/irc-protocol.c +++ b/src/plugins/irc/irc-protocol.c @@ -213,7 +213,8 @@ IRC_PROTOCOL_CALLBACK(account) pos_account = (strcmp (argv[2], "*") != 0) ? argv[2] : NULL; - cap_account_notify = weechat_hashtable_has_key (server->cap_list, "account-notify"); + cap_account_notify = weechat_hashtable_has_key (server->cap_list, + "account-notify"); for (ptr_channel = server->channels; ptr_channel; ptr_channel = ptr_channel->next_channel) @@ -332,6 +333,146 @@ IRC_PROTOCOL_CALLBACK(away) return WEECHAT_RC_OK; } +/* + * Callback for IRC server capabilities string length hashtable map. + */ + +void irc_protocol_cap_length_cb (void *data, + struct t_hashtable *hashtable, + const char *key, const char *value) +{ + int *length; + + /* make C compiler happy */ + (void) hashtable; + + length = (int*)data; + *length += 1 + strlen (key); // separator + key + if (value) + *length += 1 + strlen (value); // equals sign + value +} + +/* + * Callback for IRC server capabilities string hashtable map. + */ + +void irc_protocol_cap_print_cb (void *data, + struct t_hashtable *hashtable, + const char *key, const char *value) +{ + char *str, *pos; + + /* make C compiler happy */ + (void) hashtable; + + str = (char*)data; + pos = str + strlen (str); + + sprintf (pos, " %s%s%s", + key, + (value) ? "=" : "", + (value) ? value : ""); +} + +/* + * Synchronize requested capabilities for IRC server + */ + +void irc_protocol_cap_sync (struct t_irc_server *server, int sasl) +{ + char *cap_option, *cap_req, **caps_requested; + const char *ptr_cap_option; + int sasl_requested, sasl_to_do, sasl_fail; + int i, length, num_caps_requested; + + if (sasl) + { + sasl_requested = irc_server_sasl_enabled (server); + sasl_to_do = 0; + } + ptr_cap_option = IRC_SERVER_OPTION_STRING( + server, + IRC_SERVER_OPTION_CAPABILITIES); + length = ((ptr_cap_option && ptr_cap_option[0]) ? + strlen (ptr_cap_option) : 0) + 16; + cap_option = malloc (length); + cap_req = malloc (length); + if (cap_option && cap_req) + { + cap_option[0] = '\0'; + if (ptr_cap_option && ptr_cap_option[0]) + strcat (cap_option, ptr_cap_option); + if (sasl && sasl_requested) + { + if (cap_option[0]) + strcat (cap_option, ","); + strcat (cap_option, "sasl"); + } + cap_req[0] = '\0'; + caps_requested = weechat_string_split (cap_option, ",", 0, 0, + &num_caps_requested); + if (caps_requested) + { + for (i = 0; i < num_caps_requested; i++) + { + if (weechat_hashtable_has_key (server->cap_ls, + caps_requested[i]) && + !weechat_hashtable_has_key (server->cap_list, + caps_requested[i])) + { + if (sasl && strcmp (caps_requested[i], "sasl") == 0) + sasl_to_do = 1; + if (cap_req[0]) + strcat (cap_req, " "); + strcat (cap_req, caps_requested[i]); + } + } + weechat_string_free_split (caps_requested); + } + + if (cap_req[0]) + { + weechat_printf ( + server->buffer, + _("%s%s: client capability, requesting: %s"), + weechat_prefix ("network"), IRC_PLUGIN_NAME, + cap_req); + irc_server_sendf (server, 0, NULL, + "CAP REQ :%s", cap_req); + } + + if (sasl) + { + if (!sasl_to_do) + irc_server_sendf (server, 0, NULL, "CAP END"); + if (sasl_requested && !sasl_to_do) + { + weechat_printf ( + server->buffer, + _("%s%s: client capability: SASL not supported"), + weechat_prefix ("network"), IRC_PLUGIN_NAME); + + if (weechat_config_boolean (irc_config_network_sasl_fail_unavailable)) + { + /* same handling as for sasl_end_fail */ + sasl_fail = IRC_SERVER_OPTION_INTEGER(server, IRC_SERVER_OPTION_SASL_FAIL); + if ((sasl_fail == IRC_SERVER_SASL_FAIL_RECONNECT) + || (sasl_fail == IRC_SERVER_SASL_FAIL_DISCONNECT)) + { + irc_server_disconnect ( + server, 0, + (sasl_fail == IRC_SERVER_SASL_FAIL_RECONNECT) ? 1 : 0); + } + } + } + } + } + if (cap_option) + free (cap_option); + if (cap_req) + free (cap_req); +} + /* * Callback for the IRC message "CAP": client capability. * @@ -343,12 +484,12 @@ IRC_PROTOCOL_CALLBACK(away) IRC_PROTOCOL_CALLBACK(cap) { - char *ptr_caps, **caps_supported, **caps_requested, **caps_added; - char **caps_removed, *cap_option, *cap_req, str_msg_auth[512]; - const char *ptr_cap_option; - int num_caps_supported, num_caps_requested, num_caps_added; - int num_caps_removed, sasl_requested, sasl_to_do, sasl_mechanism; - int sasl_fail, i, j, timeout, length; + char *ptr_caps, **caps_supported, **caps_added, **caps_removed; + char **caps_enabled, *pos_value, *str_name, *str_caps; + char str_msg_auth[512]; + int num_caps_supported, num_caps_added, num_caps_removed; + int num_caps_enabled, sasl_to_do, sasl_mechanism; + int i, timeout, length, last_reply; IRC_PROTOCOL_MIN_ARGS(4); @@ -356,113 +497,168 @@ IRC_PROTOCOL_CALLBACK(cap) { if (argc > 4) { - ptr_caps = (argv_eol[4][0] == ':') ? argv_eol[4] + 1 : argv_eol[4]; - weechat_printf_date_tags ( - server->buffer, date, NULL, - _("%s%s: client capability, server supports: %s"), - weechat_prefix ("network"), - IRC_PLUGIN_NAME, - ptr_caps); - - /* auto-enable capabilities only when connecting to server */ - if (!server->is_connected) + if (argc > 5 && (strcmp (argv[4], "*") == 0)) { - sasl_requested = irc_server_sasl_enabled (server); - sasl_to_do = 0; - ptr_cap_option = IRC_SERVER_OPTION_STRING( - server, - IRC_SERVER_OPTION_CAPABILITIES); - length = ((ptr_cap_option && ptr_cap_option[0]) ? - strlen (ptr_cap_option) : 0) + 16; - cap_option = malloc (length); - cap_req = malloc (length); - if (cap_option && cap_req) - { - cap_option[0] = '\0'; - if (ptr_cap_option && ptr_cap_option[0]) - strcat (cap_option, ptr_cap_option); - if (sasl_requested) - { - if (cap_option[0]) - strcat (cap_option, ","); - strcat (cap_option, "sasl"); - } - cap_req[0] = '\0'; - caps_requested = weechat_string_split (cap_option, ",", 0, 0, - &num_caps_requested); - caps_supported = weechat_string_split (ptr_caps, " ", 0, 0, - &num_caps_supported); - if (caps_requested && caps_supported) - { - for (i = 0; i < num_caps_requested; i++) - { - for (j = 0; j < num_caps_supported; j++) - { - if (weechat_strcasecmp (caps_requested[i], - caps_supported[j]) == 0) - { - if (strcmp (caps_requested[i], "sasl") == 0) - sasl_to_do = 1; - if (cap_req[0]) - strcat (cap_req, " "); - strcat (cap_req, caps_supported[j]); - } - } - } - } - if (caps_requested) - weechat_string_free_split (caps_requested); - if (caps_supported) - weechat_string_free_split (caps_supported); - if (cap_req[0]) - { - weechat_printf ( - server->buffer, - _("%s%s: client capability, requesting: %s"), - weechat_prefix ("network"), IRC_PLUGIN_NAME, - cap_req); - irc_server_sendf (server, 0, NULL, - "CAP REQ :%s", cap_req); - } - if (!sasl_to_do) - irc_server_sendf (server, 0, NULL, "CAP END"); - if (sasl_requested && !sasl_to_do) - { - weechat_printf ( - server->buffer, - _("%s%s: client capability: SASL not supported"), - weechat_prefix ("network"), IRC_PLUGIN_NAME); + ptr_caps = argv_eol[5]; + last_reply = 0; + } + else + { + ptr_caps = argv_eol[4]; + last_reply = 1; + } - if (weechat_config_boolean (irc_config_network_sasl_fail_unavailable)) + if (!server->checking_cap_ls) + { + weechat_hashtable_remove_all (server->cap_ls); + server->checking_cap_ls = 1; + } + + if (last_reply) + server->checking_cap_ls = 0; + + if (ptr_caps[0] == ':') + ptr_caps++; + + caps_supported = weechat_string_split (ptr_caps, " ", 0, 0, + &num_caps_supported); + if (caps_supported) + { + for (i = 0; i < num_caps_supported; i++) + { + pos_value = strstr (caps_supported[i], "="); + if (pos_value) + { + str_name = strndup (caps_supported[i], + pos_value - caps_supported[i]); + if (str_name) { - /* same handling as for sasl_end_fail */ - sasl_fail = IRC_SERVER_OPTION_INTEGER(server, IRC_SERVER_OPTION_SASL_FAIL); - if ((sasl_fail == IRC_SERVER_SASL_FAIL_RECONNECT) - || (sasl_fail == IRC_SERVER_SASL_FAIL_DISCONNECT)) - { - irc_server_disconnect ( - server, 0, - (sasl_fail == IRC_SERVER_SASL_FAIL_RECONNECT) ? 1 : 0); - } + weechat_hashtable_set (server->cap_ls, + str_name, pos_value + 1); + free (str_name); } } + else + { + weechat_hashtable_set (server->cap_ls, + caps_supported[i], NULL); + } } - if (cap_option) - free (cap_option); - if (cap_req) - free (cap_req); } + + if (last_reply) + { + length = 0; + weechat_hashtable_map_string (server->cap_ls, + irc_protocol_cap_length_cb, + &length); + + str_caps = malloc (length + 1); + if (str_caps) + { + str_caps[0] = '\0'; + weechat_hashtable_map_string (server->cap_ls, + irc_protocol_cap_print_cb, + str_caps); + + weechat_printf_date_tags ( + server->buffer, date, NULL, + _("%s%s: client capability, server supports:%s"), + weechat_prefix ("network"), + IRC_PLUGIN_NAME, + str_caps); + free (str_caps); + } + } + + /* auto-enable capabilities only when connecting to server */ + if (last_reply && !server->is_connected) + irc_protocol_cap_sync (server, 1); + + if (caps_supported) + weechat_string_free_split (caps_supported); } } else if (strcmp (argv[3], "LIST") == 0) { if (argc > 4) { - ptr_caps = (argv_eol[4][0] == ':') ? argv_eol[4] + 1 : argv_eol[4]; - weechat_printf_date_tags ( - server->buffer, date, NULL, - _("%s%s: client capability, currently enabled: %s"), - weechat_prefix ("network"), IRC_PLUGIN_NAME, ptr_caps); + if (argc > 5 && (strcmp (argv[4], "*") == 0)) + { + ptr_caps = argv_eol[5]; + last_reply = 0; + } + else + { + ptr_caps = argv_eol[4]; + last_reply = 1; + } + + if (!server->checking_cap_list) + { + weechat_hashtable_remove_all (server->cap_list); + server->checking_cap_list = 1; + } + + if (last_reply) + server->checking_cap_list = 0; + + if (ptr_caps[0] == ':') + ptr_caps++; + + caps_enabled = weechat_string_split (ptr_caps, " ", 0, 0, + &num_caps_enabled); + if (caps_enabled) + { + for (i = 0; i < num_caps_enabled; i++) + { + pos_value = strstr (caps_enabled[i], "="); + if (pos_value) + { + str_name = strndup (caps_enabled[i], + pos_value - caps_enabled[i]); + if (str_name) + { + weechat_hashtable_set (server->cap_list, + str_name, pos_value + 1); + free (str_name); + } + } + else + { + weechat_hashtable_set (server->cap_list, + caps_enabled[i], NULL); + } + } + } + + + if (last_reply) + { + length = 0; + weechat_hashtable_map_string (server->cap_list, + irc_protocol_cap_length_cb, + &length); + + str_caps = malloc (length + 1); + if (str_caps) + { + str_caps[0] = '\0'; + weechat_hashtable_map_string (server->cap_list, + irc_protocol_cap_print_cb, + str_caps); + + weechat_printf_date_tags ( + server->buffer, date, NULL, + _("%s%s: client capability, currently enabled:%s"), + weechat_prefix ("network"), IRC_PLUGIN_NAME, str_caps); + free (str_caps); + } + } + + + if (caps_enabled) + weechat_string_free_split (caps_enabled); } } else if (strcmp (argv[3], "ACK") == 0) @@ -538,64 +734,37 @@ IRC_PROTOCOL_CALLBACK(cap) server->buffer, date, NULL, _("%s%s: client capability, now available: %s"), weechat_prefix ("network"), IRC_PLUGIN_NAME, ptr_caps); - - /* - * assume that we're not requesting any already-enabled - * capabilities - * TODO: SASL Reauthentication - */ - ptr_cap_option = IRC_SERVER_OPTION_STRING( - server, - IRC_SERVER_OPTION_CAPABILITIES); - length = ((ptr_cap_option && ptr_cap_option[0]) ? - strlen (ptr_cap_option) : 0) + 16; - cap_option = malloc (length); - cap_req = malloc (length); - if (cap_option && cap_req) + caps_added = weechat_string_split (ptr_caps, " ", 0, 0, + &num_caps_added); + if (caps_added) { - cap_option[0] = '\0'; - if (ptr_cap_option && ptr_cap_option[0]) - strcat (cap_option, ptr_cap_option); - cap_req[0] = '\0'; - caps_requested = weechat_string_split (cap_option, ",", 0, 0, - &num_caps_requested); - caps_added = weechat_string_split (ptr_caps, " ", 0, 0, - &num_caps_added); - if (caps_requested && caps_added) + for (i = 0; i < num_caps_added; i++) { - for (i = 0; i < num_caps_requested; i++) + pos_value = strstr (caps_added[i], "="); + if (pos_value) { - for (j = 0; j < num_caps_added; j++) + str_name = strndup (caps_added[i], + pos_value - caps_added[i]); + if (str_name) { - if (weechat_strcasecmp (caps_requested[i], - caps_added[j]) == 0) - { - if (cap_req[0]) - strcat (cap_req, " "); - strcat (cap_req, caps_added[j]); - } + weechat_hashtable_set (server->cap_ls, + str_name, pos_value + 1); + free (str_name); } } + else + { + weechat_hashtable_set (server->cap_ls, + caps_added[i], NULL); + } } - if (caps_requested) - weechat_string_free_split (caps_requested); - if (caps_added) - weechat_string_free_split (caps_added); - if (cap_req[0]) - { - weechat_printf ( - server->buffer, - _("%s%s: client capability, requesting: %s"), - weechat_prefix ("network"), IRC_PLUGIN_NAME, - cap_req); - irc_server_sendf (server, 0, NULL, - "CAP REQ :%s", cap_req); - } + weechat_string_free_split (caps_added); } - if (cap_option) - free (cap_option); - if (cap_req) - free (cap_req); + + /* + * TODO: SASL Reauthentication + */ + irc_protocol_cap_sync (server, 0); } } else if (strcmp (argv[3], "DEL") == 0) @@ -613,6 +782,7 @@ IRC_PROTOCOL_CALLBACK(cap) { for (i = 0; i < num_caps_removed; i++) { + weechat_hashtable_remove (server->cap_ls, caps_removed[i]); weechat_hashtable_remove (server->cap_list, caps_removed[i]); } weechat_string_free_split (caps_removed); diff --git a/src/plugins/irc/irc-server.c b/src/plugins/irc/irc-server.c index 7776175dd..b7783e0e3 100644 --- a/src/plugins/irc/irc-server.c +++ b/src/plugins/irc/irc-server.c @@ -1167,11 +1167,13 @@ irc_server_alloc (const char *name) new_server->nick_alternate_number = -1; new_server->nick = NULL; new_server->nick_modes = NULL; + new_server->checking_cap_ls = 0; new_server->cap_ls = weechat_hashtable_new (32, WEECHAT_HASHTABLE_STRING, WEECHAT_HASHTABLE_STRING, NULL, NULL); + new_server->checking_cap_list = 0; new_server->cap_list = weechat_hashtable_new (32, WEECHAT_HASHTABLE_STRING, WEECHAT_HASHTABLE_STRING, @@ -3542,7 +3544,7 @@ irc_server_login (struct t_irc_server *server) if (irc_server_sasl_enabled (server) || (capabilities && capabilities[0])) { - irc_server_sendf (server, 0, NULL, "CAP LS"); + irc_server_sendf (server, 0, NULL, "CAP LS 302"); } username2 = (username && username[0]) ? @@ -4896,7 +4898,9 @@ irc_server_disconnect (struct t_irc_server *server, int switch_address, weechat_bar_item_update ("input_prompt"); weechat_bar_item_update ("irc_nick_modes"); } + server->checking_cap_ls = 0; weechat_hashtable_remove_all (server->cap_ls); + server->checking_cap_list = 0; weechat_hashtable_remove_all (server->cap_list); server->is_away = 0; server->away_time = 0; @@ -5446,7 +5450,9 @@ irc_server_hdata_server_cb (const void *pointer, void *data, WEECHAT_HDATA_VAR(struct t_irc_server, nick_alternate_number, INTEGER, 0, NULL, NULL); WEECHAT_HDATA_VAR(struct t_irc_server, nick, STRING, 0, NULL, NULL); WEECHAT_HDATA_VAR(struct t_irc_server, nick_modes, STRING, 0, NULL, NULL); + WEECHAT_HDATA_VAR(struct t_irc_server, checking_cap_ls, INTEGER, 0, NULL, NULL); WEECHAT_HDATA_VAR(struct t_irc_server, cap_ls, HASHTABLE, 0, NULL, NULL); + WEECHAT_HDATA_VAR(struct t_irc_server, checking_cap_list, INTEGER, 0, NULL, NULL); WEECHAT_HDATA_VAR(struct t_irc_server, cap_list, HASHTABLE, 0, NULL, NULL); WEECHAT_HDATA_VAR(struct t_irc_server, isupport, STRING, 0, NULL, NULL); WEECHAT_HDATA_VAR(struct t_irc_server, prefix_modes, STRING, 0, NULL, NULL); @@ -5669,8 +5675,12 @@ irc_server_add_to_infolist (struct t_infolist *infolist, return 0; if (!weechat_infolist_new_var_string (ptr_item, "nick_modes", server->nick_modes)) return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "checking_cap_ls", server->checking_cap_ls)) + return 0; if (!weechat_hashtable_add_to_infolist (server->cap_ls, ptr_item, "cap_ls")) return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "checking_cap_list", server->checking_cap_list)) + return 0; if (!weechat_hashtable_add_to_infolist (server->cap_list, ptr_item, "cap_list")) return 0; if (!weechat_infolist_new_var_string (ptr_item, "isupport", server->isupport)) @@ -6051,9 +6061,11 @@ irc_server_print_log () weechat_log_printf (" nick_alternate_number: %d", ptr_server->nick_alternate_number); weechat_log_printf (" nick . . . . . . . . : '%s'", ptr_server->nick); weechat_log_printf (" nick_modes . . . . . : '%s'", ptr_server->nick_modes); + weechat_log_printf (" checking_cap_ls. . . : %d", ptr_server->checking_cap_ls); weechat_log_printf (" cap_ls . . . . . . . : 0x%lx (hashtable: '%s')", ptr_server->cap_ls, weechat_hashtable_get_string (ptr_server->cap_ls, "keys_values")); + weechat_log_printf (" checking_cap_list. . : %d", ptr_server->checking_cap_list); weechat_log_printf (" cap_list . . . . . . : 0x%lx (hashtable: '%s')", ptr_server->cap_list, weechat_hashtable_get_string (ptr_server->cap_list, "keys_values")); diff --git a/src/plugins/irc/irc-server.h b/src/plugins/irc/irc-server.h index 14593710f..df2c78718 100644 --- a/src/plugins/irc/irc-server.h +++ b/src/plugins/irc/irc-server.h @@ -188,7 +188,9 @@ struct t_irc_server /* (nick____1, nick____2, ...) */ char *nick; /* current nickname */ char *nick_modes; /* nick modes */ + int checking_cap_ls; /* 1 if checking supported capabilities */ struct t_hashtable *cap_ls; /* list of supported capabilities */ + int checking_cap_list; /* 1 if checking enabled capabilities */ struct t_hashtable *cap_list; /* list of enabled capabilities */ char *isupport; /* copy of message 005 (ISUPPORT) */ char *prefix_modes; /* prefix modes from msg 005 (eg "ohv") */ From 4563d43166ad13b1de9028db94d832a9e12a2b74 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Sun, 13 Dec 2015 16:12:28 +0200 Subject: [PATCH 3/7] irc: force uppercase subcommand for /cap --- src/plugins/irc/irc-command.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/plugins/irc/irc-command.c b/src/plugins/irc/irc-command.c index 12eafc35a..c09d77725 100644 --- a/src/plugins/irc/irc-command.c +++ b/src/plugins/irc/irc-command.c @@ -1201,6 +1201,8 @@ IRC_COMMAND_CALLBACK(ban) IRC_COMMAND_CALLBACK(cap) { + char *cap_cmd; + IRC_BUFFER_GET_SERVER(buffer); IRC_COMMAND_CHECK_SERVER("cap", 1); @@ -1210,11 +1212,27 @@ IRC_COMMAND_CALLBACK(cap) if (argc > 1) { - irc_server_sendf (ptr_server, IRC_SERVER_SEND_OUTQ_PRIO_HIGH, NULL, - "CAP %s%s%s", - argv[1], - (argv_eol[2]) ? " :" : "", - (argv_eol[2]) ? argv_eol[2] : ""); + cap_cmd = strdup (argv[1]); + if (!cap_cmd) + WEECHAT_COMMAND_ERROR; + + weechat_string_toupper (cap_cmd); + + if ((weechat_strcasecmp (argv[1], "ls") == 0) && !argv_eol[2]) + { + irc_server_sendf (ptr_server, IRC_SERVER_SEND_OUTQ_PRIO_HIGH, NULL, + "CAP LS 302"); + } + else + { + irc_server_sendf (ptr_server, IRC_SERVER_SEND_OUTQ_PRIO_HIGH, NULL, + "CAP %s%s%s", + cap_cmd, + (argv_eol[2]) ? " :" : "", + (argv_eol[2]) ? argv_eol[2] : ""); + } + + free (cap_cmd); } else { From 0a4be02dc368218f729eb118521885f30fa23a6d Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Sun, 13 Dec 2015 16:55:59 +0200 Subject: [PATCH 4/7] core: add hashtable_add_from_infolist to API --- doc/en/weechat_plugin_api.en.adoc | 45 +++++++++++++++ src/core/wee-hashtable.c | 92 ++++++++++++++++++++++++++++++ src/core/wee-hashtable.h | 4 ++ src/plugins/plugin.c | 1 + src/plugins/weechat-plugin.h | 10 +++- tests/unit/core/test-hashtable.cpp | 1 + 6 files changed, 152 insertions(+), 1 deletion(-) diff --git a/doc/en/weechat_plugin_api.en.adoc b/doc/en/weechat_plugin_api.en.adoc index 4fb28a02c..bce4692bd 100644 --- a/doc/en/weechat_plugin_api.en.adoc +++ b/doc/en/weechat_plugin_api.en.adoc @@ -4846,6 +4846,51 @@ weechat_hashtable_add_to_infolist (hashtable, infolist_item, "testhash"); [NOTE] This function is not available in scripting API. +==== hashtable_add_from_infolist + +_WeeChat ≥ x.y.z._ + +Add hashtable items from an infolist. + +Prototype: + +[source,C] +---- +int weechat_hashtable_add_from_infolist (struct t_hashtable *hashtable, + struct t_infolist *infolist, + const char *prefix); +---- + +Arguments: + +* 'hashtable': hashtable pointer +* 'infolist': infolist pointer +* 'prefix': string used as prefix for names in infolist + +Return value: + +* 1 if OK, 0 if error + +C example: + +[source,C] +---- +weechat_hashtable_add_from_infolist (hashtable, infolist, "testhash"); + +/* if infolist contains: + "testhash_name_00000" = "key1" + "testhash_value_00000" = "value 1" + "testhash_name_00001" = "key2" + "testhash_value_00001" = "value 2" + then following variables will be added to hashtable: + "key1" => "value 1" + "key2" => "value 2" +*/ +---- + +[NOTE] +This function is not available in scripting API. + ==== hashtable_remove _WeeChat ≥ 0.3.3._ diff --git a/src/core/wee-hashtable.c b/src/core/wee-hashtable.c index 15ebd14c4..d9f480c42 100644 --- a/src/core/wee-hashtable.c +++ b/src/core/wee-hashtable.c @@ -1062,6 +1062,8 @@ hashtable_add_to_infolist (struct t_hashtable *hashtable, hashtable_to_string (hashtable->type_keys, ptr_item->key))) return 0; + /* TODO: implement other key types */ + snprintf (option_name, sizeof (option_name), "%s_value_%05d", prefix, item_number); switch (hashtable->type_values) @@ -1101,6 +1103,96 @@ hashtable_add_to_infolist (struct t_hashtable *hashtable, return 1; } +/* + * Adds hashtable keys and values from an infolist. + * + * Returns: + * 1: OK + * 0: error + */ + +int +hashtable_add_from_infolist (struct t_hashtable *hashtable, + struct t_infolist *infolist, + const char *prefix) +{ + struct t_infolist_item *infolist_item; + struct t_infolist_var *ptr_name, *ptr_value; + void *value; + char prefix_name[128], option_value[128]; + int prefix_length; + + if (!hashtable || !infolist || !prefix) + return 0; + + infolist_item = infolist->ptr_item; + if (!infolist_item) + return 0; + + if (hashtable->type_keys != HASHTABLE_STRING) + return 0; + /* TODO: implement other key types */ + + snprintf (prefix_name, sizeof (prefix_name), + "%s_name_", prefix); + prefix_length = strlen (prefix_name); + + for (ptr_name = infolist_item->vars; ptr_name; ptr_name = ptr_name->next_var) + { + if (string_strncasecmp (ptr_name->name, prefix_name, prefix_length) == 0) + { + snprintf (option_value, sizeof (option_value), + "%s_value_%s", prefix, ptr_name->name + prefix_length); + + for (ptr_value = infolist_item->vars; ptr_value; ptr_value = ptr_value->next_var) + { + if (string_strcasecmp (ptr_value->name, option_value) == 0) + { + switch (hashtable->type_values) + { + case HASHTABLE_INTEGER: + if (ptr_value->type != INFOLIST_INTEGER) + return 0; + + value = ptr_value->value; + break; + case HASHTABLE_STRING: + if (ptr_value->type != INFOLIST_STRING) + return 0; + + value = ptr_value->value; + break; + case HASHTABLE_POINTER: + if (ptr_value->type != INFOLIST_POINTER) + return 0; + + value = ptr_value->value; + break; + case HASHTABLE_BUFFER: + if (ptr_value->type != INFOLIST_BUFFER) + return 0; + + value = ptr_value->value; /* TODO: implement size */ + break; + case HASHTABLE_TIME: + if (ptr_value->type != INFOLIST_TIME) + return 0; + + value = ptr_value->value; + break; + case HASHTABLE_NUM_TYPES: + break; + } + hashtable_set (hashtable, ptr_name->value, value); + break; + } + } + } + } + + return 1; +} + /* * Removes an item from hashtable. */ diff --git a/src/core/wee-hashtable.h b/src/core/wee-hashtable.h index 38706d7cb..2ea414574 100644 --- a/src/core/wee-hashtable.h +++ b/src/core/wee-hashtable.h @@ -22,6 +22,7 @@ struct t_hashtable; struct t_infolist_item; +struct t_infolist; typedef unsigned long long (t_hashtable_hash_key)(struct t_hashtable *hashtable, const void *key); @@ -149,6 +150,9 @@ extern void hashtable_set_pointer (struct t_hashtable *hashtable, extern int hashtable_add_to_infolist (struct t_hashtable *hashtable, struct t_infolist_item *infolist_item, const char *prefix); +extern int hashtable_add_from_infolist (struct t_hashtable *hashtable, + struct t_infolist *infolist, + const char *prefix); extern void hashtable_remove (struct t_hashtable *hashtable, const void *key); extern void hashtable_remove_all (struct t_hashtable *hashtable); extern void hashtable_free (struct t_hashtable *hashtable); diff --git a/src/plugins/plugin.c b/src/plugins/plugin.c index 6d9d6583a..1d4e104ee 100644 --- a/src/plugins/plugin.c +++ b/src/plugins/plugin.c @@ -711,6 +711,7 @@ plugin_load (const char *filename, int init_plugin, int argc, char **argv) new_plugin->hashtable_get_string = &hashtable_get_string; new_plugin->hashtable_set_pointer = &hashtable_set_pointer; new_plugin->hashtable_add_to_infolist = &hashtable_add_to_infolist; + new_plugin->hashtable_add_from_infolist = &hashtable_add_from_infolist; new_plugin->hashtable_remove = &hashtable_remove; new_plugin->hashtable_remove_all = &hashtable_remove_all; new_plugin->hashtable_free = &hashtable_free; diff --git a/src/plugins/weechat-plugin.h b/src/plugins/weechat-plugin.h index a78db2cd6..4ac49d11e 100644 --- a/src/plugins/weechat-plugin.h +++ b/src/plugins/weechat-plugin.h @@ -66,7 +66,7 @@ struct timeval; * please change the date with current one; for a second change at same * date, increment the 01, otherwise please keep 01. */ -#define WEECHAT_PLUGIN_API_VERSION "20170530-02" +#define WEECHAT_PLUGIN_API_VERSION "20170617-01" /* macros for defining plugin infos */ #define WEECHAT_PLUGIN_NAME(__name) \ @@ -465,6 +465,9 @@ struct t_weechat_plugin int (*hashtable_add_to_infolist) (struct t_hashtable *hashtable, struct t_infolist_item *infolist_item, const char *prefix); + int (*hashtable_add_from_infolist) (struct t_hashtable *hashtable, + struct t_infolist *infolist, + const char *prefix); void (*hashtable_remove) (struct t_hashtable *hashtable, const void *key); void (*hashtable_remove_all) (struct t_hashtable *hashtable); void (*hashtable_free) (struct t_hashtable *hashtable); @@ -1396,6 +1399,11 @@ extern int weechat_plugin_end (struct t_weechat_plugin *plugin); (weechat_plugin->hashtable_add_to_infolist)(__hashtable, \ __infolist_item, \ __prefix) +#define weechat_hashtable_add_from_infolist(__hashtable, __infolist, \ + __prefix) \ + (weechat_plugin->hashtable_add_from_infolist)(__hashtable, \ + __infolist, \ + __prefix) #define weechat_hashtable_remove(__hashtable, __key) \ (weechat_plugin->hashtable_remove)(__hashtable, __key) #define weechat_hashtable_remove_all(__hashtable) \ diff --git a/tests/unit/core/test-hashtable.cpp b/tests/unit/core/test-hashtable.cpp index dd33d9a40..1201d7996 100644 --- a/tests/unit/core/test-hashtable.cpp +++ b/tests/unit/core/test-hashtable.cpp @@ -359,6 +359,7 @@ TEST(Hashtable, Properties) /* * Tests functions: * hashtable_add_to_infolist + * hashtable_add_from_infolist */ TEST(Hashtable, Infolist) From 08da7c658649b8564e9017cb64bfa7de92383c5b Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Sun, 13 Dec 2015 16:56:18 +0200 Subject: [PATCH 5/7] irc: implement capability upgrading fully --- src/plugins/irc/irc-upgrade.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/plugins/irc/irc-upgrade.c b/src/plugins/irc/irc-upgrade.c index 58f41e6cb..098132514 100644 --- a/src/plugins/irc/irc-upgrade.c +++ b/src/plugins/irc/irc-upgrade.c @@ -375,14 +375,26 @@ irc_upgrade_read_cb (const void *pointer, void *data, str = weechat_infolist_string (infolist, "nick_modes"); if (str) irc_upgrade_current_server->nick_modes = strdup (str); - /* TODO: "cap_list" is new in WeeChat x.y.z */ + /* "cap_ls" and "cap_list" replace "cap_away_notify" and "cap_account_notify" in WeeChat x.y.z */ if (weechat_infolist_integer (infolist, "cap_away_notify")) + { + weechat_hashtable_set (irc_upgrade_current_server->cap_ls, "away-notify", NULL); weechat_hashtable_set (irc_upgrade_current_server->cap_list, "away-notify", NULL); + } if (weechat_infolist_integer (infolist, "cap_account_notify")) + { + weechat_hashtable_set (irc_upgrade_current_server->cap_ls, "account-notify", NULL); weechat_hashtable_set (irc_upgrade_current_server->cap_list, "account-notify", NULL); + } if (weechat_infolist_integer (infolist, "cap_extended_join")) + { + weechat_hashtable_set (irc_upgrade_current_server->cap_ls, "extended-join", NULL); weechat_hashtable_set (irc_upgrade_current_server->cap_list, "extended-join", NULL); - /* TODO: transfer all of "cap_ls" and "cap_list" */ + } + weechat_hashtable_add_from_infolist ( + irc_upgrade_current_server->cap_ls, infolist, "cap_ls"); + weechat_hashtable_add_from_infolist ( + irc_upgrade_current_server->cap_list, infolist, "cap_list"); str = weechat_infolist_string (infolist, "isupport"); if (str) From 1af75739b5e4fa6aeb4cf0d4c674b057fc98024d Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Sun, 13 Dec 2015 19:44:06 +0200 Subject: [PATCH 6/7] core: implement buffer type in hashtable_add_from_infolist --- src/core/wee-hashtable.c | 79 +++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 46 deletions(-) diff --git a/src/core/wee-hashtable.c b/src/core/wee-hashtable.c index d9f480c42..508c30892 100644 --- a/src/core/wee-hashtable.c +++ b/src/core/wee-hashtable.c @@ -1116,19 +1116,13 @@ hashtable_add_from_infolist (struct t_hashtable *hashtable, struct t_infolist *infolist, const char *prefix) { - struct t_infolist_item *infolist_item; struct t_infolist_var *ptr_name, *ptr_value; - void *value; char prefix_name[128], option_value[128]; int prefix_length; if (!hashtable || !infolist || !prefix) return 0; - infolist_item = infolist->ptr_item; - if (!infolist_item) - return 0; - if (hashtable->type_keys != HASHTABLE_STRING) return 0; /* TODO: implement other key types */ @@ -1137,55 +1131,48 @@ hashtable_add_from_infolist (struct t_hashtable *hashtable, "%s_name_", prefix); prefix_length = strlen (prefix_name); - for (ptr_name = infolist_item->vars; ptr_name; ptr_name = ptr_name->next_var) + for (ptr_name = infolist->ptr_item->vars; ptr_name; ptr_name = ptr_name->next_var) { if (string_strncasecmp (ptr_name->name, prefix_name, prefix_length) == 0) { snprintf (option_value, sizeof (option_value), "%s_value_%s", prefix, ptr_name->name + prefix_length); - for (ptr_value = infolist_item->vars; ptr_value; ptr_value = ptr_value->next_var) + ptr_value = infolist_search_var (infolist, option_value); + if (ptr_value) { - if (string_strcasecmp (ptr_value->name, option_value) == 0) + switch (hashtable->type_values) { - switch (hashtable->type_values) - { - case HASHTABLE_INTEGER: - if (ptr_value->type != INFOLIST_INTEGER) - return 0; - - value = ptr_value->value; - break; - case HASHTABLE_STRING: - if (ptr_value->type != INFOLIST_STRING) - return 0; - - value = ptr_value->value; - break; - case HASHTABLE_POINTER: - if (ptr_value->type != INFOLIST_POINTER) - return 0; - - value = ptr_value->value; - break; - case HASHTABLE_BUFFER: - if (ptr_value->type != INFOLIST_BUFFER) - return 0; - - value = ptr_value->value; /* TODO: implement size */ - break; - case HASHTABLE_TIME: - if (ptr_value->type != INFOLIST_TIME) - return 0; - - value = ptr_value->value; - break; - case HASHTABLE_NUM_TYPES: - break; - } - hashtable_set (hashtable, ptr_name->value, value); - break; + case HASHTABLE_INTEGER: + if (ptr_value->type != INFOLIST_INTEGER) + return 0; + break; + case HASHTABLE_STRING: + if (ptr_value->type != INFOLIST_STRING) + return 0; + break; + case HASHTABLE_POINTER: + if (ptr_value->type != INFOLIST_POINTER) + return 0; + break; + case HASHTABLE_BUFFER: + if (ptr_value->type != INFOLIST_BUFFER) + return 0; + break; + case HASHTABLE_TIME: + if (ptr_value->type != INFOLIST_TIME) + return 0; + break; + case HASHTABLE_NUM_TYPES: + break; } + if (hashtable->type_values == HASHTABLE_BUFFER) + { + hashtable_set_with_size (hashtable, ptr_name->value, 0, + ptr_value->value, ptr_value->size); + } + else + hashtable_set (hashtable, ptr_name->value, ptr_value->value); } } } From 0a348f0b9dd31fe8546e61d445f23b44a26d1abf Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 17 Feb 2016 13:26:00 +0200 Subject: [PATCH 7/7] irc: factor supported CAP version --- src/plugins/irc/irc-command.c | 4 ++-- src/plugins/irc/irc-server.c | 2 +- src/plugins/irc/irc-server.h | 3 +++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/plugins/irc/irc-command.c b/src/plugins/irc/irc-command.c index c09d77725..bb40e000d 100644 --- a/src/plugins/irc/irc-command.c +++ b/src/plugins/irc/irc-command.c @@ -1221,7 +1221,7 @@ IRC_COMMAND_CALLBACK(cap) if ((weechat_strcasecmp (argv[1], "ls") == 0) && !argv_eol[2]) { irc_server_sendf (ptr_server, IRC_SERVER_SEND_OUTQ_PRIO_HIGH, NULL, - "CAP LS 302"); + "CAP LS " IRC_SERVER_VERSION_CAP); } else { @@ -1241,7 +1241,7 @@ IRC_COMMAND_CALLBACK(cap) * enabled */ irc_server_sendf (ptr_server, IRC_SERVER_SEND_OUTQ_PRIO_HIGH, NULL, - "CAP LS 302"); + "CAP LS " IRC_SERVER_VERSION_CAP); irc_server_sendf (ptr_server, IRC_SERVER_SEND_OUTQ_PRIO_HIGH, NULL, "CAP LIST"); } diff --git a/src/plugins/irc/irc-server.c b/src/plugins/irc/irc-server.c index b7783e0e3..dd785c29a 100644 --- a/src/plugins/irc/irc-server.c +++ b/src/plugins/irc/irc-server.c @@ -3544,7 +3544,7 @@ irc_server_login (struct t_irc_server *server) if (irc_server_sasl_enabled (server) || (capabilities && capabilities[0])) { - irc_server_sendf (server, 0, NULL, "CAP LS 302"); + irc_server_sendf (server, 0, NULL, "CAP LS " IRC_SERVER_VERSION_CAP); } username2 = (username && username[0]) ? diff --git a/src/plugins/irc/irc-server.h b/src/plugins/irc/irc-server.h index df2c78718..74987e675 100644 --- a/src/plugins/irc/irc-server.h +++ b/src/plugins/irc/irc-server.h @@ -121,6 +121,9 @@ enum t_irc_server_option #define IRC_SERVER_SEND_OUTQ_PRIO_LOW 2 #define IRC_SERVER_SEND_RETURN_HASHTABLE 4 +/* version strings */ +#define IRC_SERVER_VERSION_CAP "302" + /* casemapping (string comparisons for nicks/channels) */ enum t_irc_server_casemapping {