From 8a3bc36ae7c893e2c25047d2187339a0c4d4327c Mon Sep 17 00:00:00 2001 From: defanor Date: Fri, 20 Nov 2020 22:26:41 +0300 Subject: Handle XEP-0402: PEP Native Bookmarks --- README | 2 +- examples/weechat.c | 61 +++++++++++++++++++++++----------------- src/rexmpp.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++----- src/rexmpp.h | 11 ++++---- src/rexmpp_openpgp.c | 11 +++++--- src/rexmpp_openpgp.h | 2 +- 6 files changed, 123 insertions(+), 43 deletions(-) diff --git a/README b/README index 36b9daa..111a7bf 100644 --- a/README +++ b/README @@ -63,7 +63,7 @@ A rough roadmap: [+] XEP-0115: Entity Capabilities (including into initial presence) [+] XEP-0172: User Nickname [+] XEP-0373: OpenPGP for XMPP -[ ] XEP-0402: PEP Native Bookmarks (autojoin conferences) +[+] XEP-0402: PEP Native Bookmarks (autojoin conferences) [ ] XEP-0166: Jingle [ ] XEP-0234: Jingle File Transfer [ ] XEP-0261: Jingle In-Band Bytestreams Transport Method diff --git a/examples/weechat.c b/examples/weechat.c index b314c58..904e711 100644 --- a/examples/weechat.c +++ b/examples/weechat.c @@ -47,7 +47,7 @@ struct weechat_rexmpp { struct weechat_rexmpp_muc { struct weechat_rexmpp *wr; - char *jid; + struct rexmpp_jid jid; }; struct t_weechat_plugin *weechat_plugin = NULL; @@ -117,9 +117,8 @@ int muc_input_cb (const void *ptr, void *data, { struct weechat_rexmpp_muc *wrm = (void*)ptr; rexmpp_t *s = &wrm->wr->rexmpp_state; - const char *to = weechat_buffer_get_string(buffer, "name"); xmlNodePtr msg = rexmpp_xml_add_id(s, xmlNewNode(NULL, "message")); - xmlNewProp(msg, "to", to); + xmlNewProp(msg, "to", wrm->jid.bare); xmlNewProp(msg, "type", "groupchat"); xmlNewTextChild(msg, NULL, "body", input_data); rexmpp_send(s, msg); @@ -133,7 +132,7 @@ int muc_close_cb (const void *ptr, void *data, rexmpp_t *s = &wrm->wr->rexmpp_state; xmlNodePtr presence = rexmpp_xml_add_id(s, xmlNewNode(NULL, "presence")); xmlNewProp(presence, "from", s->assigned_jid.full); - xmlNewProp(presence, "to", wrm->jid); + xmlNewProp(presence, "to", wrm->jid.full); xmlNewProp(presence, "type", "unavailable"); rexmpp_send(s, presence); free(wrm); @@ -212,7 +211,37 @@ int my_xml_in_cb (rexmpp_t *s, xmlNodePtr node) { rexmpp_jid_parse(from, &from_jid); xmlFree(from); - if (rexmpp_xml_find_child(node, "http://jabber.org/protocol/muc#user", "x")) { + xmlNodePtr muc = + rexmpp_xml_find_child(node, "http://jabber.org/protocol/muc#user", "x"); + if (muc != NULL) { + + /* Handle newly joined MUCs */ + if (presence_type == NULL) { + xmlNodePtr status = + rexmpp_xml_find_child(muc, "http://jabber.org/protocol/muc#user", + "status"); + if (status != NULL) { + char *code = xmlGetProp(status, "code"); + if (code != NULL) { + if (strcmp(code, "110") == 0) { + struct weechat_rexmpp_muc *wrm = + malloc(sizeof(struct weechat_rexmpp_muc)); + wrm->wr = wr; + rexmpp_jid_parse(from_jid.full, &(wrm->jid)); + struct t_gui_buffer *buf = + weechat_buffer_search("rexmpp", wrm->jid.bare); + if (buf == NULL) { + buf = weechat_buffer_new (wrm->jid.bare, + &muc_input_cb, wrm, NULL, + &muc_close_cb, wrm, NULL); + weechat_buffer_set(buf, "nicklist", "1"); + } + } + free(code); + } + } + } + /* Update MUC nicklist */ struct t_gui_buffer *buf = weechat_buffer_search("rexmpp", from_jid.bare); if (buf != NULL) { @@ -304,7 +333,7 @@ my_input_cb (const void *ptr, void *data, weechat_buffer_set(buf, "nicklist", "1"); } } else if (input_data[0] == 'j' && input_data[1] == ' ') { - char *jid = strdup(input_data + 2); + const char *jid = input_data + 2; xmlNodePtr presence = rexmpp_xml_add_id(s, xmlNewNode(NULL, "presence")); xmlNewProp(presence, "from", s->assigned_jid.full); xmlNewProp(presence, "to", jid); @@ -312,24 +341,6 @@ my_input_cb (const void *ptr, void *data, xmlNewNs(x, "http://jabber.org/protocol/muc", NULL); xmlAddChild(presence, x); rexmpp_send(s, presence); - int i; - struct weechat_rexmpp_muc *wrm = malloc(sizeof(struct weechat_rexmpp_muc)); - wrm->wr = wr; - wrm->jid = strdup(jid); - for (i = 0; i < strlen(jid); i++) { - if (jid[i] == '/') { - jid[i] = 0; - break; - } - } - struct t_gui_buffer *buf = weechat_buffer_search("rexmpp", jid); - if (buf == NULL) { - buf = weechat_buffer_new (jid, - &muc_input_cb, wrm, NULL, - &muc_close_cb, wrm, NULL); - weechat_buffer_set(buf, "nicklist", "1"); - } - free(jid); } return WEECHAT_RC_OK; } @@ -471,7 +482,7 @@ command_sc_cb (const void *wr_ptr, void *data, xmlNewNs(body, "jabber:client", NULL); xmlNodeAddContent(body, argv_eol[1]); - char *rcpt[3]; + const char *rcpt[2]; rcpt[0] = to; rcpt[1] = NULL; diff --git a/src/rexmpp.c b/src/rexmpp.c index 14d8159..c84eb5d 100644 --- a/src/rexmpp.c +++ b/src/rexmpp.c @@ -257,7 +257,7 @@ char *rexmpp_get_name (rexmpp_t *s, const char *jid_str) { "http://jabber.org/protocol/nick", "nick"); if (nick != NULL) { - return strdup(xmlNodeGetContent(nick)); + return xmlNodeGetContent(nick); } } } @@ -302,6 +302,11 @@ xmlNodePtr rexmpp_disco_info (rexmpp_t *s) { prev->next = cur; prev = cur; } + if (s->autojoin_bookmarked_mucs) { + cur = rexmpp_xml_feature("urn:xmpp:bookmarks:1+notify"); + prev->next = cur; + prev = cur; + } if (s->retrieve_openpgp_keys) { cur = rexmpp_xml_feature("urn:xmpp:openpgp:0:public-keys+notify"); prev->next = cur; @@ -352,6 +357,7 @@ rexmpp_err_t rexmpp_init (rexmpp_t *s, const char *jid) s->track_roster_events = 1; s->nick_notifications = 1; s->retrieve_openpgp_keys = 1; + s->autojoin_bookmarked_mucs = 1; s->send_buffer = NULL; s->send_queue = NULL; s->resolver_ctx = NULL; @@ -1554,8 +1560,10 @@ void rexmpp_bound (rexmpp_t *s, xmlNodePtr req, xmlNodePtr response, int success if (rexmpp_xml_match(child, "urn:ietf:params:xml:ns:xmpp-bind", "bind")) { xmlNodePtr jid = xmlFirstElementChild(child); if (rexmpp_xml_match(jid, "urn:ietf:params:xml:ns:xmpp-bind", "jid")) { - rexmpp_log(s, LOG_INFO, "jid: %s", xmlNodeGetContent(jid)); - rexmpp_jid_parse(xmlNodeGetContent(jid), &(s->assigned_jid)); + char *jid_str = xmlNodeGetContent(jid); + rexmpp_log(s, LOG_INFO, "jid: %s", jid_str); + rexmpp_jid_parse(jid_str, &(s->assigned_jid)); + free(jid_str); } if (s->stream_id == NULL && (child = rexmpp_xml_find_child(s->stream_features, "urn:xmpp:sm:3", @@ -1813,7 +1821,58 @@ rexmpp_err_t rexmpp_process_element (rexmpp_t *s, xmlNodePtr elem) { strcmp(node, "urn:xmpp:openpgp:0:public-keys") == 0) { rexmpp_openpgp_check_keys(s, from_jid.bare, items); } - + if (s->autojoin_bookmarked_mucs && + strcmp(node, "urn:xmpp:bookmarks:1") == 0 && + strcmp(from_jid.bare, s->assigned_jid.bare) == 0) { + xmlNodePtr item; + for (item = xmlFirstElementChild(items); + item != NULL; + item = xmlNextElementSibling(item)) { + xmlNodePtr conference = + rexmpp_xml_find_child(item, + "urn:xmpp:bookmarks:1", + "conference"); + if (conference == NULL) { + continue; + } + char *item_id = xmlGetProp(item, "id"); + if (item_id == NULL) { + continue; + } + char *autojoin = xmlGetProp(conference, "autojoin"); + if (autojoin == NULL) { + free(item_id); + continue; + } + if (strcmp(autojoin, "true") == 0 || + strcmp(autojoin, "1") == 0) { + xmlNodePtr presence = + rexmpp_xml_add_id(s, xmlNewNode(NULL, "presence")); + xmlNewProp(presence, "from", s->assigned_jid.full); + xmlNodePtr nick = + rexmpp_xml_find_child(conference, + "urn:xmpp:bookmarks:1", + "nick"); + char *nick_str; + if (nick != NULL) { + nick_str = xmlNodeGetContent(nick); + } else { + nick_str = strdup(s->initial_jid.local); + } + char *jid = malloc(strlen(item_id) + strlen(nick_str) + 2); + sprintf(jid, "%s/%s", item_id, nick_str); + free(nick_str); + xmlNewProp(presence, "to", jid); + free(jid); + xmlNodePtr x = xmlNewNode(NULL, "x"); + xmlNewNs(x, "http://jabber.org/protocol/muc", NULL); + xmlAddChild(presence, x); + rexmpp_send(s, presence); + } + free(item_id); + free(autojoin); + } + } free(node); } } @@ -1866,10 +1925,12 @@ rexmpp_err_t rexmpp_process_element (rexmpp_t *s, xmlNodePtr elem) { mechanism = xmlNextElementSibling(mechanism)) { if (rexmpp_xml_match(mechanism, "urn:ietf:params:xml:ns:xmpp-sasl", "mechanism")) { + char *mech_str = xmlNodeGetContent(mechanism); snprintf(mech_list + strlen(mech_list), 2048 - strlen(mech_list), "%s ", - xmlNodeGetContent(mechanism)); + mech_str); + free(mech_str); } } const char *mech = @@ -1952,8 +2013,10 @@ rexmpp_err_t rexmpp_process_element (rexmpp_t *s, xmlNodePtr elem) { int sasl_err; if (rexmpp_xml_match(elem, "urn:ietf:params:xml:ns:xmpp-sasl", "challenge")) { - sasl_err = gsasl_step64 (s->sasl_session, xmlNodeGetContent(elem), + char *challenge = xmlNodeGetContent(elem); + sasl_err = gsasl_step64 (s->sasl_session, challenge, (char**)&sasl_buf); + free(challenge); if (sasl_err != GSASL_OK) { if (sasl_err == GSASL_NEEDS_MORE) { rexmpp_log(s, LOG_DEBUG, "SASL needs more data"); @@ -1971,8 +2034,10 @@ rexmpp_err_t rexmpp_process_element (rexmpp_t *s, xmlNodePtr elem) { return rexmpp_send(s, response); } else if (rexmpp_xml_match(elem, "urn:ietf:params:xml:ns:xmpp-sasl", "success")) { - sasl_err = gsasl_step64 (s->sasl_session, xmlNodeGetContent(elem), + char *success = xmlNodeGetContent(elem); + sasl_err = gsasl_step64 (s->sasl_session, success, (char**)&sasl_buf); + free(success); free(sasl_buf); if (sasl_err == GSASL_OK) { rexmpp_log(s, LOG_DEBUG, "SASL success"); diff --git a/src/rexmpp.h b/src/rexmpp.h index fa8e8bd..5ad2f61 100644 --- a/src/rexmpp.h +++ b/src/rexmpp.h @@ -239,14 +239,15 @@ struct rexmpp uint16_t socks_port; /* Various knobs (these are used instead of loadable modules). */ - int enable_carbons; - int enable_service_discovery; + int enable_carbons; /* XEP-0280 */ + int enable_service_discovery; /* XEP-0030 */ int manage_roster; const char *roster_cache_file; int track_roster_presence; - int track_roster_events; - int nick_notifications; - int retrieve_openpgp_keys; + int track_roster_events; /* XEP-0163 */ + int nick_notifications; /* XEP-0172 */ + int retrieve_openpgp_keys; /* XEP-0373 */ + int autojoin_bookmarked_mucs; /* XEP-0402 */ /* Resource limits. */ uint32_t stanza_queue_size; diff --git a/src/rexmpp_openpgp.c b/src/rexmpp_openpgp.c index 908e66d..b7bb493 100644 --- a/src/rexmpp_openpgp.c +++ b/src/rexmpp_openpgp.c @@ -60,12 +60,13 @@ void rexmpp_pgp_fp_reply (rexmpp_t *s, rexmpp_log(s, LOG_ERR, "OpenPGP key retrieval: no data in pubkey"); return; } - char *key_base64 = xmlNodeGetContent(data); char *key_raw = NULL; size_t key_raw_len = 0; + char *key_base64 = xmlNodeGetContent(data); int sasl_err = gsasl_base64_from(key_base64, strlen(key_base64), &key_raw, &key_raw_len); + free(key_base64); if (sasl_err != GSASL_OK) { rexmpp_log(s, LOG_ERR, "Base-64 key decoding failure: %s", gsasl_strerror(sasl_err)); @@ -374,8 +375,10 @@ rexmpp_openpgp_decrypt_verify_message (rexmpp_t *s, rexmpp_log(s, LOG_ERR, "No 'openpgp' child element"); return NULL; } + char *cipher_str = xmlNodeGetContent(openpgp); xmlNodePtr plain = - rexmpp_openpgp_decrypt_verify(s, xmlNodeGetContent(openpgp)); + rexmpp_openpgp_decrypt_verify(s, cipher_str); + free(cipher_str); if (plain == NULL) { return NULL; } @@ -523,7 +526,7 @@ rexmpp_openpgp_decrypt_verify (rexmpp_t *s, } void rexmpp_openpgp_add_keys (rexmpp_t *s, - char *jid, + const char *jid, gpgme_key_t **keys, int *nkeys, int *allocated) @@ -559,7 +562,7 @@ void rexmpp_openpgp_add_keys (rexmpp_t *s, char *rexmpp_openpgp_encrypt_sign (rexmpp_t *s, xmlNodePtr payload, - char **recipients) + const char **recipients) { gpgme_error_t err; int sasl_err; diff --git a/src/rexmpp_openpgp.h b/src/rexmpp_openpgp.h index c940db9..13b80f7 100644 --- a/src/rexmpp_openpgp.h +++ b/src/rexmpp_openpgp.h @@ -28,6 +28,6 @@ rexmpp_openpgp_decrypt_verify_message (rexmpp_t *s, char *rexmpp_openpgp_encrypt_sign (rexmpp_t *s, xmlNodePtr payload, - char **recipients); + const char **recipients); #endif -- cgit v1.2.3