summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordefanor <defanor@uberspace.net>2020-11-20 22:26:41 +0300
committerdefanor <defanor@uberspace.net>2020-11-20 22:47:57 +0300
commit8a3bc36ae7c893e2c25047d2187339a0c4d4327c (patch)
tree06838cc779d97fa8669d2a8fb00857fadc48813c
parent29002b52c9c031efaebfddef74ef8ceed6fd0157 (diff)
Handle XEP-0402: PEP Native Bookmarks
-rw-r--r--README2
-rw-r--r--examples/weechat.c61
-rw-r--r--src/rexmpp.c79
-rw-r--r--src/rexmpp.h11
-rw-r--r--src/rexmpp_openpgp.c11
-rw-r--r--src/rexmpp_openpgp.h2
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