about summary refs log tree commit diff stats
path: root/src/xmpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/xmpp')
-rw-r--r--src/xmpp/blocking.c27
-rw-r--r--src/xmpp/iq.c17
-rw-r--r--src/xmpp/message.c22
-rw-r--r--src/xmpp/roster_list.c24
-rw-r--r--src/xmpp/roster_list.h1
-rw-r--r--src/xmpp/stanza.c51
-rw-r--r--src/xmpp/stanza.h7
-rw-r--r--src/xmpp/xmpp.h9
8 files changed, 150 insertions, 8 deletions
diff --git a/src/xmpp/blocking.c b/src/xmpp/blocking.c
index 34614679..b16f95cb 100644
--- a/src/xmpp/blocking.c
+++ b/src/xmpp/blocking.c
@@ -109,7 +109,7 @@ blocked_ac_reset(void)
 }
 
 gboolean
-blocked_add(char* jid)
+blocked_add(char* jid, blocked_report reportkind, const char* const message)
 {
     GList* found = g_list_find_custom(blocked, jid, (GCompareFunc)g_strcmp0);
     if (found) {
@@ -129,6 +129,31 @@ blocked_add(char* jid)
     xmpp_stanza_set_name(item, STANZA_NAME_ITEM);
     xmpp_stanza_set_attribute(item, STANZA_ATTR_JID, jid);
 
+    if (reportkind != BLOCKED_NO_REPORT) {
+        xmpp_stanza_t* report = xmpp_stanza_new(ctx);
+        xmpp_stanza_set_name(report, STANZA_NAME_REPORT);
+        if (reportkind == BLOCKED_REPORT_ABUSE) {
+            xmpp_stanza_set_attribute(report, STANZA_ATTR_REASON, STANZA_REPORTING_ABUSE);
+        } else {
+            xmpp_stanza_set_attribute(report, STANZA_ATTR_REASON, STANZA_REPORTING_SPAM);
+        }
+
+        if (message) {
+            xmpp_stanza_t* text = xmpp_stanza_new(ctx);
+            xmpp_stanza_set_name(text, STANZA_NAME_TEXT);
+
+            xmpp_stanza_t* txt = xmpp_stanza_new(ctx);
+            xmpp_stanza_set_text(txt, message);
+
+            xmpp_stanza_add_child(text, txt);
+            xmpp_stanza_add_child(report, text);
+            xmpp_stanza_release(txt);
+        }
+
+        xmpp_stanza_add_child(item, report);
+        xmpp_stanza_release(report);
+    }
+
     xmpp_stanza_add_child(block, item);
     xmpp_stanza_release(item);
 
diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c
index beecb97e..42571b9c 100644
--- a/src/xmpp/iq.c
+++ b/src/xmpp/iq.c
@@ -1385,7 +1385,7 @@ _autoping_timed_send(xmpp_conn_t* const conn, void* const userdata)
     if (connection_supports(XMPP_FEATURE_PING) == FALSE) {
         log_warning("Server doesn't advertise %s feature, disabling autoping.", XMPP_FEATURE_PING);
         prefs_set_autoping(0);
-        cons_show_error("Server ping not supported, autoping disabled.");
+        cons_show_error("Server ping not supported (%s), autoping disabled.", XMPP_FEATURE_PING);
         xmpp_conn_t* conn = connection_get_conn();
         xmpp_timed_handler_delete(conn, _autoping_timed_send);
         return 1;
@@ -2308,6 +2308,8 @@ _disco_info_response_id_handler(xmpp_stanza_t* const stanza, void* const userdat
         GSList* features = NULL;
         while (child) {
             const char* stanza_name = xmpp_stanza_get_name(child);
+            const char* child_type = xmpp_stanza_get_type(child);
+
             if (g_strcmp0(stanza_name, STANZA_NAME_FEATURE) == 0) {
                 const char* var = xmpp_stanza_get_attribute(child, STANZA_ATTR_VAR);
                 if (var) {
@@ -2315,10 +2317,9 @@ _disco_info_response_id_handler(xmpp_stanza_t* const stanza, void* const userdat
                 }
             } else if (g_strcmp0(stanza_name, STANZA_NAME_IDENTITY) == 0) {
                 const char* name = xmpp_stanza_get_attribute(child, STANZA_ATTR_NAME);
-                const char* type = xmpp_stanza_get_type(child);
                 const char* category = xmpp_stanza_get_attribute(child, STANZA_ATTR_CATEGORY);
 
-                if (name || category || type) {
+                if (name || category || child_type) {
                     DiscoIdentity* identity = malloc(sizeof(struct disco_identity_t));
 
                     if (identity) {
@@ -2332,8 +2333,8 @@ _disco_info_response_id_handler(xmpp_stanza_t* const stanza, void* const userdat
                         } else {
                             identity->category = NULL;
                         }
-                        if (type) {
-                            identity->type = strdup(type);
+                        if (child_type) {
+                            identity->type = strdup(child_type);
                         } else {
                             identity->type = NULL;
                         }
@@ -2341,6 +2342,10 @@ _disco_info_response_id_handler(xmpp_stanza_t* const stanza, void* const userdat
                         identities = g_slist_append(identities, identity);
                     }
                 }
+            } else if (g_strcmp0(child_type, STANZA_TYPE_RESULT) == 0) {
+                GHashTable *adr = stanza_get_service_contact_addresses(connection_get_ctx(), child);
+                cons_show_disco_contact_information(adr);
+                g_hash_table_destroy(adr);
             }
 
             child = xmpp_stanza_get_next(child);
@@ -2581,7 +2586,7 @@ iq_mam_request(ProfChatWin* win)
 {
     if (connection_supports(XMPP_FEATURE_MAM2) == FALSE) {
         log_warning("Server doesn't advertise %s feature.", XMPP_FEATURE_MAM2);
-        cons_show_error("Server doesn't support MAM.");
+        cons_show_error("Server doesn't support MAM (%s).", XMPP_FEATURE_MAM2);
         return;
     }
 
diff --git a/src/xmpp/message.c b/src/xmpp/message.c
index 38d3ad49..051d1ece 100644
--- a/src/xmpp/message.c
+++ b/src/xmpp/message.c
@@ -94,6 +94,7 @@ static gboolean _handle_mam(xmpp_stanza_t* const stanza);
 static void _handle_pubsub(xmpp_stanza_t* const stanza, xmpp_stanza_t* const event);
 static gboolean _handle_form(xmpp_stanza_t* const stanza);
 static gboolean _handle_jingle_message(xmpp_stanza_t* const stanza);
+static gboolean _should_ignore_based_on_silence(xmpp_stanza_t* const stanza);
 
 #ifdef HAVE_LIBGPGME
 static xmpp_stanza_t* _openpgp_signcrypt(xmpp_ctx_t* ctx, const char* const to, const char* const text);
@@ -171,6 +172,11 @@ _message_handler(xmpp_conn_t* const conn, xmpp_stanza_t* const stanza, void* con
     } else if (type == NULL || g_strcmp0(type, STANZA_TYPE_CHAT) == 0 || g_strcmp0(type, STANZA_TYPE_NORMAL) == 0) {
         // type: chat, normal (==NULL)
 
+        // ignore all messages from JIDs that are not in roster, if 'silence' is set
+        if (_should_ignore_based_on_silence(stanza)) {
+            return 1;
+        }
+
         // XEP-0353: Jingle Message Initiation
         if (_handle_jingle_message(stanza)) {
             return 1;
@@ -1689,3 +1695,19 @@ _handle_jingle_message(xmpp_stanza_t* const stanza)
     }
     return FALSE;
 }
+
+static gboolean
+_should_ignore_based_on_silence(xmpp_stanza_t* const stanza)
+{
+    if (prefs_get_boolean(PREF_SILENCE_NON_ROSTER)) {
+        const char* const from = xmpp_stanza_get_from(stanza);
+        Jid* from_jid = jid_create(from);
+        PContact contact = roster_get_contact(from_jid->barejid);
+        jid_destroy(from_jid);
+        if (!contact) {
+            log_debug("[Silence] Ignoring message from: %s", from);
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
diff --git a/src/xmpp/roster_list.c b/src/xmpp/roster_list.c
index 04d16a17..9d7ac427 100644
--- a/src/xmpp/roster_list.c
+++ b/src/xmpp/roster_list.c
@@ -171,6 +171,30 @@ roster_get_contact(const char* const barejid)
 }
 
 char*
+roster_get_display_name(const char* const barejid)
+{
+    assert(roster != NULL);
+
+    GString* result = g_string_new("");
+
+    PContact contact = roster_get_contact(barejid);
+    if (contact) {
+        if (p_contact_name(contact)) {
+            g_string_append(result, p_contact_name(contact));
+        } else {
+            g_string_append(result, barejid);
+        }
+    } else {
+        g_string_append(result, barejid);
+    }
+
+    char* result_str = result->str;
+    g_string_free(result, FALSE);
+
+    return result_str;
+}
+
+char*
 roster_get_msg_display_name(const char* const barejid, const char* const resource)
 {
     assert(roster != NULL);
diff --git a/src/xmpp/roster_list.h b/src/xmpp/roster_list.h
index e47a29cb..f9548d97 100644
--- a/src/xmpp/roster_list.h
+++ b/src/xmpp/roster_list.h
@@ -70,6 +70,7 @@ GList* roster_get_groups(void);
 char* roster_group_autocomplete(const char* const search_str, gboolean previous, void* context);
 char* roster_barejid_autocomplete(const char* const search_str, gboolean previous, void* context);
 GSList* roster_get_contacts_by_presence(const char* const presence);
+char* roster_get_display_name(const char* const barejid);
 char* roster_get_msg_display_name(const char* const barejid, const char* const resource);
 gint roster_compare_name(PContact a, PContact b);
 gint roster_compare_presence(PContact a, PContact b);
diff --git a/src/xmpp/stanza.c b/src/xmpp/stanza.c
index 235a7dee..604d4003 100644
--- a/src/xmpp/stanza.c
+++ b/src/xmpp/stanza.c
@@ -2838,3 +2838,54 @@ stanza_create_muc_register_nick(xmpp_ctx_t* ctx, const char* const id, const cha
 
     return iq;
 }
+
+static void
+_contact_addresses_list_free(GSList* list)
+{
+    if (list) {
+        g_slist_free_full(list, g_free);
+    }
+}
+
+GHashTable*
+stanza_get_service_contact_addresses(xmpp_ctx_t* ctx, xmpp_stanza_t* stanza)
+{
+    GHashTable* addresses = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)_contact_addresses_list_free);
+
+    xmpp_stanza_t* fields = xmpp_stanza_get_children(stanza);
+    while (fields) {
+        const char* child_name = xmpp_stanza_get_name(fields);
+        const char* child_type = xmpp_stanza_get_type(fields);
+
+        if (g_strcmp0(child_name, STANZA_NAME_FIELD) == 0 && g_strcmp0(child_type, STANZA_TYPE_LIST_MULTI) == 0) {
+            // extract key (eg 'admin-addresses')
+            const char* var = xmpp_stanza_get_attribute(fields, STANZA_ATTR_VAR );
+
+            // extract values (a list of contact addresses eg mailto:xmpp@shakespeare.lit, xmpp:admins@shakespeare.lit)
+            xmpp_stanza_t* values = xmpp_stanza_get_children(fields);
+            GSList* val_list = NULL;
+            while (values) {
+                const char* value_name = xmpp_stanza_get_name(values);
+                if (value_name && (g_strcmp0(value_name, STANZA_NAME_VALUE) == 0)) {
+                    char* value_text = xmpp_stanza_get_text(values);
+                    if (value_text) {
+                        val_list = g_slist_append(val_list, g_strdup(value_text));
+
+                        xmpp_free(ctx, value_text);
+                    }
+                }
+
+                values = xmpp_stanza_get_next(values);
+            }
+
+            // add to list
+            if (g_slist_length(val_list) > 0) {
+                g_hash_table_insert(addresses, g_strdup(var), val_list);
+            }
+        }
+
+        fields = xmpp_stanza_get_next(fields);
+    }
+
+    return addresses;
+}
diff --git a/src/xmpp/stanza.h b/src/xmpp/stanza.h
index 5effaf3e..47560ce0 100644
--- a/src/xmpp/stanza.h
+++ b/src/xmpp/stanza.h
@@ -122,6 +122,7 @@
 #define STANZA_NAME_AFTER            "after"
 #define STANZA_NAME_USERNAME         "username"
 #define STANZA_NAME_PROPOSE          "propose"
+#define STANZA_NAME_REPORT           "report"
 
 // error conditions
 #define STANZA_NAME_BAD_REQUEST             "bad-request"
@@ -162,6 +163,7 @@
 #define STANZA_TYPE_SUBMIT       "submit"
 #define STANZA_TYPE_CANCEL       "cancel"
 #define STANZA_TYPE_MODIFY       "modify"
+#define STANZA_TYPE_LIST_MULTI   "list-multi"
 
 #define STANZA_ATTR_TO             "to"
 #define STANZA_ATTR_FROM           "from"
@@ -244,6 +246,9 @@
 
 #define STANZA_DATAFORM_SOFTWARE "urn:xmpp:dataforms:softwareinfo"
 
+#define STANZA_REPORTING_ABUSE "urn:xmpp:reporting:abuse"
+#define STANZA_REPORTING_SPAM  "urn:xmpp:reporting:spam"
+
 typedef struct caps_stanza_t
 {
     char* hash;
@@ -388,6 +393,8 @@ char* stanza_get_muc_destroy_reason(xmpp_stanza_t* stanza);
 const char* stanza_get_actor(xmpp_stanza_t* stanza);
 char* stanza_get_reason(xmpp_stanza_t* stanza);
 
+GHashTable* stanza_get_service_contact_addresses(xmpp_ctx_t* ctx, xmpp_stanza_t* stanza);
+
 Resource* stanza_resource_from_presence(XMPPPresence* presence);
 XMPPPresence* stanza_parse_presence(xmpp_stanza_t* stanza, int* err);
 void stanza_free_presence(XMPPPresence* presence);
diff --git a/src/xmpp/xmpp.h b/src/xmpp/xmpp.h
index 003c3e07..61c7a642 100644
--- a/src/xmpp/xmpp.h
+++ b/src/xmpp/xmpp.h
@@ -70,6 +70,7 @@
 #define XMPP_FEATURE_USER_AVATAR_METADATA_NOTIFY "urn:xmpp:avatar:metadata+notify"
 #define XMPP_FEATURE_LAST_MESSAGE_CORRECTION     "urn:xmpp:message-correct:0"
 #define XMPP_FEATURE_MAM2                        "urn:xmpp:mam:2"
+#define XMPP_FEATURE_SPAM_REPORTING              "urn:xmpp:reporting:1"
 
 typedef enum {
     JABBER_CONNECTING,
@@ -89,6 +90,12 @@ typedef enum {
     INVITE_MEDIATED
 } jabber_invite_t;
 
+typedef enum {
+    BLOCKED_NO_REPORT,
+    BLOCKED_REPORT_ABUSE,
+    BLOCKED_REPORT_SPAM
+} blocked_report;
+
 typedef struct bookmark_t
 {
     char* barejid;
@@ -286,7 +293,7 @@ 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_add(char* jid, blocked_report reportkind, const char* const message);
 gboolean blocked_remove(char* jid);
 char* blocked_ac_find(const char* const search_str, gboolean previous, void* context);
 void blocked_ac_reset(void);