From fc3ac84c2fa091d12c2034f06b227618e76c1226 Mon Sep 17 00:00:00 2001 From: defanor Date: Sun, 5 Jul 2020 22:28:44 +0300 Subject: Add presence tracking Presence of roster contacts is tracked by rexmpp now (optionally, by default), and the weechat plugin marks online contacts with the "+" prefix. --- src/rexmpp.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'src/rexmpp.c') diff --git a/src/rexmpp.c b/src/rexmpp.c index c4c1e1c..deee805 100644 --- a/src/rexmpp.c +++ b/src/rexmpp.c @@ -238,6 +238,7 @@ rexmpp_err_t rexmpp_init (rexmpp_t *s, const char *jid) s->enable_service_discovery = 1; s->manage_roster = 1; s->roster_cache_file = NULL; + s->track_roster_presence = 1; s->send_buffer = NULL; s->send_queue = NULL; s->server_srv = NULL; @@ -250,6 +251,7 @@ rexmpp_err_t rexmpp_init (rexmpp_t *s, const char *jid) s->stream_features = NULL; s->roster_items = NULL; s->roster_ver = NULL; + s->roster_presence = NULL; s->stanza_queue = NULL; s->stream_id = NULL; s->active_iq = NULL; @@ -419,6 +421,10 @@ void rexmpp_done (rexmpp_t *s) { xmlFreeNodeList(s->roster_items); s->roster_items = NULL; } + if (s->roster_presence != NULL) { + xmlFreeNodeList(s->roster_presence); + s->roster_presence = NULL; + } if (s->roster_ver != NULL) { free(s->roster_ver); s->roster_ver = NULL; @@ -1493,6 +1499,62 @@ void rexmpp_process_element (rexmpp_t *s) { free(type); } + /* Incoming presence information. */ + if (rexmpp_xml_match(elem, "jabber:client", "presence") && + s->manage_roster && + s->track_roster_presence) { + char *from = xmlGetProp(elem, "from"); + if (from != NULL) { + size_t i; + int resource_removed = 0; + for (i = 0; i < strlen(from); i++) { + if (from[i] == '/') { + from[i] = '\0'; + resource_removed = i; + break; + } + } + if (rexmpp_roster_find_item(s, from, NULL) != NULL) { + /* The bare JID is in the roster. */ + if (resource_removed) { + /* Restore full JID. */ + from[resource_removed] = '/'; + } + char *type = xmlGetProp(elem, "type"); + xmlNodePtr cur, prev; + if (type == NULL || strcmp(type, "unavailable") == 0) { + /* Either a new "available" presence or an "unavailable" + one: remove the previously stored presence for this + JID. */ + for (prev = NULL, cur = s->roster_presence; + cur != NULL; + prev = cur, cur = xmlNextElementSibling(cur)) { + char *cur_from = xmlGetProp(cur, "from"); + if (strcmp(cur_from, from) == 0) { + if (prev == NULL) { + s->roster_presence = cur->next; + } else { + prev->next = cur->next; + } + xmlFreeNode(cur); + cur = NULL; + } + free(cur_from); + } + } + if (type == NULL) { + /* An "available" presence: add it. */ + xmlNodePtr presence = xmlCopyNode(elem, 1); + presence->next = s->roster_presence; + s->roster_presence = presence; + } else { + free(type); + } + } + free(from); + } + } + /* Stream negotiation, https://tools.ietf.org/html/rfc6120#section-4.3 */ if (s->stream_state == REXMPP_STREAM_NEGOTIATION && -- cgit v1.2.3