From 0b7ee1e683b55610379d7d4ee8da8ddfd0b49ffe Mon Sep 17 00:00:00 2001 From: defanor Date: Fri, 27 Mar 2020 17:44:20 +0300 Subject: Add optional roster caching --- examples/basic.c | 2 ++ src/rexmpp.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++-------- src/rexmpp.h | 1 + 3 files changed, 60 insertions(+), 9 deletions(-) diff --git a/examples/basic.c b/examples/basic.c index 38ddbc3..61eeb7a 100644 --- a/examples/basic.c +++ b/examples/basic.c @@ -84,6 +84,8 @@ main () { /* "foo.custom.crt", */ /* GNUTLS_X509_FMT_PEM); */ + s.roster_cache_file = "roster.xml"; + do { if (n > 0 && FD_ISSET(STDIN_FILENO, &read_fds)) { diff --git a/src/rexmpp.c b/src/rexmpp.c index 7edcb1f..51229b7 100644 --- a/src/rexmpp.c +++ b/src/rexmpp.c @@ -82,6 +82,7 @@ rexmpp_err_t rexmpp_init (rexmpp_t *s, s->enable_carbons = 1; s->enable_service_discovery = 1; s->manage_roster = 1; + s->roster_cache_file = NULL; s->send_buffer = NULL; s->send_queue = NULL; s->server_srv = NULL; @@ -1153,6 +1154,47 @@ rexmpp_err_t rexmpp_modify_roster (rexmpp_t *s, xmlNodePtr item) { return ret; } +void rexmpp_roster_set (rexmpp_t *s, xmlNodePtr query) { + if (s->roster_items != NULL) { + xmlFreeNodeList(s->roster_items); + } + if (s->roster_ver != NULL) { + free(s->roster_ver); + } + s->roster_ver = xmlGetProp(query, "ver"); + s->roster_items = xmlCopyNodeList(xmlFirstElementChild(query)); +} + +void rexmpp_roster_cache_read (rexmpp_t *s) { + if (s->roster_cache_file == NULL) { + rexmpp_log(s, LOG_WARNING, "No roster cache file path is set."); + return; + } + xmlDocPtr doc = xmlReadFile(s->roster_cache_file, "utf-8", XML_PARSE_NONET); + xmlNodePtr query = xmlDocGetRootElement(doc); + rexmpp_roster_set(s, query); + xmlFreeDoc(doc); +} + +void rexmpp_roster_cache_write (rexmpp_t *s) { + if (s->roster_cache_file == NULL) { + rexmpp_log(s, LOG_WARNING, "No roster cache file path is set."); + return; + } + xmlDocPtr doc = xmlNewDoc("1.0"); + xmlNodePtr query = xmlNewDocNode(doc, NULL, "query", NULL); + xmlDocSetRootElement(doc, query); + xmlNewNs(query, "jabber:iq:roster", NULL); + if (s->roster_ver != NULL) { + xmlNewProp(query, "ver", s->roster_ver); + } + if (s->roster_items != NULL) { + xmlAddChild(query, xmlDocCopyNodeList(doc, s->roster_items)); + } + xmlSaveFileEnc(s->roster_cache_file, doc, "utf-8"); + xmlFreeDoc(doc); +} + void rexmpp_iq_roster_get (rexmpp_t *s, xmlNodePtr req, xmlNodePtr response, @@ -1164,17 +1206,13 @@ void rexmpp_iq_roster_get (rexmpp_t *s, } xmlNodePtr query = xmlFirstElementChild(response); if (! rexmpp_xml_match(query, "jabber:iq:roster", "query")) { - rexmpp_log(s, LOG_WARNING, "No roster query found."); + rexmpp_log(s, LOG_DEBUG, "No roster query in reply."); return; } - if (s->roster_items != NULL) { - xmlFreeNodeList(s->roster_items); + rexmpp_roster_set(s, query); + if (s->roster_cache_file != NULL) { + rexmpp_roster_cache_write(s); } - if (s->roster_ver != NULL) { - free(s->roster_ver); - } - s->roster_ver = xmlGetProp(query, "ver"); - s->roster_items = xmlFirstElementChild(query); } void rexmpp_stream_is_ready(rexmpp_t *s) { @@ -1188,6 +1226,9 @@ void rexmpp_stream_is_ready(rexmpp_t *s) { disco_query, rexmpp_iq_discovery_info); } if (s->manage_roster) { + if (s->roster_cache_file != NULL) { + rexmpp_roster_cache_read(s); + } xmlNodePtr roster_query = xmlNewNode(NULL, "query"); xmlNewNs(roster_query, "jabber:iq:roster", NULL); if (s->roster_ver != NULL) { @@ -1245,7 +1286,7 @@ void rexmpp_stream_bind (rexmpp_t *s) { rexmpp_iq_new(s, "set", NULL, bind_cmd, rexmpp_bound); } -void rexmpp_process_element(rexmpp_t *s) { +void rexmpp_process_element (rexmpp_t *s) { xmlNodePtr elem = s->current_element; /* IQs */ @@ -1299,9 +1340,16 @@ void rexmpp_process_element(rexmpp_t *s) { if (s->manage_roster && rexmpp_xml_match(query, "jabber:iq:roster", "query")) { /* Roster push. */ + if (s->roster_ver != NULL) { + free(s->roster_ver); + } + s->roster_ver = xmlGetProp(query, "ver"); rexmpp_modify_roster(s, xmlFirstElementChild(query)); /* todo: check for errors */ rexmpp_iq_reply(s, elem, "result", NULL); + if (s->roster_cache_file != NULL) { + rexmpp_roster_cache_write(s); + } } } free(type); diff --git a/src/rexmpp.h b/src/rexmpp.h index 43c715c..c7b07b0 100644 --- a/src/rexmpp.h +++ b/src/rexmpp.h @@ -233,6 +233,7 @@ struct rexmpp int enable_carbons; int enable_service_discovery; int manage_roster; + const char *roster_cache_file; /* Resource limits. */ uint32_t stanza_queue_size; -- cgit v1.2.3