about summary refs log tree commit diff stats
path: root/src/xmpp
diff options
context:
space:
mode:
authorJames Booth <boothj5@gmail.com>2016-05-01 19:39:39 +0100
committerJames Booth <boothj5@gmail.com>2016-05-01 19:39:39 +0100
commitb8c94376aad2d5edf4390e47b8dc89db8ab1a517 (patch)
treeed498c6b0fed9428e5d0f0cdd28cdd12f82cb447 /src/xmpp
parentc31913f8d582c57dc2d148739e190ddff743cb94 (diff)
downloadprofani-tty-b8c94376aad2d5edf4390e47b8dc89db8ab1a517.tar.gz
Add /blocked command
Diffstat (limited to 'src/xmpp')
-rw-r--r--src/xmpp/blocking.c323
-rw-r--r--src/xmpp/blocking.h41
-rw-r--r--src/xmpp/connection.c17
-rw-r--r--src/xmpp/iq.c6
-rw-r--r--src/xmpp/stanza.c20
-rw-r--r--src/xmpp/stanza.h6
-rw-r--r--src/xmpp/xmpp.h9
7 files changed, 422 insertions, 0 deletions
diff --git a/src/xmpp/blocking.c b/src/xmpp/blocking.c
new file mode 100644
index 00000000..06bbadf6
--- /dev/null
+++ b/src/xmpp/blocking.c
@@ -0,0 +1,323 @@
+/*
+ * blocking.c
+ *
+ * Copyright (C) 2012 - 2016 James Booth <boothj5@gmail.com>
+ *
+ * This file is part of Profanity.
+ *
+ * Profanity is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Profanity is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Profanity.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, as a special exception, the copyright holders give permission to
+ * link the code of portions of this program with the OpenSSL library under
+ * certain conditions as described in each individual source file, and
+ * distribute linked combinations including the two.
+ *
+ * You must obey the GNU General Public License in all respects for all of the
+ * code used other than OpenSSL. If you modify file(s) with this exception, you
+ * may extend this exception to your version of the file(s), but you are not
+ * obligated to do so. If you do not wish to do so, delete this exception
+ * statement from your version. If you delete this exception statement from all
+ * source files in the program, then also delete it here.
+ *
+ */
+
+#include <stdlib.h>
+
+#ifdef HAVE_LIBMESODE
+#include <mesode.h>
+#endif
+#ifdef HAVE_LIBSTROPHE
+#include <strophe.h>
+#endif
+
+#include <glib.h>
+
+#include "log.h"
+#include "common.h"
+#include "ui/ui.h"
+#include "xmpp/connection.h"
+#include "xmpp/stanza.h"
+
+static int _blocklist_result_handler(xmpp_stanza_t *const stanza, void *const userdata);
+static int _block_add_result_handler(xmpp_stanza_t *const stanza, void *const userdata);
+static int _block_remove_result_handler(xmpp_stanza_t *const stanza, void *const userdata);
+
+static GList *blocked;
+static Autocomplete blocked_ac;
+
+void
+blocking_request(void)
+{
+    char *id = create_unique_id("blocked_list_request");
+    xmpp_ctx_t *ctx = connection_get_ctx();
+    xmpp_stanza_t *iq;
+
+    if (blocked) {
+        g_list_free_full(blocked, free);
+        blocked = NULL;
+    }
+
+    if (blocked_ac) {
+        autocomplete_free(blocked_ac);
+    }
+    blocked_ac = autocomplete_new();
+
+    id_handler_add(id, _blocklist_result_handler, id);
+
+    iq = stanza_create_blocked_list_request(ctx);
+    xmpp_stanza_set_id(iq, id);
+    send_iq_stanza(iq);
+    xmpp_stanza_release(iq);
+    free(id);
+}
+
+GList*
+blocked_list(void)
+{
+    return blocked;
+}
+
+char*
+blocked_ac_find(const char *const search_str)
+{
+    return autocomplete_complete(blocked_ac, search_str, TRUE);
+}
+
+void
+blocked_ac_reset(void)
+{
+    if (blocked_ac) {
+        autocomplete_reset(blocked_ac);
+    }
+}
+
+gboolean
+blocked_add(char *jid)
+{
+    GList *found = g_list_find_custom(blocked, jid, (GCompareFunc)g_strcmp0);
+    if (found) {
+        return FALSE;
+    }
+
+    xmpp_ctx_t *ctx = connection_get_ctx();
+
+    xmpp_stanza_t *iq = xmpp_stanza_new(ctx);
+    xmpp_stanza_set_name(iq, STANZA_NAME_IQ);
+    xmpp_stanza_set_type(iq, STANZA_TYPE_SET);
+    char *id = create_unique_id("block");
+    xmpp_stanza_set_id(iq, id);
+
+    xmpp_stanza_t *block = xmpp_stanza_new(ctx);
+    xmpp_stanza_set_name(block, STANZA_NAME_BLOCK);
+    xmpp_stanza_set_ns(block, STANZA_NS_BLOCKING);
+
+    xmpp_stanza_t *item = xmpp_stanza_new(ctx);
+    xmpp_stanza_set_name(item, STANZA_NAME_ITEM);
+    xmpp_stanza_set_attribute(item, STANZA_ATTR_JID, jid);
+
+    xmpp_stanza_add_child(block, item);
+    xmpp_stanza_release(item);
+
+    xmpp_stanza_add_child(iq, block);
+    xmpp_stanza_release(block);
+
+    id_handler_add(id, _block_add_result_handler, strdup(jid));
+
+    send_iq_stanza(iq);
+    xmpp_stanza_release(iq);
+    free(id);
+
+    return TRUE;
+}
+
+gboolean
+blocked_remove(char *jid)
+{
+    GList *found = g_list_find_custom(blocked, jid, (GCompareFunc)g_strcmp0);
+    if (!found) {
+        return FALSE;
+    }
+
+    xmpp_ctx_t *ctx = connection_get_ctx();
+
+    xmpp_stanza_t *iq = xmpp_stanza_new(ctx);
+    xmpp_stanza_set_name(iq, STANZA_NAME_IQ);
+    xmpp_stanza_set_type(iq, STANZA_TYPE_SET);
+    char *id = create_unique_id("unblock");
+    xmpp_stanza_set_id(iq, id);
+
+    xmpp_stanza_t *block = xmpp_stanza_new(ctx);
+    xmpp_stanza_set_name(block, STANZA_NAME_UNBLOCK);
+    xmpp_stanza_set_ns(block, STANZA_NS_BLOCKING);
+
+    xmpp_stanza_t *item = xmpp_stanza_new(ctx);
+    xmpp_stanza_set_name(item, STANZA_NAME_ITEM);
+    xmpp_stanza_set_attribute(item, STANZA_ATTR_JID, jid);
+
+    xmpp_stanza_add_child(block, item);
+    xmpp_stanza_release(item);
+
+    xmpp_stanza_add_child(iq, block);
+    xmpp_stanza_release(block);
+
+    id_handler_add(id, _block_remove_result_handler, strdup(jid));
+
+    send_iq_stanza(iq);
+    xmpp_stanza_release(iq);
+    free(id);
+
+    return TRUE;
+}
+
+int
+blocked_set_handler(xmpp_stanza_t *stanza)
+{
+    xmpp_stanza_t *block = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_BLOCK);
+    if (block) {
+        xmpp_stanza_t *child = xmpp_stanza_get_children(block);
+        while (child) {
+            if (g_strcmp0(xmpp_stanza_get_name(child), STANZA_NAME_ITEM) == 0) {
+                const char *jid = xmpp_stanza_get_attribute(child, STANZA_ATTR_JID);
+                if (jid) {
+                    blocked = g_list_append(blocked, strdup(jid));
+                    autocomplete_add(blocked_ac, jid);
+                }
+
+            }
+
+            child = xmpp_stanza_get_next(child);
+        }
+    }
+
+    xmpp_stanza_t *unblock = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_UNBLOCK);
+    if (unblock) {
+        xmpp_stanza_t *child = xmpp_stanza_get_children(unblock);
+        if (!child) {
+            g_list_free_full(blocked, free);
+            blocked = NULL;
+            autocomplete_clear(blocked_ac);
+        } else {
+            while (child) {
+                if (g_strcmp0(xmpp_stanza_get_name(child), STANZA_NAME_ITEM) == 0) {
+                    const char *jid = xmpp_stanza_get_attribute(child, STANZA_ATTR_JID);
+                    if (jid) {
+                        GList *found = g_list_find_custom(blocked, jid, (GCompareFunc)g_strcmp0);
+                        if (found) {
+                            blocked = g_list_remove_link(blocked, found);
+                            g_list_free_full(found, free);
+                            autocomplete_remove(blocked_ac, jid);
+                        }
+                    }
+
+                }
+
+                child = xmpp_stanza_get_next(child);
+            }
+        }
+    }
+
+    return 1;
+}
+
+static int
+_block_add_result_handler(xmpp_stanza_t *const stanza, void *const userdata)
+{
+    char *jid = (char*)userdata;
+
+    const char *type = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_TYPE);
+    if (type == NULL) {
+        log_info("Block response received for %s with no type attribute.", jid);
+        free(jid);
+        return 0;
+    }
+
+    if (g_strcmp0(type, "result") != 0) {
+        log_info("Block response received for %s with unrecognised type attribute.", jid);
+        free(jid);
+        return 0;
+    }
+
+    cons_show("User %s successfully blocked.", jid);
+    free(jid);
+
+    return 0;
+}
+
+static int
+_block_remove_result_handler(xmpp_stanza_t *const stanza, void *const userdata)
+{
+    char *jid = (char*)userdata;
+
+    const char *type = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_TYPE);
+    if (type == NULL) {
+        log_info("Unblock response received for %s with no type attribute.", jid);
+        free(jid);
+        return 0;
+    }
+
+    if (g_strcmp0(type, "result") != 0) {
+        log_info("Unblock response received for %s with unrecognised type attribute.", jid);
+        free(jid);
+        return 0;
+    }
+
+    cons_show("User %s successfully unblocked.", jid);
+    free(jid);
+
+    return 0;
+}
+
+static int
+_blocklist_result_handler(xmpp_stanza_t *const stanza, void *const userdata)
+{
+    log_info("Blocked list result handler fired.");
+
+    const char *type = xmpp_stanza_get_type(stanza);
+    if (g_strcmp0(type, "result") != 0) {
+        log_info("Received blocklist without result type");
+        return 0;
+    }
+
+    xmpp_stanza_t *blocklist = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_BLOCKLIST);
+    if (!blocklist) {
+        log_info("Received blocklist without blocklist element");
+        return 0;
+    }
+
+    if (blocked) {
+        g_list_free_full(blocked, free);
+        blocked = NULL;
+    }
+
+    xmpp_stanza_t *items = xmpp_stanza_get_children(blocklist);
+    if (!items) {
+        log_info("No blocked users.");
+        return 0;
+    }
+
+    xmpp_stanza_t *curr = items;
+    while (curr) {
+        const char *name = xmpp_stanza_get_name(curr);
+        if (g_strcmp0(name, "item") == 0) {
+            const char *jid = xmpp_stanza_get_attribute(curr, STANZA_ATTR_JID);
+            if (jid) {
+                blocked = g_list_append(blocked, strdup(jid));
+                autocomplete_add(blocked_ac, jid);
+            }
+        }
+        curr = xmpp_stanza_get_next(curr);
+    }
+
+    return 0;
+}
diff --git a/src/xmpp/blocking.h b/src/xmpp/blocking.h
new file mode 100644
index 00000000..f541cef1
--- /dev/null
+++ b/src/xmpp/blocking.h
@@ -0,0 +1,41 @@
+/*
+ * blocking.h
+ *
+ * Copyright (C) 2012 - 2016 James Booth <boothj5@gmail.com>
+ *
+ * This file is part of Profanity.
+ *
+ * Profanity is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Profanity is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Profanity.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, as a special exception, the copyright holders give permission to
+ * link the code of portions of this program with the OpenSSL library under
+ * certain conditions as described in each individual source file, and
+ * distribute linked combinations including the two.
+ *
+ * You must obey the GNU General Public License in all respects for all of the
+ * code used other than OpenSSL. If you modify file(s) with this exception, you
+ * may extend this exception to your version of the file(s), but you are not
+ * obligated to do so. If you do not wish to do so, delete this exception
+ * statement from your version. If you delete this exception statement from all
+ * source files in the program, then also delete it here.
+ *
+ */
+
+#ifndef XMPP_BLOCKING_H
+#define XMPP_BLOCKING_H
+
+void blocking_request(void);
+int blocked_set_handler(xmpp_stanza_t *stanza);
+
+#endif
diff --git a/src/xmpp/connection.c b/src/xmpp/connection.c
index 710e71b2..7db3b2ed 100644
--- a/src/xmpp/connection.c
+++ b/src/xmpp/connection.c
@@ -55,6 +55,7 @@
 #include "profanity.h"
 #include "event/server_events.h"
 #include "xmpp/bookmark.h"
+#include "xmpp/blocking.h"
 #include "xmpp/capabilities.h"
 #include "xmpp/connection.h"
 #include "xmpp/iq.h"
@@ -343,6 +344,21 @@ jabber_get_disco_items(void)
     return (disco_items);
 }
 
+gboolean
+jabber_service_supports(const char *const feature)
+{
+    DiscoInfo *disco_info;
+    while (disco_items) {
+        disco_info = disco_items->data;
+        if (g_hash_table_lookup_extended(disco_info->features, feature, NULL, NULL)) {
+            return TRUE;
+        }
+        disco_items = g_slist_next(disco_items);
+    }
+
+    return FALSE;
+}
+
 void
 jabber_set_disco_items(GSList *_disco_items)
 {
@@ -678,6 +694,7 @@ _connection_handler(xmpp_conn_t *const conn, const xmpp_conn_event_t status, con
 
         roster_request();
         bookmark_request();
+        blocking_request();
 
         // items discovery
         DiscoInfo *info = malloc(sizeof(struct disco_info_t));
diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c
index c874a721..cba3d4d3 100644
--- a/src/xmpp/iq.c
+++ b/src/xmpp/iq.c
@@ -58,6 +58,7 @@
 #include "config/preferences.h"
 #include "event/server_events.h"
 #include "xmpp/capabilities.h"
+#include "xmpp/blocking.h"
 #include "xmpp/connection.h"
 #include "xmpp/stanza.h"
 #include "xmpp/form.h"
@@ -170,6 +171,11 @@ _iq_handler(xmpp_conn_t *const conn, xmpp_stanza_t *const stanza, void *const us
         roster_result_handler(stanza);
     }
 
+    xmpp_stanza_t *blocking = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_BLOCKING);
+    if (blocking && (g_strcmp0(type, STANZA_TYPE_SET) == 0)) {
+        blocked_set_handler(stanza);
+    }
+
     const char *id = xmpp_stanza_get_id(stanza);
     if (id) {
         ProfIdHandler *handler = g_hash_table_lookup(id_handlers, id);
diff --git a/src/xmpp/stanza.c b/src/xmpp/stanza.c
index dc2fb68a..13450e20 100644
--- a/src/xmpp/stanza.c
+++ b/src/xmpp/stanza.c
@@ -117,6 +117,26 @@ stanza_create_bookmarks_storage_request(xmpp_ctx_t *ctx)
     return iq;
 }
 
+xmpp_stanza_t*
+stanza_create_blocked_list_request(xmpp_ctx_t *ctx)
+{
+    xmpp_stanza_t *iq, *blocklist;
+
+    iq = xmpp_stanza_new(ctx);
+    blocklist = xmpp_stanza_new(ctx);
+
+    xmpp_stanza_set_name(iq, STANZA_NAME_IQ);
+    xmpp_stanza_set_type(iq, STANZA_TYPE_GET);
+
+    xmpp_stanza_set_name(blocklist, STANZA_NAME_BLOCKLIST);
+    xmpp_stanza_set_ns(blocklist, STANZA_NS_BLOCKING);
+
+    xmpp_stanza_add_child(iq, blocklist);
+    xmpp_stanza_release(blocklist);
+
+    return iq;
+}
+
 #if 0
 xmpp_stanza_t*
 stanza_create_bookmarks_pubsub_add(xmpp_ctx_t *ctx, const char *const jid,
diff --git a/src/xmpp/stanza.h b/src/xmpp/stanza.h
index 977e34c5..d557b5c7 100644
--- a/src/xmpp/stanza.h
+++ b/src/xmpp/stanza.h
@@ -54,6 +54,9 @@
 
 #define STANZA_NAME_MESSAGE "message"
 #define STANZA_NAME_BODY "body"
+#define STANZA_NAME_BLOCK "block"
+#define STANZA_NAME_UNBLOCK "unblock"
+#define STANZA_NAME_BLOCKLIST "blocklist"
 #define STANZA_NAME_PRESENCE "presence"
 #define STANZA_NAME_PRIORITY "priority"
 #define STANZA_NAME_X "x"
@@ -181,6 +184,7 @@
 #define STANZA_NS_ENCRYPTED "jabber:x:encrypted"
 #define STANZA_NS_HTTP_UPLOAD "urn:xmpp:http:upload"
 #define STANZA_NS_X_OOB "jabber:x:oob"
+#define STANZA_NS_BLOCKING "urn:xmpp:blocking"
 
 #define STANZA_DATAFORM_SOFTWARE "urn:xmpp:dataforms:softwareinfo"
 
@@ -205,6 +209,8 @@ typedef enum {
 
 xmpp_stanza_t* stanza_create_bookmarks_storage_request(xmpp_ctx_t *ctx);
 
+xmpp_stanza_t* stanza_create_blocked_list_request(xmpp_ctx_t *ctx);
+
 xmpp_stanza_t* stanza_create_http_upload_request(xmpp_ctx_t *ctx, const char *const id, const char *const jid, HTTPUpload *upload);
 
 xmpp_stanza_t* stanza_enable_carbons(xmpp_ctx_t *ctx);
diff --git a/src/xmpp/xmpp.h b/src/xmpp/xmpp.h
index d6e6031b..bf7bbbac 100644
--- a/src/xmpp/xmpp.h
+++ b/src/xmpp/xmpp.h
@@ -54,6 +54,8 @@
 #define JABBER_PRIORITY_MIN -128
 #define JABBER_PRIORITY_MAX 127
 
+#define XMPP_FEATURE_BLOCKING "urn:xmpp:blocking"
+
 typedef enum {
     JABBER_UNDEFINED,
     JABBER_STARTED,
@@ -126,6 +128,7 @@ TLSCertificate* jabber_get_tls_peer_cert(void);
 #endif
 gboolean jabber_conn_is_secured(void);
 gboolean jabber_send_stanza(const char *const stanza);
+gboolean jabber_service_supports(const char *const feature);
 
 // message functions
 char* message_send_chat(const char *const barejid, const char *const msg, const char *const oob_url);
@@ -206,6 +209,12 @@ void roster_send_remove_from_group(const char *const group, PContact contact);
 void roster_send_add_new(const char *const barejid, const char *const name);
 void roster_send_remove(const char *const barejid);
 
+GList* blocked_list(void);
+gboolean blocked_add(char *jid);
+gboolean blocked_remove(char *jid);
+char* blocked_ac_find(const char *const search_str);
+void blocked_ac_reset(void);
+
 void form_destroy(DataForm *form);
 char* form_get_form_type_field(DataForm *form);
 void form_set_value(DataForm *form, const char *const tag, char *value);