diff options
author | James Booth <boothj5@gmail.com> | 2013-01-28 22:24:47 +0000 |
---|---|---|
committer | James Booth <boothj5@gmail.com> | 2013-01-28 22:24:47 +0000 |
commit | 7255ef5e1c03aa09ebffc8636a0b49a76ff3f07a (patch) | |
tree | f2608b7828e95ca193dd5ee9218f8dd9c5940b2f | |
parent | cb24ba8be175e0ddde93a0e01c286ee7cab2b241 (diff) | |
download | profani-tty-7255ef5e1c03aa09ebffc8636a0b49a76ff3f07a.tar.gz |
Added xmpp_presence.c
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | src/command.c | 8 | ||||
-rw-r--r-- | src/muc.h | 2 | ||||
-rw-r--r-- | src/xmpp.h | 13 | ||||
-rw-r--r-- | src/xmpp_conn.c | 301 | ||||
-rw-r--r-- | src/xmpp_presence.c | 324 |
6 files changed, 360 insertions, 290 deletions
diff --git a/Makefile.am b/Makefile.am index 846f9bd0..66e599f2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5,7 +5,7 @@ profanity_SOURCES = src/command.c src/contact.c src/command_history.c src/xmpp.h src/autocomplete.h src/ui_titlebar.c src/ui_windows.c src/common.c \ src/contact_list.c src/ui_inputwin.c src/log.h src/profanity.c \ src/history.c src/ui.h src/common.h src/ contact_list.h src/xmpp_conn.c \ - src/main.c src/profanity.h src/history.h \ + src/main.c src/profanity.h src/history.h src/xmpp_presence.c \ src/tinyurl.c src/tinyurl.h src/chat_session.c \ src/chat_session.h src/muc.c \ src/muc.h src/xmpp_stanza.c src/command_parser.c \ diff --git a/src/command.c b/src/command.c index 0d590b1f..c3701d3f 100644 --- a/src/command.c +++ b/src/command.c @@ -1206,7 +1206,7 @@ _cmd_sub(gchar **args, struct cmd_help_t help) } if (strcmp(subcmd, "received") == 0) { - GList *received = jabber_get_subscription_requests(); + GList *received = presence_get_subscription_requests(); if (received == NULL) { cons_show("No outstanding subscription requests."); @@ -1236,15 +1236,15 @@ _cmd_sub(gchar **args, struct cmd_help_t help) bare_jid = strtok(jid, "/"); if (strcmp(subcmd, "allow") == 0) { - jabber_subscription(bare_jid, PRESENCE_SUBSCRIBED); + presence_subscription(bare_jid, PRESENCE_SUBSCRIBED); cons_show("Accepted subscription for %s", bare_jid); log_info("Accepted subscription for %s", bare_jid); } else if (strcmp(subcmd, "deny") == 0) { - jabber_subscription(bare_jid, PRESENCE_UNSUBSCRIBED); + presence_subscription(bare_jid, PRESENCE_UNSUBSCRIBED); cons_show("Deleted/denied subscription for %s", bare_jid); log_info("Deleted/denied subscription for %s", bare_jid); } else if (strcmp(subcmd, "request") == 0) { - jabber_subscription(bare_jid, PRESENCE_SUBSCRIBE); + presence_subscription(bare_jid, PRESENCE_SUBSCRIBE); cons_show("Sent subscription request to %s.", bare_jid); log_info("Sent subscription request to %s.", bare_jid); } else if (strcmp(subcmd, "show") == 0) { diff --git a/src/muc.h b/src/muc.h index efd637fd..f2685b96 100644 --- a/src/muc.h +++ b/src/muc.h @@ -26,6 +26,8 @@ #include <glib.h> #include "autocomplete.h" +#include "contact.h" +#include "jid.h" void muc_join_room(const char * const room, const char * const nick); void muc_leave_room(const char * const room); diff --git a/src/xmpp.h b/src/xmpp.h index 4d8d9898..b8356729 100644 --- a/src/xmpp.h +++ b/src/xmpp.h @@ -149,8 +149,6 @@ void jabber_process_events(void); void jabber_join(Jid *jid); void jabber_change_room_nick(const char * const room, const char * const nick); void jabber_leave_chat_room(const char * const room_jid); -void jabber_subscription(const char * const jid, jabber_subscr_t action); -GList* jabber_get_subscription_requests(void); void jabber_send(const char * const msg, const char * const recipient); void jabber_send_groupchat(const char * const msg, const char * const recipient); void jabber_send_inactive(const char * const recipient); @@ -167,10 +165,21 @@ char * jabber_get_status(void); void jabber_free_resources(void); void jabber_restart(void); void jabber_set_autoping(int seconds); +xmpp_conn_t *jabber_get_conn(void); +xmpp_ctx_t *jabber_get_ctx(void); +int error_handler(xmpp_stanza_t * const stanza); // iq functions void iq_add_handlers(xmpp_conn_t * const conn, xmpp_ctx_t * const ctx); +// presence functions +void presence_init(void); +void presence_subscription(const char * const jid, const jabber_subscr_t action); +GList* presence_get_subscription_requests(void); +void presence_free_sub_requests(void); +int presence_handler(xmpp_conn_t * const conn, + xmpp_stanza_t * const stanza, void * const userdata); + // caps functions void caps_init(void); void caps_add(const char * const caps_str, const char * const client); diff --git a/src/xmpp_conn.c b/src/xmpp_conn.c index 07e592e7..52ded632 100644 --- a/src/xmpp_conn.c +++ b/src/xmpp_conn.c @@ -47,8 +47,6 @@ static struct _jabber_conn_t { int priority; } jabber_conn; -static GHashTable *sub_requests; - // for auto reconnect static struct { char *name; @@ -85,13 +83,9 @@ static void _connection_handler(xmpp_conn_t * const conn, static int _message_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _groupchat_message_handler(xmpp_stanza_t * const stanza); -static int _error_handler(xmpp_stanza_t * const stanza); static int _chat_message_handler(xmpp_stanza_t * const stanza); -static int _presence_handler(xmpp_conn_t * const conn, - xmpp_stanza_t * const stanza, void * const userdata); static int _ping_timed_handler(xmpp_conn_t * const conn, void * const userdata); -static char * _handle_presence_caps(xmpp_stanza_t * const stanza); void jabber_init(const int disable_tls) @@ -101,7 +95,7 @@ jabber_init(const int disable_tls) jabber_conn.presence = PRESENCE_OFFLINE; jabber_conn.status = NULL; jabber_conn.tls_disabled = disable_tls; - sub_requests = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + presence_init(); } void @@ -325,43 +319,6 @@ jabber_send_gone(const char * const recipient) } void -jabber_subscription(const char * const jid, jabber_subscr_t action) -{ - xmpp_stanza_t *presence; - char *type, *jid_cpy, *bare_jid; - - // jid must be a bare JID - jid_cpy = strdup(jid); - bare_jid = strtok(jid_cpy, "/"); - g_hash_table_remove(sub_requests, bare_jid); - - if (action == PRESENCE_SUBSCRIBE) - type = STANZA_TYPE_SUBSCRIBE; - else if (action == PRESENCE_SUBSCRIBED) - type = STANZA_TYPE_SUBSCRIBED; - else if (action == PRESENCE_UNSUBSCRIBED) - type = STANZA_TYPE_UNSUBSCRIBED; - else { // unknown action - free(jid_cpy); - return; - } - - presence = xmpp_stanza_new(jabber_conn.ctx); - xmpp_stanza_set_name(presence, STANZA_NAME_PRESENCE); - xmpp_stanza_set_type(presence, type); - xmpp_stanza_set_attribute(presence, STANZA_ATTR_TO, bare_jid); - xmpp_send(jabber_conn.conn, presence); - xmpp_stanza_release(presence); - free(jid_cpy); -} - -GList * -jabber_get_subscription_requests(void) -{ - return g_hash_table_get_keys(sub_requests); -} - -void jabber_join(Jid *jid) { xmpp_stanza_t *presence = stanza_create_room_join_presence(jabber_conn.ctx, @@ -524,6 +481,18 @@ jabber_get_connection_status(void) return (jabber_conn.conn_status); } +xmpp_conn_t * +jabber_get_conn(void) +{ + return jabber_conn.conn; +} + +xmpp_ctx_t * +jabber_get_ctx(void) +{ + return jabber_conn.ctx; +} + const char * jabber_get_jid(void) { @@ -559,8 +528,7 @@ jabber_free_resources(void) FREE_SET_NULL(saved_account.name); FREE_SET_NULL(saved_account.passwd); chat_sessions_clear(); - if (sub_requests != NULL) - g_hash_table_remove_all(sub_requests); + presence_free_sub_requests(); xmpp_conn_release(jabber_conn.conn); xmpp_ctx_free(jabber_conn.ctx); xmpp_shutdown(); @@ -584,7 +552,7 @@ _message_handler(xmpp_conn_t * const conn, log_error("Message stanza received with no type attribute"); return 1; } else if (strcmp(type, STANZA_TYPE_ERROR) == 0) { - return _error_handler(stanza); + return error_handler(stanza); } else if (strcmp(type, STANZA_TYPE_GROUPCHAT) == 0) { return _groupchat_message_handler(stanza); } else if (strcmp(type, STANZA_TYPE_CHAT) == 0) { @@ -661,8 +629,8 @@ _groupchat_message_handler(xmpp_stanza_t * const stanza) return 1; } -static int -_error_handler(xmpp_stanza_t * const stanza) +int +error_handler(xmpp_stanza_t * const stanza) { gchar *err_msg = NULL; gchar *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); @@ -811,7 +779,7 @@ _connection_handler(xmpp_conn_t * const conn, chat_sessions_init(); xmpp_handler_add(conn, _message_handler, NULL, STANZA_NAME_MESSAGE, NULL, ctx); - xmpp_handler_add(conn, _presence_handler, NULL, STANZA_NAME_PRESENCE, NULL, ctx); + xmpp_handler_add(conn, presence_handler, NULL, STANZA_NAME_PRESENCE, NULL, ctx); iq_add_handlers(conn, ctx); @@ -877,239 +845,6 @@ _ping_timed_handler(xmpp_conn_t * const conn, void * const userdata) return 1; } -static int -_room_presence_handler(const char * const jid, xmpp_stanza_t * const stanza) -{ - char *room = NULL; - char *nick = NULL; - - if (!parse_room_jid(jid, &room, &nick)) { - log_error("Could not parse room jid: %s", room); - return 1; - } - - // handle self presence - if (stanza_is_muc_self_presence(stanza, jabber_get_jid())) { - char *type = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_TYPE); - gboolean nick_change = stanza_is_room_nick_change(stanza); - - if ((type != NULL) && (strcmp(type, STANZA_TYPE_UNAVAILABLE) == 0)) { - - // leave room if not self nick change - if (nick_change) { - muc_set_room_pending_nick_change(room); - } else { - prof_handle_leave_room(room); - } - - // handle self nick change - } else if (muc_is_room_pending_nick_change(room)) { - muc_complete_room_nick_change(room, nick); - prof_handle_room_nick_change(room, nick); - - // handle roster complete - } else if (!muc_get_roster_received(room)) { - prof_handle_room_roster_complete(room); - - } - - // handle presence from room members - } else { - char *type = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_TYPE); - char *show_str, *status_str; - char *caps_key = _handle_presence_caps(stanza); - - xmpp_stanza_t *status = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_STATUS); - if (status != NULL) { - status_str = xmpp_stanza_get_text(status); - } else { - status_str = NULL; - } - - if ((type != NULL) && (strcmp(type, STANZA_TYPE_UNAVAILABLE) == 0)) { - - // handle nickname change - if (stanza_is_room_nick_change(stanza)) { - char *new_nick = stanza_get_new_nick(stanza); - muc_set_roster_pending_nick_change(room, new_nick, nick); - } else { - prof_handle_room_member_offline(room, nick, "offline", status_str); - } - } else { - xmpp_stanza_t *show = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_SHOW); - if (show != NULL) { - show_str = xmpp_stanza_get_text(show); - } else { - show_str = "online"; - } - if (!muc_get_roster_received(room)) { - muc_add_to_roster(room, nick, show_str, status_str, caps_key); - } else { - char *old_nick = muc_complete_roster_nick_change(room, nick); - - if (old_nick != NULL) { - muc_add_to_roster(room, nick, show_str, status_str, caps_key); - prof_handle_room_member_nick_change(room, old_nick, nick); - } else { - if (!muc_nick_in_roster(room, nick)) { - prof_handle_room_member_online(room, nick, show_str, status_str, caps_key); - } else { - prof_handle_room_member_presence(room, nick, show_str, status_str, caps_key); - } - } - } - } - } - - free(room); - free(nick); - - return 1; -} - -static char * -_handle_presence_caps(xmpp_stanza_t * const stanza) -{ - char *caps_key = NULL; - char *node = NULL; - char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); - if (stanza_contains_caps(stanza)) { - char *hash_type = stanza_caps_get_hash(stanza); - - // xep-0115 - if (hash_type != NULL) { - - // supported hash - if (strcmp(hash_type, "sha-1") == 0) { - node = stanza_get_caps_str(stanza); - caps_key = node; - - if (node != NULL) { - if (!caps_contains(caps_key)) { - xmpp_stanza_t *iq = stanza_create_disco_iq(jabber_conn.ctx, "disco", from, node); - xmpp_send(jabber_conn.conn, iq); - xmpp_stanza_release(iq); - } - } - - // unsupported hash - } else { - node = stanza_get_caps_str(stanza); - caps_key = from; - - if (node != NULL) { - if (!caps_contains(caps_key)) { - GString *id = g_string_new("disco_"); - g_string_append(id, from); - xmpp_stanza_t *iq = stanza_create_disco_iq(jabber_conn.ctx, id->str, from, node); - xmpp_send(jabber_conn.conn, iq); - xmpp_stanza_release(iq); - g_string_free(id, TRUE); - } - } - } - - return strdup(caps_key); - - //ignore or handle legacy caps - } else { - node = stanza_get_caps_str(stanza); - caps_key = from; - - if (node != NULL) { - if (!caps_contains(caps_key)) { - GString *id = g_string_new("disco_"); - g_string_append(id, from); - xmpp_stanza_t *iq = stanza_create_disco_iq(jabber_conn.ctx, id->str, from, node); - xmpp_send(jabber_conn.conn, iq); - xmpp_stanza_release(iq); - g_string_free(id, TRUE); - } - } - - return caps_key; - } - } - return NULL; -} - -static int -_presence_handler(xmpp_conn_t * const conn, - xmpp_stanza_t * const stanza, void * const userdata) -{ - const char *jid = xmpp_conn_get_jid(jabber_conn.conn); - char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); - char *type = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_TYPE); - - Jid *my_jid = jid_create(jid); - Jid *from_jid = jid_create(from); - - if ((type != NULL) && (strcmp(type, STANZA_TYPE_ERROR) == 0)) { - return _error_handler(stanza); - } - - // handle chat room presence - if (muc_room_is_active(from_jid)) { - return _room_presence_handler(from_jid->str, stanza); - - // handle regular presence - } else { - char *type = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_TYPE); - char *show_str, *status_str; - int idle_seconds = stanza_get_idle_time(stanza); - GDateTime *last_activity = NULL; - - if (idle_seconds > 0) { - GDateTime *now = g_date_time_new_now_local(); - last_activity = g_date_time_add_seconds(now, 0 - idle_seconds); - g_date_time_unref(now); - } - - char *caps_key = _handle_presence_caps(stanza); - - xmpp_stanza_t *status = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_STATUS); - if (status != NULL) - status_str = xmpp_stanza_get_text(status); - else - status_str = NULL; - - if (type == NULL) { // available - xmpp_stanza_t *show = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_SHOW); - if (show != NULL) - show_str = xmpp_stanza_get_text(show); - else - show_str = "online"; - - if (strcmp(my_jid->barejid, from_jid->barejid) !=0) { - prof_handle_contact_online(from_jid->barejid, show_str, status_str, last_activity, caps_key); - } - } else if (strcmp(type, STANZA_TYPE_UNAVAILABLE) == 0) { - if (strcmp(my_jid->barejid, from_jid->barejid) !=0) { - prof_handle_contact_offline(from_jid->barejid, "offline", status_str); - } - - if (last_activity != NULL) { - g_date_time_unref(last_activity); - } - - // subscriptions - } else if (strcmp(type, STANZA_TYPE_SUBSCRIBE) == 0) { - prof_handle_subscription(from_jid->barejid, PRESENCE_SUBSCRIBE); - g_hash_table_insert(sub_requests, strdup(from_jid->barejid), strdup(from_jid->barejid)); - } else if (strcmp(type, STANZA_TYPE_SUBSCRIBED) == 0) { - prof_handle_subscription(from_jid->barejid, PRESENCE_SUBSCRIBED); - g_hash_table_remove(sub_requests, from_jid->barejid); - } else if (strcmp(type, STANZA_TYPE_UNSUBSCRIBED) == 0) { - prof_handle_subscription(from_jid->barejid, PRESENCE_UNSUBSCRIBED); - g_hash_table_remove(sub_requests, from_jid->barejid); - } else { /* unknown type */ - log_debug("Received presence with unknown type '%s'", type); - } - } - - return 1; -} - static log_level_t _get_log_level(xmpp_log_level_t xmpp_level) { diff --git a/src/xmpp_presence.c b/src/xmpp_presence.c new file mode 100644 index 00000000..aa5dcad3 --- /dev/null +++ b/src/xmpp_presence.c @@ -0,0 +1,324 @@ +/* + * xmpp_presence.c + * + * Copyright (C) 2012, 2013 James Booth <boothj5@gmail.com> + * + * This file is part of Profanity. + * + * Profanity is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Profanity is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Profanity. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <stdlib.h> +#include <string.h> + +#include <glib.h> + +#include "log.h" +#include "muc.h" +#include "profanity.h" +#include "xmpp.h" + +static GHashTable *sub_requests; +static char* _handle_presence_caps(xmpp_stanza_t * const stanza); +static int _room_presence_handler(const char * const jid, + xmpp_stanza_t * const stanza); + +void +presence_init(void) +{ + sub_requests = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); +} + +void +presence_subscription(const char * const jid, const jabber_subscr_t action) +{ + xmpp_ctx_t *ctx = jabber_get_ctx(); + xmpp_conn_t *conn = jabber_get_conn(); + xmpp_stanza_t *presence; + char *type, *jid_cpy, *bare_jid; + + // jid must be a bare JID + jid_cpy = strdup(jid); + bare_jid = strtok(jid_cpy, "/"); + g_hash_table_remove(sub_requests, bare_jid); + + if (action == PRESENCE_SUBSCRIBE) + type = STANZA_TYPE_SUBSCRIBE; + else if (action == PRESENCE_SUBSCRIBED) + type = STANZA_TYPE_SUBSCRIBED; + else if (action == PRESENCE_UNSUBSCRIBED) + type = STANZA_TYPE_UNSUBSCRIBED; + else { // unknown action + free(jid_cpy); + return; + } + + presence = xmpp_stanza_new(ctx); + xmpp_stanza_set_name(presence, STANZA_NAME_PRESENCE); + xmpp_stanza_set_type(presence, type); + xmpp_stanza_set_attribute(presence, STANZA_ATTR_TO, bare_jid); + xmpp_send(conn, presence); + xmpp_stanza_release(presence); + free(jid_cpy); +} + +GList * +presence_get_subscription_requests(void) +{ + return g_hash_table_get_keys(sub_requests); +} + +void +presence_free_sub_requests(void) +{ + if (sub_requests != NULL) + g_hash_table_remove_all(sub_requests); +} + +int +presence_handler(xmpp_conn_t * const conn, + xmpp_stanza_t * const stanza, void * const userdata) +{ + const char *jid = xmpp_conn_get_jid(conn); + char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); + char *type = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_TYPE); + + Jid *my_jid = jid_create(jid); + Jid *from_jid = jid_create(from); + + if ((type != NULL) && (strcmp(type, STANZA_TYPE_ERROR) == 0)) { + return error_handler(stanza); + } + + // handle chat room presence + if (muc_room_is_active(from_jid)) { + return _room_presence_handler(from_jid->str, stanza); + + // handle regular presence + } else { + char *type = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_TYPE); + char *show_str, *status_str; + int idle_seconds = stanza_get_idle_time(stanza); + GDateTime *last_activity = NULL; + + if (idle_seconds > 0) { + GDateTime *now = g_date_time_new_now_local(); + last_activity = g_date_time_add_seconds(now, 0 - idle_seconds); + g_date_time_unref(now); + } + + char *caps_key = _handle_presence_caps(stanza); + + xmpp_stanza_t *status = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_STATUS); + if (status != NULL) + status_str = xmpp_stanza_get_text(status); + else + status_str = NULL; + + if (type == NULL) { // available + xmpp_stanza_t *show = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_SHOW); + if (show != NULL) + show_str = xmpp_stanza_get_text(show); + else + show_str = "online"; + + if (strcmp(my_jid->barejid, from_jid->barejid) !=0) { + prof_handle_contact_online(from_jid->barejid, show_str, status_str, last_activity, caps_key); + } + } else if (strcmp(type, STANZA_TYPE_UNAVAILABLE) == 0) { + if (strcmp(my_jid->barejid, from_jid->barejid) !=0) { + prof_handle_contact_offline(from_jid->barejid, "offline", status_str); + } + + if (last_activity != NULL) { + g_date_time_unref(last_activity); + } + + // subscriptions + } else if (strcmp(type, STANZA_TYPE_SUBSCRIBE) == 0) { + prof_handle_subscription(from_jid->barejid, PRESENCE_SUBSCRIBE); + g_hash_table_insert(sub_requests, strdup(from_jid->barejid), strdup(from_jid->barejid)); + } else if (strcmp(type, STANZA_TYPE_SUBSCRIBED) == 0) { + prof_handle_subscription(from_jid->barejid, PRESENCE_SUBSCRIBED); + g_hash_table_remove(sub_requests, from_jid->barejid); + } else if (strcmp(type, STANZA_TYPE_UNSUBSCRIBED) == 0) { + prof_handle_subscription(from_jid->barejid, PRESENCE_UNSUBSCRIBED); + g_hash_table_remove(sub_requests, from_jid->barejid); + } else { /* unknown type */ + log_debug("Received presence with unknown type '%s'", type); + } + } + + return 1; +} + +static char * +_handle_presence_caps(xmpp_stanza_t * const stanza) +{ + xmpp_ctx_t *ctx = jabber_get_ctx(); + xmpp_conn_t *conn = jabber_get_conn(); + char *caps_key = NULL; + char *node = NULL; + char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); + if (stanza_contains_caps(stanza)) { + char *hash_type = stanza_caps_get_hash(stanza); + + // xep-0115 + if (hash_type != NULL) { + + // supported hash + if (strcmp(hash_type, "sha-1") == 0) { + node = stanza_get_caps_str(stanza); + caps_key = node; + + if (node != NULL) { + if (!caps_contains(caps_key)) { + xmpp_stanza_t *iq = stanza_create_disco_iq(ctx, "disco", from, node); + xmpp_send(conn, iq); + xmpp_stanza_release(iq); + } + } + + // unsupported hash + } else { + node = stanza_get_caps_str(stanza); + caps_key = from; + + if (node != NULL) { + if (!caps_contains(caps_key)) { + GString *id = g_string_new("disco_"); + g_string_append(id, from); + xmpp_stanza_t *iq = stanza_create_disco_iq(ctx, id->str, from, node); + xmpp_send(conn, iq); + xmpp_stanza_release(iq); + g_string_free(id, TRUE); + } + } + } + + return strdup(caps_key); + + //ignore or handle legacy caps + } else { + node = stanza_get_caps_str(stanza); + caps_key = from; + + if (node != NULL) { + if (!caps_contains(caps_key)) { + GString *id = g_string_new("disco_"); + g_string_append(id, from); + xmpp_stanza_t *iq = stanza_create_disco_iq(ctx, id->str, from, node); + xmpp_send(conn, iq); + xmpp_stanza_release(iq); + g_string_free(id, TRUE); + } + } + + return caps_key; + } + } + return NULL; +} + +static int +_room_presence_handler(const char * const jid, xmpp_stanza_t * const stanza) +{ + char *room = NULL; + char *nick = NULL; + + if (!parse_room_jid(jid, &room, &nick)) { + log_error("Could not parse room jid: %s", room); + return 1; + } + + // handle self presence + if (stanza_is_muc_self_presence(stanza, jabber_get_jid())) { + char *type = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_TYPE); + gboolean nick_change = stanza_is_room_nick_change(stanza); + + if ((type != NULL) && (strcmp(type, STANZA_TYPE_UNAVAILABLE) == 0)) { + + // leave room if not self nick change + if (nick_change) { + muc_set_room_pending_nick_change(room); + } else { + prof_handle_leave_room(room); + } + + // handle self nick change + } else if (muc_is_room_pending_nick_change(room)) { + muc_complete_room_nick_change(room, nick); + prof_handle_room_nick_change(room, nick); + + // handle roster complete + } else if (!muc_get_roster_received(room)) { + prof_handle_room_roster_complete(room); + + } + + // handle presence from room members + } else { + char *type = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_TYPE); + char *show_str, *status_str; + char *caps_key = _handle_presence_caps(stanza); + + xmpp_stanza_t *status = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_STATUS); + if (status != NULL) { + status_str = xmpp_stanza_get_text(status); + } else { + status_str = NULL; + } + + if ((type != NULL) && (strcmp(type, STANZA_TYPE_UNAVAILABLE) == 0)) { + + // handle nickname change + if (stanza_is_room_nick_change(stanza)) { + char *new_nick = stanza_get_new_nick(stanza); + muc_set_roster_pending_nick_change(room, new_nick, nick); + } else { + prof_handle_room_member_offline(room, nick, "offline", status_str); + } + } else { + xmpp_stanza_t *show = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_SHOW); + if (show != NULL) { + show_str = xmpp_stanza_get_text(show); + } else { + show_str = "online"; + } + if (!muc_get_roster_received(room)) { + muc_add_to_roster(room, nick, show_str, status_str, caps_key); + } else { + char *old_nick = muc_complete_roster_nick_change(room, nick); + + if (old_nick != NULL) { + muc_add_to_roster(room, nick, show_str, status_str, caps_key); + prof_handle_room_member_nick_change(room, old_nick, nick); + } else { + if (!muc_nick_in_roster(room, nick)) { + prof_handle_room_member_online(room, nick, show_str, status_str, caps_key); + } else { + prof_handle_room_member_presence(room, nick, show_str, status_str, caps_key); + } + } + } + } + } + + free(room); + free(nick); + + return 1; +} + |