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/bookmark.c245
-rw-r--r--src/xmpp/bookmark.h22
-rw-r--r--src/xmpp/capabilities.c49
-rw-r--r--src/xmpp/connection.c2
-rw-r--r--src/xmpp/iq.c20
-rw-r--r--src/xmpp/message.c6
-rw-r--r--src/xmpp/presence.c86
-rw-r--r--src/xmpp/stanza.c65
-rw-r--r--src/xmpp/stanza.h6
9 files changed, 441 insertions, 60 deletions
diff --git a/src/xmpp/bookmark.c b/src/xmpp/bookmark.c
new file mode 100644
index 00000000..92e6d7e8
--- /dev/null
+++ b/src/xmpp/bookmark.c
@@ -0,0 +1,245 @@
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include <strophe.h>
+
+#include "log.h"
+#include "muc.h"
+#include "ui/ui.h"
+#include "xmpp/connection.h"
+#include "xmpp/stanza.h"
+#include "xmpp/xmpp.h"
+#include "xmpp/bookmark.h"
+
+#define BOOKMARK_TIMEOUT 5000
+/* TODO: replace with a preference */
+#define BOOKMARK_AUTOJOIN_MAX 5
+
+static int autojoin_count;
+
+static Autocomplete bookmark_ac;
+static GList *bookmark_list;
+
+static int _bookmark_handle_result(xmpp_conn_t * const conn,
+    xmpp_stanza_t * const stanza, void * const userdata);
+static int _bookmark_handle_delete(xmpp_conn_t * const conn,
+    void * const userdata);
+static void _bookmark_item_destroy(gpointer item);
+
+void
+bookmark_request(void)
+{
+    char *id;
+    xmpp_conn_t *conn = connection_get_conn();
+    xmpp_ctx_t *ctx = connection_get_ctx();
+    xmpp_stanza_t *iq;
+
+    id = get_unique_id();
+    if (!id) {
+        return;
+    }
+
+    autojoin_count = 0;
+    if (bookmark_ac != NULL) {
+        autocomplete_free(bookmark_ac);
+    }
+    bookmark_ac = autocomplete_new();
+    if (bookmark_list != NULL) {
+        g_list_free_full(bookmark_list, _bookmark_item_destroy);
+        bookmark_list = NULL;
+    }
+
+    xmpp_timed_handler_add(conn, _bookmark_handle_delete, BOOKMARK_TIMEOUT, id);
+    xmpp_id_handler_add(conn, _bookmark_handle_result, id, id);
+
+    iq = stanza_create_storage_bookmarks(ctx);
+    xmpp_stanza_set_id(iq, id);
+    xmpp_send(conn, iq);
+    xmpp_stanza_release(iq);
+}
+
+void
+bookmark_add(const char *jid, const char *nick, gboolean autojoin)
+{
+    /* TODO: send request */
+    /* TODO: manage bookmark_list */
+
+    /* this may be command for modifying */
+    autocomplete_remove(bookmark_ac, jid);
+    autocomplete_add(bookmark_ac, strdup(jid));
+}
+
+void
+bookmark_remove(const char *jid, gboolean autojoin)
+{
+    /* TODO: manage bookmark_list */
+    if (autojoin) {
+        /* TODO: just set autojoin=0 */
+    } else {
+        /* TODO: send request */
+        autocomplete_remove(bookmark_ac, jid);
+    }
+}
+
+const GList *
+bookmark_get_list(void)
+{
+    return bookmark_list;
+}
+
+char *
+bookmark_find(char *search_str)
+{
+    return autocomplete_complete(bookmark_ac, search_str);
+}
+
+void
+bookmark_autocomplete_reset(void)
+{
+    if (bookmark_ac != NULL) {
+        autocomplete_reset(bookmark_ac);
+    }
+}
+
+static int
+_bookmark_handle_result(xmpp_conn_t * const conn,
+    xmpp_stanza_t * const stanza, void * const userdata)
+{
+    xmpp_ctx_t *ctx = connection_get_ctx();
+    char *id = (char *)userdata;
+    xmpp_stanza_t *ptr;
+    xmpp_stanza_t *nick;
+    char *name;
+    char *jid;
+    char *autojoin;
+    gboolean autojoin_val;
+    Jid *my_jid;
+    Bookmark *item;
+
+    xmpp_timed_handler_delete(conn, _bookmark_handle_delete);
+    g_free(id);
+
+    name = xmpp_stanza_get_name(stanza);
+    if (!name || strcmp(name, STANZA_NAME_IQ) != 0) {
+        return 0;
+    }
+
+    ptr = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY);
+    if (!ptr) {
+        return 0;
+    }
+    ptr = xmpp_stanza_get_child_by_name(ptr, STANZA_NAME_STORAGE);
+    if (!ptr) {
+        return 0;
+    }
+
+    if (bookmark_ac == NULL) {
+        bookmark_ac = autocomplete_new();
+    }
+    my_jid = jid_create(jabber_get_fulljid());
+
+    ptr = xmpp_stanza_get_children(ptr);
+    while (ptr) {
+        name = xmpp_stanza_get_name(ptr);
+        if (!name || strcmp(name, STANZA_NAME_CONFERENCE) != 0) {
+            ptr = xmpp_stanza_get_next(ptr);
+            continue;
+        }
+        jid = xmpp_stanza_get_attribute(ptr, STANZA_ATTR_JID);
+        if (!jid) {
+            ptr = xmpp_stanza_get_next(ptr);
+            continue;
+        }
+
+        log_debug("Handle bookmark for %s", jid);
+
+        name = NULL;
+        nick = xmpp_stanza_get_child_by_name(ptr, "nick");
+        if (nick) {
+            char *tmp;
+            tmp = xmpp_stanza_get_text(nick);
+            if (tmp) {
+                name = strdup(tmp);
+                xmpp_free(ctx, tmp);
+            }
+        }
+
+        autojoin = xmpp_stanza_get_attribute(ptr, "autojoin");
+        if (autojoin && (strcmp(autojoin, "1") == 0 || strcmp(autojoin, "true") == 0)) {
+            autojoin_val = TRUE;
+        } else {
+            autojoin_val = FALSE;
+        }
+
+        autocomplete_add(bookmark_ac, strdup(jid));
+        item = malloc(sizeof(*item));
+        item->jid = strdup(jid);
+        item->nick = name;
+        item->autojoin = autojoin_val;
+        bookmark_list = g_list_append(bookmark_list, item);
+
+
+        /* TODO: preference whether autojoin */
+        if (autojoin_val) {
+            if (autojoin_count < BOOKMARK_AUTOJOIN_MAX) {
+                Jid *room_jid;
+
+                ++autojoin_count;
+
+                if (name == NULL) {
+                    name = my_jid->localpart;
+                }
+
+                log_debug("Autojoin %s with nick=%s", jid, name);
+                room_jid = jid_create_from_bare_and_resource(jid, name);
+                if (!muc_room_is_active(room_jid)) {
+                    presence_join_room(room_jid);
+                    /* TODO: this should be removed after fixing #195 */
+                    ui_room_join(room_jid);
+                }
+                jid_destroy(room_jid);
+            } else {
+                log_debug("Rejected autojoin %s (maximum has been reached)", jid);
+            }
+        }
+
+        ptr = xmpp_stanza_get_next(ptr);
+    }
+
+    jid_destroy(my_jid);
+
+    return 0;
+}
+
+static int
+_bookmark_handle_delete(xmpp_conn_t * const conn,
+    void * const userdata)
+{
+    char *id = (char *)userdata;
+
+    assert(id != NULL);
+
+    log_debug("Timeout for handler with id=%s", id);
+
+    xmpp_id_handler_delete(conn, _bookmark_handle_result, id);
+    g_free(id);
+
+    return 0;
+}
+
+static void
+_bookmark_item_destroy(gpointer item)
+{
+    Bookmark *p = (Bookmark *)item;
+
+    if (p == NULL) {
+        return;
+    }
+
+    free(p->jid);
+    free(p->nick);
+    free(p);
+}
diff --git a/src/xmpp/bookmark.h b/src/xmpp/bookmark.h
new file mode 100644
index 00000000..e15b6eab
--- /dev/null
+++ b/src/xmpp/bookmark.h
@@ -0,0 +1,22 @@
+
+#ifndef BOOKMARK_H
+#define BOOKMARK_H
+
+#include <glib.h>
+
+struct bookmark_t {
+    char *jid;
+    char *nick;
+    gboolean autojoin;
+};
+
+typedef struct bookmark_t Bookmark;
+
+void bookmark_request(void);
+void bookmark_add(const char *jid, const char *nick, gboolean autojoin);
+void bookmark_remove(const char *jid, gboolean autojoin);
+const GList *bookmark_get_list(void);
+char *bookmark_find(char *search_str);
+void bookmark_autocomplete_reset(void);
+
+#endif
diff --git a/src/xmpp/capabilities.c b/src/xmpp/capabilities.c
index 10aa8a38..ed3cf169 100644
--- a/src/xmpp/capabilities.c
+++ b/src/xmpp/capabilities.c
@@ -122,7 +122,7 @@ caps_create_sha1_str(xmpp_stanza_t * const query)
     GSList *form_names = NULL;
     DataForm *form = NULL;
     FormField *field = NULL;
-    GHashTable *forms = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)stanza_destroy_form);
+    GHashTable *forms = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)stanza_destroy_form);
 
     GString *s = g_string_new("");
 
@@ -134,18 +134,18 @@ caps_create_sha1_str(xmpp_stanza_t * const query)
             lang = xmpp_stanza_get_attribute(child, "xml:lang");
             name = xmpp_stanza_get_attribute(child, "name");
 
-            GString *identity_str = g_string_new(g_strdup(category));
+            GString *identity_str = g_string_new(category);
             g_string_append(identity_str, "/");
             if (type != NULL) {
-                g_string_append(identity_str, g_strdup(type));
+                g_string_append(identity_str, type);
             }
             g_string_append(identity_str, "/");
             if (lang != NULL) {
-                g_string_append(identity_str, g_strdup(lang));
+                g_string_append(identity_str, lang);
             }
             g_string_append(identity_str, "/");
             if (name != NULL) {
-                g_string_append(identity_str, g_strdup(name));
+                g_string_append(identity_str, name);
             }
             g_string_append(identity_str, "<");
             identities = g_slist_insert_sorted(identities, g_strdup(identity_str->str), (GCompareFunc)octet_compare);
@@ -156,8 +156,8 @@ caps_create_sha1_str(xmpp_stanza_t * const query)
         } else if (g_strcmp0(xmpp_stanza_get_name(child), STANZA_NAME_X) == 0) {
             if (strcmp(xmpp_stanza_get_ns(child), STANZA_NS_DATA) == 0) {
                 form = stanza_create_form(child);
-                form_names = g_slist_insert_sorted(form_names, strdup(form->form_type), (GCompareFunc)octet_compare);
-                g_hash_table_insert(forms, strdup(form->form_type), form);
+                form_names = g_slist_insert_sorted(form_names, g_strdup(form->form_type), (GCompareFunc)octet_compare);
+                g_hash_table_insert(forms, g_strdup(form->form_type), form);
             }
         }
         child = xmpp_stanza_get_next(child);
@@ -165,13 +165,13 @@ caps_create_sha1_str(xmpp_stanza_t * const query)
 
     GSList *curr = identities;
     while (curr != NULL) {
-        g_string_append(s, strdup(curr->data));
+        g_string_append(s, curr->data);
         curr = g_slist_next(curr);
     }
 
     curr = features;
     while (curr != NULL) {
-        g_string_append(s, strdup(curr->data));
+        g_string_append(s, curr->data);
         g_string_append(s, "<");
         curr = g_slist_next(curr);
     }
@@ -179,17 +179,17 @@ caps_create_sha1_str(xmpp_stanza_t * const query)
     curr = form_names;
     while (curr != NULL) {
         form = g_hash_table_lookup(forms, curr->data);
-        g_string_append(s, strdup(form->form_type));
+        g_string_append(s, form->form_type);
         g_string_append(s, "<");
 
         GSList *curr_field = form->fields;
         while (curr_field != NULL) {
             field = curr_field->data;
-            g_string_append(s, strdup(field->var));
+            g_string_append(s, field->var);
             g_string_append(s, "<");
             GSList *curr_value = field->values;
             while (curr_value != NULL) {
-                g_string_append(s, strdup(curr_value->data));
+                g_string_append(s, curr_value->data);
                 g_string_append(s, "<");
                 curr_value = g_slist_next(curr_value);
             }
@@ -215,10 +215,10 @@ caps_create_sha1_str(xmpp_stanza_t * const query)
     char *result = g_base64_encode(md_value, md_len);
 
     g_string_free(s, TRUE);
-    g_slist_free_full(identities, free);
-    g_slist_free_full(features, free);
-    g_slist_free_full(form_names, free);
-    //g_hash_table_destroy(forms);
+    g_slist_free_full(identities, g_free);
+    g_slist_free_full(features, g_free);
+    g_slist_free_full(form_names, g_free);
+    g_hash_table_destroy(forms);
 
     return result;
 }
@@ -301,17 +301,16 @@ static void
 _caps_destroy(Capabilities *caps)
 {
     if (caps != NULL) {
-        FREE_SET_NULL(caps->category);
-        FREE_SET_NULL(caps->type);
-        FREE_SET_NULL(caps->name);
-        FREE_SET_NULL(caps->software);
-        FREE_SET_NULL(caps->software_version);
-        FREE_SET_NULL(caps->os);
-        FREE_SET_NULL(caps->os_version);
+        free(caps->category);
+        free(caps->type);
+        free(caps->name);
+        free(caps->software);
+        free(caps->software_version);
+        free(caps->os);
+        free(caps->os_version);
         if (caps->features != NULL) {
             g_slist_free_full(caps->features, free);
-            caps->features = NULL;
         }
-        FREE_SET_NULL(caps);
+        free(caps);
     }
 }
diff --git a/src/xmpp/connection.c b/src/xmpp/connection.c
index 85ddfa45..5040aa91 100644
--- a/src/xmpp/connection.c
+++ b/src/xmpp/connection.c
@@ -33,6 +33,7 @@
 #include "log.h"
 #include "muc.h"
 #include "profanity.h"
+#include "xmpp/bookmark.h"
 #include "xmpp/capabilities.h"
 #include "xmpp/connection.h"
 #include "xmpp/iq.h"
@@ -494,6 +495,7 @@ _connection_handler(xmpp_conn_t * const conn,
         }
 
         roster_request();
+        bookmark_request();
         jabber_conn.conn_status = JABBER_CONNECTED;
 
         if (prefs_get_reconnect() != 0) {
diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c
index 48b561f0..742a2258 100644
--- a/src/xmpp/iq.c
+++ b/src/xmpp/iq.c
@@ -312,10 +312,10 @@ static void
 _identity_destroy(DiscoIdentity *identity)
 {
     if (identity != NULL) {
-        FREE_SET_NULL(identity->name);
-        FREE_SET_NULL(identity->type);
-        FREE_SET_NULL(identity->category);
-        FREE_SET_NULL(identity);
+        free(identity->name);
+        free(identity->type);
+        free(identity->category);
+        free(identity);
     }
 }
 
@@ -323,9 +323,9 @@ static void
 _item_destroy(DiscoItem *item)
 {
     if (item != NULL) {
-        FREE_SET_NULL(item->jid);
-        FREE_SET_NULL(item->name);
-        FREE_SET_NULL(item);
+        free(item->jid);
+        free(item->name);
+        free(item);
     }
 }
 
@@ -411,12 +411,13 @@ _iq_handle_discoinfo_result(xmpp_conn_t * const conn, xmpp_stanza_t * const stan
                 log_info("Generated sha-1 does not match given:");
                 log_info("Generated : %s", generated_sha1);
                 log_info("Given     : %s", given_sha1);
-                FREE_SET_NULL(generated_sha1);
+                g_free(generated_sha1);
                 g_strfreev(split);
+                free(caps_key);
 
                 return 1;
             }
-            FREE_SET_NULL(generated_sha1);
+            g_free(generated_sha1);
             g_strfreev(split);
 
         // non supported hash, or legacy caps
@@ -429,6 +430,7 @@ _iq_handle_discoinfo_result(xmpp_conn_t * const conn, xmpp_stanza_t * const stan
         // already cached
         if (caps_contains(caps_key)) {
             log_info("Client info already cached.");
+            free(caps_key);
             return 1;
         }
 
diff --git a/src/xmpp/message.c b/src/xmpp/message.c
index 29d11958..95b3152a 100644
--- a/src/xmpp/message.c
+++ b/src/xmpp/message.c
@@ -212,6 +212,9 @@ _conference_message_handler(xmpp_conn_t * const conn,
         }
 
         Jid *jidp = jid_create(invitor_jid);
+        if (jidp == NULL) {
+            return 1;
+        }
         invitor = jidp->barejid;
 
         xmpp_stanza_t *reason_st = xmpp_stanza_get_child_by_name(invite, STANZA_NAME_REASON);
@@ -233,6 +236,9 @@ _conference_message_handler(xmpp_conn_t * const conn,
         }
 
         Jid *jidp = jid_create(from);
+        if (jidp == NULL) {
+            return 1;
+        }
         invitor = jidp->barejid;
 
         reason = xmpp_stanza_get_attribute(x_groupchat, STANZA_ATTR_REASON);
diff --git a/src/xmpp/presence.c b/src/xmpp/presence.c
index c05ba198..a18bf6fe 100644
--- a/src/xmpp/presence.c
+++ b/src/xmpp/presence.c
@@ -156,14 +156,23 @@ presence_sub_request_find(char * search_str)
 gboolean
 presence_sub_request_exists(const char * const bare_jid)
 {
-    GSList *requests = autocomplete_get_list(sub_requests_ac);
+    gboolean result = FALSE;
+    GSList *requests_p = autocomplete_get_list(sub_requests_ac);
+    GSList *requests = requests_p;
+
     while (requests != NULL) {
         if (strcmp(requests->data, bare_jid) == 0) {
-            return TRUE;
+            result = TRUE;
+            break;
         }
         requests = g_slist_next(requests);
     }
-    return FALSE;
+
+    if (requests_p != NULL) {
+        g_slist_free_full(requests_p, free);
+    }
+
+    return result;
 }
 
 void
@@ -220,20 +229,28 @@ presence_update(const resource_presence_t presence_type, const char * const msg,
 static void
 _send_room_presence(xmpp_conn_t *conn, xmpp_stanza_t *presence)
 {
-    GList *rooms = muc_get_active_room_list();
+    GList *rooms_p = muc_get_active_room_list();
+    GList *rooms = rooms_p;
+
     while (rooms != NULL) {
         const char *room = rooms->data;
         const char *nick = muc_get_room_nick(room);
-        char *full_room_jid = create_fulljid(room, nick);
 
-        xmpp_stanza_set_attribute(presence, STANZA_ATTR_TO, full_room_jid);
-        log_debug("Sending presence to room: %s", full_room_jid);
-        xmpp_send(conn, presence);
-        free(full_room_jid);
+        if (nick != NULL) {
+            char *full_room_jid = create_fulljid(room, nick);
+
+            xmpp_stanza_set_attribute(presence, STANZA_ATTR_TO, full_room_jid);
+            log_debug("Sending presence to room: %s", full_room_jid);
+            xmpp_send(conn, presence);
+            free(full_room_jid);
+        }
 
         rooms = g_list_next(rooms);
     }
-    g_list_free(rooms);
+
+    if (rooms_p != NULL) {
+        g_list_free(rooms_p);
+    }
 }
 
 void
@@ -347,9 +364,13 @@ _subscribe_handler(xmpp_conn_t * const conn,
     xmpp_stanza_t * const stanza, void * const userdata)
 {
     char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM);
-    Jid *from_jid = jid_create(from);
     log_debug("Subscribe presence handler fired for %s", from);
 
+    Jid *from_jid = jid_create(from);
+    if (from_jid == NULL) {
+        return 1;
+    }
+
     prof_handle_subscription(from_jid->barejid, PRESENCE_SUBSCRIBE);
     autocomplete_add(sub_requests_ac, strdup(from_jid->barejid));
 
@@ -368,6 +389,11 @@ _unavailable_handler(xmpp_conn_t * const conn,
 
     Jid *my_jid = jid_create(jid);
     Jid *from_jid = jid_create(from);
+    if (my_jid == NULL || from_jid == NULL) {
+        jid_destroy(my_jid);
+        jid_destroy(from_jid);
+        return 1;
+    }
 
     char *status_str = stanza_get_status(stanza, NULL);
 
@@ -385,7 +411,7 @@ _unavailable_handler(xmpp_conn_t * const conn,
         }
     }
 
-    FREE_SET_NULL(status_str);
+    free(status_str);
     jid_destroy(my_jid);
     jid_destroy(from_jid);
 
@@ -420,6 +446,11 @@ _available_handler(xmpp_conn_t * const conn,
 
     Jid *my_jid = jid_create(jid);
     Jid *from_jid = jid_create(from);
+    if (my_jid == NULL || from_jid == NULL) {
+        jid_destroy(my_jid);
+        jid_destroy(from_jid);
+        return 1;
+    }
 
     char *show_str = stanza_get_show(stanza, "online");
     char *status_str = stanza_get_status(stanza, NULL);
@@ -471,8 +502,8 @@ _available_handler(xmpp_conn_t * const conn,
             last_activity);
     }
 
-    FREE_SET_NULL(status_str);
-    FREE_SET_NULL(show_str);
+    free(status_str);
+    free(show_str);
     jid_destroy(my_jid);
     jid_destroy(from_jid);
 
@@ -515,6 +546,10 @@ _get_caps_key(xmpp_stanza_t * const stanza)
 
     log_debug("Presence contains capabilities.");
 
+    if (node == NULL) {
+        return NULL;
+    }
+
     // xep-0115
     if ((hash_type != NULL) && (strcmp(hash_type, "sha-1") == 0)) {
         log_debug("Hash type %s supported.", hash_type);
@@ -544,6 +579,8 @@ _get_caps_key(xmpp_stanza_t * const stanza)
         g_string_free(id_str, TRUE);
     }
 
+    g_free(node);
+
     return caps_key;
 }
 
@@ -556,10 +593,11 @@ _room_presence_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
         return 1;
     }
 
-    const char *jid = xmpp_conn_get_jid(conn);
     char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM);
-    Jid *my_jid = jid_create(jid);
     Jid *from_jid = jid_create(from);
+    if (from_jid == NULL || from_jid->resourcepart == NULL) {
+        return 1;
+    }
 
     char *room = from_jid->barejid;
     char *nick = from_jid->resourcepart;
@@ -592,7 +630,7 @@ _room_presence_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
     // handle presence from room members
     } else {
         char *type = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_TYPE);
-        char *show_str, *status_str;
+        char *status_str;
 
         char *caps_key = NULL;
         if (stanza_contains_caps(stanza)) {
@@ -608,12 +646,15 @@ _room_presence_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
             // handle nickname change
             if (stanza_is_room_nick_change(stanza)) {
                 char *new_nick = stanza_get_new_nick(stanza);
-                muc_set_roster_pending_nick_change(room, new_nick, nick);
+                if (new_nick != NULL) {
+                    muc_set_roster_pending_nick_change(room, new_nick, nick);
+                    free(new_nick);
+                }
             } else {
                 prof_handle_room_member_offline(room, nick, "offline", status_str);
             }
         } else {
-            show_str = stanza_get_show(stanza, "online");
+            char *show_str = stanza_get_show(stanza, "online");
             if (!muc_get_roster_received(room)) {
                 muc_add_to_roster(room, nick, show_str, status_str, caps_key);
             } else {
@@ -622,6 +663,7 @@ _room_presence_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
                 if (old_nick != NULL) {
                     muc_add_to_roster(room, nick, show_str, status_str, caps_key);
                     prof_handle_room_member_nick_change(room, old_nick, nick);
+                    free(old_nick);
                 } else {
                     if (!muc_nick_in_roster(room, nick)) {
                         prof_handle_room_member_online(room, nick, show_str, status_str, caps_key);
@@ -631,13 +673,13 @@ _room_presence_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
                 }
             }
 
-           FREE_SET_NULL(show_str);
+           free(show_str);
         }
 
-        FREE_SET_NULL(status_str);
+        free(status_str);
+        free(caps_key);
     }
 
-    jid_destroy(my_jid);
     jid_destroy(from_jid);
 
     return 1;
diff --git a/src/xmpp/stanza.c b/src/xmpp/stanza.c
index e470c3b0..7d7a0949 100644
--- a/src/xmpp/stanza.c
+++ b/src/xmpp/stanza.c
@@ -35,6 +35,63 @@
 
 static int _field_compare(FormField *f1, FormField *f2);
 
+#if 0
+xmpp_stanza_t *
+stanza_create_storage_bookmarks(xmpp_ctx_t *ctx)
+{
+    xmpp_stanza_t *iq, *pubsub, *items;
+
+    /* TODO: check pointers for NULL */
+    iq = xmpp_stanza_new(ctx);
+    pubsub = xmpp_stanza_new(ctx);
+    items = xmpp_stanza_new(ctx);
+
+    xmpp_stanza_set_name(iq, STANZA_NAME_IQ);
+    xmpp_stanza_set_type(iq, STANZA_TYPE_GET);
+
+    xmpp_stanza_set_name(pubsub, STANZA_NAME_PUBSUB);
+    xmpp_stanza_set_ns(pubsub, STANZA_NS_PUBSUB);
+
+    xmpp_stanza_set_name(items, STANZA_NAME_ITEMS);
+    xmpp_stanza_set_attribute(items, "node", "storage:bookmarks");
+
+    xmpp_stanza_add_child(pubsub, items);
+    xmpp_stanza_add_child(iq, pubsub);
+    xmpp_stanza_release(items);
+    xmpp_stanza_release(pubsub);
+
+    return iq;
+}
+#endif
+
+xmpp_stanza_t *
+stanza_create_storage_bookmarks(xmpp_ctx_t *ctx)
+{
+    xmpp_stanza_t *iq, *query, *storage;
+
+    /* TODO: check pointers for NULL */
+    iq = xmpp_stanza_new(ctx);
+    query = xmpp_stanza_new(ctx);
+    storage = xmpp_stanza_new(ctx);
+
+    xmpp_stanza_set_name(iq, STANZA_NAME_IQ);
+    xmpp_stanza_set_type(iq, STANZA_TYPE_GET);
+    xmpp_stanza_set_ns(iq, "jabber:client");
+
+    xmpp_stanza_set_name(query, STANZA_NAME_QUERY);
+    xmpp_stanza_set_ns(query, "jabber:iq:private");
+
+    xmpp_stanza_set_name(storage, STANZA_NAME_STORAGE);
+    xmpp_stanza_set_ns(storage, "storage:bookmarks");
+
+    xmpp_stanza_add_child(query, storage);
+    xmpp_stanza_add_child(iq, query);
+    xmpp_stanza_release(storage);
+    xmpp_stanza_release(query);
+
+    return iq;
+}
+
 xmpp_stanza_t *
 stanza_create_chat_state(xmpp_ctx_t *ctx, const char * const recipient,
     const char * const state)
@@ -85,7 +142,7 @@ stanza_create_message(xmpp_ctx_t *ctx, const char * const recipient,
         xmpp_stanza_set_name(chat_state, state);
         xmpp_stanza_set_ns(chat_state, STANZA_NS_CHATSTATES);
         xmpp_stanza_add_child(msg, chat_state);
-	xmpp_stanza_release(chat_state);
+        xmpp_stanza_release(chat_state);
     }
 
     return msg;
@@ -815,12 +872,11 @@ void
 stanza_destroy_form(DataForm *form)
 {
     if (form != NULL) {
-        FREE_SET_NULL(form->form_type);
         if (form->fields != NULL) {
             GSList *curr_field = form->fields;
             while (curr_field != NULL) {
                 FormField *field = curr_field->data;
-                FREE_SET_NULL(field->var);
+                free(field->var);
                 if ((field->values) != NULL) {
                     g_slist_free_full(field->values, free);
                 }
@@ -829,6 +885,7 @@ stanza_destroy_form(DataForm *form)
             g_slist_free_full(form->fields, free);
         }
 
+        free(form->form_type);
         free(form);
     }
 }
@@ -916,7 +973,7 @@ stanza_attach_caps(xmpp_ctx_t * const ctx, xmpp_stanza_t * const presence)
     xmpp_stanza_add_child(presence, caps);
     xmpp_stanza_release(caps);
     xmpp_stanza_release(query);
-    FREE_SET_NULL(sha1);
+    g_free(sha1);
 }
 
 const char *
diff --git a/src/xmpp/stanza.h b/src/xmpp/stanza.h
index ad777f24..108b0806 100644
--- a/src/xmpp/stanza.h
+++ b/src/xmpp/stanza.h
@@ -52,6 +52,9 @@
 #define STANZA_NAME_INVITE "invite"
 #define STANZA_NAME_REASON "reason"
 #define STANZA_NAME_GROUP "group"
+#define STANZA_NAME_PUBSUB "pubsub"
+#define STANZA_NAME_STORAGE "storage"
+#define STANZA_NAME_CONFERENCE "conference"
 
 #define STANZA_TYPE_CHAT "chat"
 #define STANZA_TYPE_GROUPCHAT "groupchat"
@@ -100,6 +103,7 @@
 #define STANZA_NS_VERSION "jabber:iq:version"
 #define STANZA_NS_CONFERENCE "jabber:x:conference"
 #define STANZA_NS_CAPTCHA "urn:xmpp:captcha"
+#define STANZA_NS_PUBSUB "http://jabber.org/protocol/pubsub"
 
 #define STANZA_DATAFORM_SOFTWARE "urn:xmpp:dataforms:softwareinfo"
 
@@ -113,6 +117,8 @@ typedef struct data_form_t {
     GSList *fields;
 } DataForm;
 
+xmpp_stanza_t* stanza_create_storage_bookmarks(xmpp_ctx_t *ctx);
+
 xmpp_stanza_t* stanza_create_chat_state(xmpp_ctx_t *ctx,
     const char * const recipient, const char * const state);