summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordefanor <defanor@uberspace.net>2020-03-27 17:44:20 +0300
committerdefanor <defanor@uberspace.net>2020-03-27 17:44:20 +0300
commit0b7ee1e683b55610379d7d4ee8da8ddfd0b49ffe (patch)
tree89042c86341ea32b25689fa28f8467f145b83477
parent6e1b2af71d8b281042481c8b32e03bb13538f446 (diff)
Add optional roster caching
-rw-r--r--examples/basic.c2
-rw-r--r--src/rexmpp.c66
-rw-r--r--src/rexmpp.h1
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;