Fix up the AGI doc dump CLI command and update the AGI commands tex file to not
[asterisk/asterisk.git] / res / res_jabber.c
index 3a002fc..78ff7d9 100644 (file)
 /*! \file
  * \brief A resource for interfacing asterisk directly as a client
  * or a component to a jabber compliant server.
+ *
+ * \extref Iksemel http://iksemel.jabberstudio.org/
+ *
+ * \todo If you unload this module, chan_gtalk/jingle will be dead. How do we handle that?
+ * \todo If you have TLS, you can't unload this module. See bug #9738. This needs to be fixed,
+ *       but the bug is in the unmantained Iksemel library
+ *
  */
 
 /*** MODULEINFO
        <depend>iksemel</depend>
+       <use>gnutls</use>
  ***/
 
 #include "asterisk.h"
@@ -54,7 +62,16 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #define JABBER_CONFIG "jabber.conf"
 
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
 /*-- Forward declarations */
+static int aji_start_sasl(iksparser *prs, enum ikssasltype type, char *username, char *pass);
 static int aji_highest_bit(int number);
 static void aji_buddy_destroy(struct aji_buddy *obj);
 static void aji_client_destroy(struct aji_client *obj);
@@ -67,8 +84,7 @@ static void aji_handle_message(struct aji_client *client, ikspak *pak);
 static void aji_handle_presence(struct aji_client *client, ikspak *pak);
 static void aji_handle_subscribe(struct aji_client *client, ikspak *pak);
 static void *aji_recv_loop(void *data);
-static int aji_component_initialize(struct aji_client *client);
-static int aji_client_initialize(struct aji_client *client);
+static int aji_initialize(struct aji_client *client);
 static int aji_client_connect(void *data, ikspak *pak);
 static void aji_set_presence(struct aji_client *client, char *to, char *from, int level, char *desc);
 static int aji_do_debug(int fd, int argc, char *argv[]);
@@ -159,15 +175,15 @@ static char *ajistatus_descrip =
 "             If not in roster variable will = 7\n";
 
 struct aji_client_container clients;
-
-struct aji_capabilities *capabilities;
+struct aji_capabilities *capabilities = NULL;
 
 /*! \brief Global flags, initialized to default values */
 static struct ast_flags globalflags = { AJI_AUTOPRUNE | AJI_AUTOREGISTER };
+static int tls_initialized = FALSE;
 
 /*!
  * \brief Deletes the aji_client data structure.
- * \param obj is the structure we will delete.
+ * \param obj aji_client The structure we will delete.
  * \return void.
  */
 static void aji_client_destroy(struct aji_client *obj)
@@ -181,17 +197,17 @@ static void aji_client_destroy(struct aji_client *obj)
        AST_LIST_LOCK(&obj->messages);
        while ((tmp = AST_LIST_REMOVE_HEAD(&obj->messages, list))) {
                if (tmp->from)
-                       free(tmp->from);
+                       ast_free(tmp->from);
                if (tmp->message)
-                       free(tmp->message);
+                       ast_free(tmp->message);
        }
        AST_LIST_HEAD_DESTROY(&obj->messages);
-       free(obj);
+       ast_free(obj);
 }
 
 /*!
  * \brief Deletes the aji_buddy data structure.
- * \param obj is the structure we will delete.
+ * \param obj aji_buddy The structure we will delete.
  * \return void.
  */
 static void aji_buddy_destroy(struct aji_buddy *obj)
@@ -200,13 +216,22 @@ static void aji_buddy_destroy(struct aji_buddy *obj)
 
        while ((tmp = obj->resources)) {
                obj->resources = obj->resources->next;
-               free(tmp->description);
-               free(tmp);
+               ast_free(tmp->description);
+               ast_free(tmp);
        }
 
-       free(obj);
+       ast_free(obj);
 }
 
+/*!
+ * \brief Find version in XML stream and populate our capabilities list
+ * \param node the node attribute in the caps element we'll look for or add to 
+ * our list
+ * \param version the version attribute in the caps element we'll look for or 
+ * add to our list
+ * \param pak struct The XML stanza we're processing
+ * \return a pointer to the added or found aji_version structure
+ */ 
 static struct aji_version *aji_find_version(char *node, char *version, ikspak *pak)
 {
        struct aji_capabilities *list = NULL;
@@ -226,8 +251,10 @@ static struct aji_version *aji_find_version(char *node, char *version, ikspak *p
                                         return res;
                                 res = res->next;
                        }
+                       /* Specified version not found. Let's add it to 
+                          this node in our capabilities list */
                        if(!res) {
-                               res = (struct aji_version *)malloc(sizeof(struct aji_version));
+                               res = ast_malloc(sizeof(*res));
                                if(!res) {
                                        ast_log(LOG_ERROR, "Out of memory!\n");
                                        return NULL;
@@ -242,13 +269,14 @@ static struct aji_version *aji_find_version(char *node, char *version, ikspak *p
                }
                list = list->next;
        }
+       /* Specified node not found. Let's add it our capabilities list */
        if(!list) {
-               list = (struct aji_capabilities *)malloc(sizeof(struct aji_capabilities));
+               list = ast_malloc(sizeof(*list));
                if(!list) {
                        ast_log(LOG_ERROR, "Out of memory!\n");
                        return NULL;
                }
-               res = (struct aji_version *)malloc(sizeof(struct aji_version));
+               res = ast_malloc(sizeof(*res));
                if(!res) {
                        ast_log(LOG_ERROR, "Out of memory!\n");
                        return NULL;
@@ -257,14 +285,19 @@ static struct aji_version *aji_find_version(char *node, char *version, ikspak *p
                ast_copy_string(res->version, version, sizeof(res->version));
                res->jingle = 0;
                res->parent = list;
-               res->next = list->versions;
+               res->next = NULL;
                list->versions = res;
                list->next = capabilities;
                capabilities = list;
        }
        return res;
 }
-
+/*!
+ * \brief Find the aji_resource we want
+ * \param buddy aji_buddy A buddy
+ * \param name 
+ * \return aji_resource object
+*/
 static struct aji_resource *aji_find_resource(struct aji_buddy *buddy, char *name)
 {
        struct aji_resource *res = NULL;
@@ -280,6 +313,11 @@ static struct aji_resource *aji_find_resource(struct aji_buddy *buddy, char *nam
        return res;
 }
 
+/*!
+ * \brief Jabber GTalk function
+ * \param node iks
+ * \return 1 on success, 0 on failure.
+*/
 static int gtalk_yuck(iks *node)
 {
        if (iks_find_with_attrib(node, "c", "node", "http://www.google.com/xmpp/client/caps"))
@@ -289,7 +327,7 @@ static int gtalk_yuck(iks *node)
 
 /*!
  * \brief Detects the highest bit in a number.
- * \param Number you want to have evaluated.
+ * \param number  Number you want to have evaluated.
  * \return the highest power of 2 that can go into the number.
  */
 static int aji_highest_bit(int number)
@@ -304,6 +342,13 @@ static int aji_highest_bit(int number)
        return (1 << x);
 }
 
+/*!
+ * \brief Setup the authentication struct
+ * \param id iksid 
+ * \param pass password
+ * \param sid
+ * \return x iks
+*/
 static iks *jabber_make_auth(iksid * id, const char *pass, const char *sid)
 {
        iks *x, *y;
@@ -328,8 +373,9 @@ static iks *jabber_make_auth(iksid * id, const char *pass, const char *sid)
 /*!
  * \brief Dial plan function status(). puts the status of watched user 
    into a channel variable.
- * \param channel, and username,watched user, status var
- * \return 0.
+ * \param chan ast_channel
+ * \param data
+ * \return 0 on success, -1 on error
  */
 static int aji_status_exec(struct ast_channel *chan, void *data)
 {
@@ -392,8 +438,9 @@ static int aji_status_exec(struct ast_channel *chan, void *data)
 
 /*!
  * \brief Dial plan function to send a message.
- * \param channel, and data, data is sender, reciever, message.
- * \return 0.
+ * \param chan ast_channel
+ * \param data  Data is sender|reciever|message.
+ * \return 0 on success,-1 on error.
  */
 static int aji_send_exec(struct ast_channel *chan, void *data)
 {
@@ -429,12 +476,17 @@ static int aji_send_exec(struct ast_channel *chan, void *data)
 
 /*!
  * \brief the debug loop.
- * \param aji_client structure, xml data as string, size of string, direction of packet, 1 for inbound 0 for outbound.
+ * \param data void
+ * \param xmpp xml data as string
+ * \param size size of string
+ * \param is_incoming direction of packet 1 for inbound 0 for outbound.
  */
 static void aji_log_hook(void *data, const char *xmpp, size_t size, int is_incoming)
 {
        struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
-       manager_event(EVENT_FLAG_USER, "JabberEvent", "Account: %s\r\nPacket: %s\r\n", client->name, xmpp);
+
+       if (!ast_strlen_zero(xmpp))
+               manager_event(EVENT_FLAG_USER, "JabberEvent", "Account: %s\r\nPacket: %s\r\n", client->name, xmpp);
 
        if (client->debug) {
                if (is_incoming)
@@ -452,8 +504,57 @@ static void aji_log_hook(void *data, const char *xmpp, size_t size, int is_incom
 }
 
 /*!
+ * \brief A wrapper function for iks_start_sasl
+ * \param prs the XML parser
+ * \param type the SASL authentication type. Supported types are PLAIN and MD5
+ * \param username
+ * \param pass
+ * If SASL authentication type is MD5, we simply call iks_start_sasl().
+ * If type is PLAIN, we compute the authentication string by ourselves, 
+ * because it looks like Google's jabber server does not accept the value 
+ * computed with iks_start_sasl().
+ * \return IKS_OK on success, IKSNET_NOTSUPP on failure.
+ */
+static int aji_start_sasl(iksparser *prs, enum ikssasltype type, char *username, char *pass)
+{
+       iks *x = NULL;
+       int len;
+       char *s;
+       char *base64;
+
+       if (type == IKS_STREAM_SASL_MD5)
+               return iks_start_sasl(prs, type, username, pass);
+
+       x = iks_new("auth"); 
+       if (!x) {
+               ast_log(LOG_ERROR, "Out of memory.\n");
+               return IKS_NET_NOTSUPP;
+       }
+
+       iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_SASL);
+       len = strlen(username) + strlen(pass) + 3;
+       /* XXX Check return values XXX */
+       s = ast_malloc(80 + len);
+       base64 = ast_malloc(80 + len * 2);
+       iks_insert_attrib(x, "mechanism", "PLAIN");
+       sprintf(s, "%c%s%c%s", 0, username, 0, pass);
+       ast_base64encode(base64, (const unsigned char *) s, len, len * 2);
+       iks_insert_cdata(x, base64, 0);
+       iks_send(prs, x);
+       iks_delete(x);
+       if (base64)
+               free(base64);
+       if (s)
+               free(s);        
+
+       return IKS_OK;
+}
+
+/*!
  * \brief The action hook parses the inbound packets, constantly running.
- * \param aji client structure, type of packet, the actual packet.
+ * \param data aji client structure 
+ * \param type type of packet 
+ * \param node the actual packet.
  * \return IKS_OK or IKS_HOOK .
  */
 static int aji_act_hook(void *data, int type, iks *node)
@@ -461,6 +562,7 @@ static int aji_act_hook(void *data, int type, iks *node)
        struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
        ikspak *pak = NULL;
        iks *auth = NULL;
+       int features = 0;
 
        if(!node) {
                ast_log(LOG_ERROR, "aji_act_hook was called with out a packet\n"); /* most likely cause type is IKS_NODE_ERROR lost connection */
@@ -468,16 +570,22 @@ static int aji_act_hook(void *data, int type, iks *node)
                return IKS_HOOK;
        }
 
+       if (client->state == AJI_DISCONNECTING) {
+               ASTOBJ_UNREF(client, aji_client_destroy);
+               return IKS_HOOK;
+       }
+
        pak = iks_packet(node);
 
        if (!client->component) { /*client */
                switch (type) {
                case IKS_NODE_START:
                        if (client->usetls && !iks_is_secure(client->p)) {
-                               if (iks_has_tls())
+                               if (iks_has_tls()) {
                                        iks_start_tls(client->p);
-                               else
-                                       ast_log(LOG_ERROR, "gnuTLS not installed.\n");
+                                       tls_initialized = TRUE;
+                               } else
+                                       ast_log(LOG_ERROR, "gnuTLS not installed. You need to recompile the Iksemel library with gnuTLS support\n");
                                break;
                        }
                        if (!client->usesasl) {
@@ -495,79 +603,59 @@ static int aji_act_hook(void *data, int type, iks *node)
                        break;
 
                case IKS_NODE_NORMAL:
-                       {
-                               int features = 0;
-                               if (!strcmp("stream:features", iks_name(node))) {
-                                       features = iks_stream_features(node);
-                                       if (client->usesasl) {
-                                               if (client->usetls && !iks_is_secure(client->p))
-                                                       break;
-                                               if (client->authorized) {
-                                                       if (features & IKS_STREAM_BIND) {
-                                                               iks_filter_add_rule (client->f, aji_client_connect, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_DONE);
-                                                               auth = iks_make_resource_bind(client->jid);
-                                                               if (auth) {
-                                                                       iks_insert_attrib(auth, "id", client->mid);
-                                                                       ast_aji_increment_mid(client->mid);
-                                                                       iks_send(client->p, auth);
-                                                                       iks_delete(auth);
-                                                               } else {
-                                                                       ast_log(LOG_ERROR, "Out of memory.\n");
-                                                                       break;
-                                                               }
-                                                       }
-                                                       if (features & IKS_STREAM_SESSION) {
-                                                               iks_filter_add_rule (client->f, aji_client_connect, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, "auth", IKS_RULE_DONE);
-                                                               auth = iks_make_session();
-                                                               if (auth) {
-                                                                       iks_insert_attrib(auth, "id", "auth");
-                                                                       ast_aji_increment_mid(client->mid);
-                                                                       iks_send(client->p, auth);
-                                                                       iks_delete(auth);
-                                                               } else {
-                                                                       ast_log(LOG_ERROR, "Out of memory.\n");
-                                                               }
+                       if (!strcmp("stream:features", iks_name(node))) {
+                               features = iks_stream_features(node);
+                               if (client->usesasl) {
+                                       if (client->usetls && !iks_is_secure(client->p))
+                                               break;
+                                       if (client->authorized) {
+                                               if (features & IKS_STREAM_BIND) {
+                                                       iks_filter_add_rule (client->f, aji_client_connect, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_DONE);
+                                                       auth = iks_make_resource_bind(client->jid);
+                                                       if (auth) {
+                                                               iks_insert_attrib(auth, "id", client->mid);
+                                                               ast_aji_increment_mid(client->mid);
+                                                               iks_send(client->p, auth);
+                                                               iks_delete(auth);
+                                                       } else {
+                                                               ast_log(LOG_ERROR, "Out of memory.\n");
+                                                               break;
                                                        }
-                                               } else {
-                                                       features = aji_highest_bit(features);
-                                                       if (features == IKS_STREAM_SASL_MD5)
-                                                               iks_start_sasl(client->p, IKS_SASL_DIGEST_MD5, client->jid->user, client->password);
-                                                       else {
-                                                               if (features == IKS_STREAM_SASL_PLAIN) {
-                                                                       iks *x = NULL;
-                                                                       x = iks_new("auth");
-                                                                       if (x) {
-                                                                               int len = strlen(client->jid->user) + strlen(client->password) + 3;
-                                                                               /* XXX Check return values XXX */
-                                                                               char *s = ast_malloc(80 + len);
-                                                                               char *base64 = ast_malloc(80 + len * 2);
-
-                                                                               iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_SASL);
-                                                                               iks_insert_attrib(x, "mechanism", "PLAIN");
-                                                                               sprintf(s, "%c%s%c%s", 0, client->jid->user, 0, client->password);
-                                                                               ast_base64encode(base64, (const unsigned char *) s, len, len * 2);
-                                                                               iks_insert_cdata(x, base64, 0);
-                                                                               iks_send(client->p, x);
-                                                                               iks_delete(x);
-                                                                               if (base64)
-                                                                                       free(base64);
-                                                                               if (s)
-                                                                                       free(s);
-                                                                       } else {
-                                                                               ast_log(LOG_ERROR, "Out of memory.\n");
-                                                                       }
-                                                               }
+                                               }
+                                               if (features & IKS_STREAM_SESSION) {
+                                                       iks_filter_add_rule (client->f, aji_client_connect, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, "auth", IKS_RULE_DONE);
+                                                       auth = iks_make_session();
+                                                       if (auth) {
+                                                               iks_insert_attrib(auth, "id", "auth");
+                                                               ast_aji_increment_mid(client->mid);
+                                                               iks_send(client->p, auth);
+                                                               iks_delete(auth);
+                                                       } else {
+                                                               ast_log(LOG_ERROR, "Out of memory.\n");
                                                        }
                                                }
+                                       } else {
+                                               int ret;
+                                               if (!client->jid->user) {
+                                                       ast_log(LOG_ERROR, "Malformed Jabber ID : %s (domain missing?)\n", client->jid->full);
+                                                       break;
+                                               }
+                                               features = aji_highest_bit(features);
+                                               ret = aji_start_sasl(client->p, features, client->jid->user, client->password);
+                                               if (ret != IKS_OK) {
+                                                       ASTOBJ_UNREF(client, aji_client_destroy);
+                                                       return IKS_HOOK;
+                                               }
+                                               break;
                                        }
-                               } else if (!strcmp("failure", iks_name(node))) {
-                                       ast_log(LOG_ERROR, "JABBER: encryption failure. possible bad password.\n");
-                               } else if (!strcmp("success", iks_name(node))) {
-                                       client->authorized = 1;
-                                       iks_send_header(client->p, client->jid->server);
                                }
-                               break;
+                       } else if (!strcmp("failure", iks_name(node))) {
+                               ast_log(LOG_ERROR, "JABBER: encryption failure. possible bad password.\n");
+                       } else if (!strcmp("success", iks_name(node))) {
+                               client->authorized = 1;
+                               iks_send_header(client->p, client->jid->server);
                        }
+                       break;
                case IKS_NODE_ERROR: 
                                ast_log(LOG_ERROR, "JABBER: Node Error\n");
                                ASTOBJ_UNREF(client, aji_client_destroy);
@@ -591,7 +679,7 @@ static int aji_act_hook(void *data, int type, iks *node)
                                asprintf(&handshake, "<handshake>%s</handshake>", shasum);
                                if (handshake) {
                                        iks_send_raw(client->p, handshake);
-                                       free(handshake);
+                                       ast_free(handshake);
                                        handshake = NULL;
                                }
                                client->state = AJI_CONNECTING;
@@ -620,32 +708,26 @@ static int aji_act_hook(void *data, int type, iks *node)
 
        switch (pak->type) {
        case IKS_PAK_NONE:
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "JABBER: I Don't know what to do with you NONE\n");
+               ast_debug(1, "JABBER: I Don't know what to do with you NONE\n");
                break;
        case IKS_PAK_MESSAGE:
                aji_handle_message(client, pak);
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "JABBER: I Don't know what to do with you MESSAGE\n");
+               ast_debug(1, "JABBER: I Don't know what to do with you MESSAGE\n");
                break;
        case IKS_PAK_PRESENCE:
                aji_handle_presence(client, pak);
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "JABBER: I Do know how to handle presence!!\n");
+               ast_debug(1, "JABBER: I Do know how to handle presence!!\n");
                break;
        case IKS_PAK_S10N:
                aji_handle_subscribe(client, pak);
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "JABBER: I Dont know S10N subscribe!!\n");
+               ast_debug(1, "JABBER: I Dont know S10N subscribe!!\n");
                break;
        case IKS_PAK_IQ:
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "JABBER: I Dont have an IQ!!!\n");
+               ast_debug(1, "JABBER: I Dont have an IQ!!!\n");
                aji_handle_iq(client, node);
                break;
        default:
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "JABBER: I Dont know %i\n", pak->type);
+               ast_debug(1, "JABBER: I Dont know %i\n", pak->type);
                break;
        }
        
@@ -657,7 +739,12 @@ static int aji_act_hook(void *data, int type, iks *node)
        ASTOBJ_UNREF(client, aji_client_destroy);
        return IKS_OK;
 }
-
+/*!
+ * \brief Uknown
+ * \param data void
+ * \param pak ikspak
+ * \return IKS_FILTER_EAT.
+*/
 static int aji_register_approve_handler(void *data, ikspak *pak)
 {
        struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
@@ -696,7 +783,12 @@ static int aji_register_approve_handler(void *data, ikspak *pak)
        ASTOBJ_UNREF(client, aji_client_destroy);
        return IKS_FILTER_EAT;
 }
-
+/*!
+ * \brief register query
+ * \param data incoming aji_client request
+ * \param pak ikspak
+ * \return IKS_FILTER_EAT.
+*/
 static int aji_register_query_handler(void *data, ikspak *pak)
 {
        struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
@@ -768,6 +860,12 @@ static int aji_register_query_handler(void *data, ikspak *pak)
        return IKS_FILTER_EAT;
 }
 
+/*!
+ * \brief Handles stuff
+ * \param data void
+ * \param pak ikspak 
+ * \return IKS_FILTER_EAT.
+*/
 static int aji_ditems_handler(void *data, ikspak *pak)
 {
        struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
@@ -863,7 +961,12 @@ static int aji_ditems_handler(void *data, ikspak *pak)
        return IKS_FILTER_EAT;
 
 }
-
+/*!
+ * \brief Handle add extra info
+ * \param data void
+ * \param pak ikspak
+ * \return IKS_FILTER_EAT
+*/
 static int aji_client_info_handler(void *data, ikspak *pak)
 {
        struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
@@ -922,7 +1025,12 @@ static int aji_client_info_handler(void *data, ikspak *pak)
        ASTOBJ_UNREF(client, aji_client_destroy);
        return IKS_FILTER_EAT;
 }
-
+/*!
+ * \brief Handler of the return info packet
+ * \param data aji_client
+ * \param pak ikspak
+ * \return IKS_FILTER_EAT
+*/
 static int aji_dinfo_handler(void *data, ikspak *pak)
 {
        struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
@@ -1073,8 +1181,9 @@ static int aji_dinfo_handler(void *data, ikspak *pak)
 }
 
 /*!
- * \brief Handles <iq> tags.
- * \param client structure and the iq node.
+ * \brief Handles \verbatim <iq> \endverbatim tags.
+ * \param client aji_client
+ * \param node iks 
  * \return void.
  */
 static void aji_handle_iq(struct aji_client *client, iks *node)
@@ -1084,20 +1193,20 @@ static void aji_handle_iq(struct aji_client *client, iks *node)
 
 /*!
  * \brief Handles presence packets.
- * \param client structure and the node.
- * \return void.
+ * \param client aji_client
+ * \param pak ikspak the node
  */
 static void aji_handle_message(struct aji_client *client, ikspak *pak)
 {
        struct aji_message *insert, *tmp;
        int flag = 0;
        
-       if (!(insert = ast_calloc(1, sizeof(struct aji_message))))
+       if (!(insert = ast_calloc(1, sizeof(*insert))))
                return;
        time(&insert->arrived);
        if (iks_find_cdata(pak->x, "body"))
                insert->message = ast_strdup(iks_find_cdata(pak->x, "body"));
-       if(pak->id)
+       if (pak->id)
                ast_copy_string(insert->id, pak->id, sizeof(insert->message));
        if (pak->from)
                insert->from = ast_strdup(pak->from->full);
@@ -1106,23 +1215,27 @@ static void aji_handle_message(struct aji_client *client, ikspak *pak)
                if (flag) {
                        AST_LIST_REMOVE_CURRENT(&client->messages, list);
                        if (tmp->from)
-                               free(tmp->from);
+                               ast_free(tmp->from);
                        if (tmp->message)
-                               free(tmp->message);
+                               ast_free(tmp->message);
                } else if (difftime(time(NULL), tmp->arrived) >= client->message_timeout) {
                        flag = 1;
                        AST_LIST_REMOVE_CURRENT(&client->messages, list);
                        if (tmp->from)
-                               free(tmp->from);
+                               ast_free(tmp->from);
                        if (tmp->message)
-                               free(tmp->message);
+                               ast_free(tmp->message);
                }
        }
        AST_LIST_TRAVERSE_SAFE_END;
        AST_LIST_INSERT_HEAD(&client->messages, insert, list);
        AST_LIST_UNLOCK(&client->messages);
 }
-
+/*!
+ * \brief Check the presence info
+ * \param client aji_client
+ * \param pak ikspak
+*/
 static void aji_handle_presence(struct aji_client *client, ikspak *pak)
 {
        int status, priority;
@@ -1152,7 +1265,7 @@ static void aji_handle_presence(struct aji_client *client, ikspak *pak)
        while (tmp) {
                if (!strcasecmp(tmp->resource, pak->from->resource)) {
                        tmp->status = status;
-                       if (tmp->description) free(tmp->description);
+                       if (tmp->description) ast_free(tmp->description);
                        tmp->description = descrip;
                        found = tmp;
                        if (status == 6) {      /* Sign off Destroy resource */
@@ -1169,7 +1282,7 @@ static void aji_handle_presence(struct aji_client *client, ikspak *pak)
                                        else
                                                buddy->resources = NULL;
                                }
-                               free(found);
+                               ast_free(found);
                                found = NULL;
                                break;
                        }
@@ -1209,8 +1322,7 @@ static void aji_handle_presence(struct aji_client *client, ikspak *pak)
        }
 
        if (!found && status != 6) {
-               found = (struct aji_resource *) malloc(sizeof(struct aji_resource));
-               memset(found, 0, sizeof(struct aji_resource));
+               found = ast_calloc(1, sizeof(*found));
 
                if (!found) {
                        ast_log(LOG_ERROR, "Out of memory!\n");
@@ -1253,8 +1365,7 @@ static void aji_handle_presence(struct aji_client *client, ikspak *pak)
                if(gtalk_yuck(pak->x)) /* gtalk should do discover */
                        found->cap->jingle = 1;
                if(found->cap->jingle && option_debug > 4) {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG,"Special case for google till they support discover.\n");
+                       ast_debug(1,"Special case for google till they support discover.\n");
                }
                else {
                        iks *iq, *query;
@@ -1316,7 +1427,8 @@ static void aji_handle_presence(struct aji_client *client, ikspak *pak)
 
 /*!
  * \brief handles subscription requests.
- * \param aji_client struct and xml packet.
+ * \param client aji_client
+ * \param pak ikspak iksemel packet.
  * \return void.
  */
 static void aji_handle_subscribe(struct aji_client *client, ikspak *pak)
@@ -1366,7 +1478,9 @@ static void aji_handle_subscribe(struct aji_client *client, ikspak *pak)
 
 /*!
  * \brief sends messages.
- * \param aji_client struct , reciever, message.
+ * \param client aji_client 
+ * \param address
+ * \param message
  * \return 1.
  */
 int ast_aji_send(struct aji_client *client, const char *address, const char *message)
@@ -1390,7 +1504,10 @@ int ast_aji_send(struct aji_client *client, const char *address, const char *mes
 
 /*!
  * \brief create a chatroom.
- * \param aji_client struct , room, server, topic for the room.
+ * \param client aji_client
+ * \param room name of room
+ * \param server name of server
+ * \param topic topic for the room.
  * \return 0.
  */
 int ast_aji_create_chat(struct aji_client *client, char *room, char *server, char *topic)
@@ -1411,7 +1528,8 @@ int ast_aji_create_chat(struct aji_client *client, char *room, char *server, cha
 
 /*!
  * \brief join a chatroom.
- * \param aji_client struct , room.
+ * \param client aji_client 
+ * \param room room to join
  * \return res.
  */
 int ast_aji_join_chat(struct aji_client *client, char *room)
@@ -1439,7 +1557,10 @@ int ast_aji_join_chat(struct aji_client *client, char *room)
 
 /*!
  * \brief invite to a chatroom.
- * \param aji_client struct ,user, room, message.
+ * \param client aji_client
+ * \param user 
+ * \param room
+ * \param message
  * \return res.
  */
 int ast_aji_invite_chat(struct aji_client *client, char *user, char *room, char *message)
@@ -1474,7 +1595,7 @@ int ast_aji_invite_chat(struct aji_client *client, char *user, char *room, char
 
 /*!
  * \brief receive message loop.
- * \param aji_client struct.
+ * \param data void
  * \return void.
  */
 static void *aji_recv_loop(void *data)
@@ -1492,6 +1613,11 @@ static void *aji_recv_loop(void *data)
                }
 
                res = iks_recv(client->p, 1);
+
+               if (client->state == AJI_DISCONNECTING) {
+                       ast_debug(2, "Ending our Jabber client's thread due to a disconnect\n");
+                       pthread_exit(NULL);
+               }
                client->timeout--;
                if (res == IKS_HOOK) 
                        ast_log(LOG_WARNING, "JABBER: Got hook event.\n");
@@ -1512,7 +1638,7 @@ static void *aji_recv_loop(void *data)
 
 /*!
  * \brief increments the mid field for messages and other events.
- * \param message id.
+ * \param mid char.
  * \return void.
  */
 void ast_aji_increment_mid(char *mid)
@@ -1619,7 +1745,7 @@ void ast_aji_increment_mid(char *mid)
 */
 /*!
  * \brief goes through roster and prunes users not needed in list, or adds them accordingly.
- * \param aji_client struct.
+ * \param client aji_client
  * \return void.
  */
 static void aji_pruneregister(struct aji_client *client)
@@ -1672,7 +1798,8 @@ static void aji_pruneregister(struct aji_client *client)
 
 /*!
  * \brief filters the roster packet we get back from server.
- * \param aji_client struct, and xml packet.
+ * \param data void
+ * \param pak ikspak iksemel packet.
  * \return IKS_FILTER_EAT.
  */
 static int aji_filter_roster(void *data, ikspak *pak)
@@ -1715,12 +1842,11 @@ static int aji_filter_roster(void *data, ikspak *pak)
                        });
 
                        if (!flag) {
-                               buddy = (struct aji_buddy *) malloc(sizeof(struct aji_buddy));
+                               buddy = ast_calloc(1, sizeof(*buddy));
                                if (!buddy) {
                                        ast_log(LOG_WARNING, "Out of memory\n");
                                        return 0;
                                }
-                               memset(buddy, 0, sizeof(struct aji_buddy));
                                ASTOBJ_INIT(buddy);
                                ASTOBJ_WRLOCK(buddy);
                                ast_copy_string(buddy->name, iks_find_attrib(x, "jid"), sizeof(buddy->name));
@@ -1746,7 +1872,11 @@ static int aji_filter_roster(void *data, ikspak *pak)
        ASTOBJ_UNREF(client, aji_client_destroy);
        return IKS_FILTER_EAT;
 }
-
+/*!
+ * \brief reconnect to jabber server
+ * \param client aji_client
+ * \return res.
+*/
 static int aji_reconnect(struct aji_client *client)
 {
        int res = 0;
@@ -1759,14 +1889,15 @@ static int aji_reconnect(struct aji_client *client)
        if (client->authorized)
                client->authorized = 0;
 
-       if(client->component)
-               res = aji_component_initialize(client);
-       else
-               res = aji_client_initialize(client);
+       res = aji_initialize(client);
 
        return res;
 }
-
+/*!
+ * \brief Get the roster of jabber users
+ * \param client aji_client
+ * \return 1.
+*/
 static int aji_get_roster(struct aji_client *client)
 {
        iks *roster = NULL;
@@ -1783,7 +1914,8 @@ static int aji_get_roster(struct aji_client *client)
 
 /*!
  * \brief connects as a client to jabber server.
- * \param aji_client struct, and xml packet.
+ * \param data void
+ * \param pak ikspak iksemel packet
  * \return res.
  */
 static int aji_client_connect(void *data, ikspak *pak)
@@ -1809,14 +1941,13 @@ static int aji_client_connect(void *data, ikspak *pak)
 
 /*!
  * \brief prepares client for connect.
- * \param aji_client struct.
+ * \param client aji_client
  * \return 1.
  */
-static int aji_client_initialize(struct aji_client *client)
+static int aji_initialize(struct aji_client *client)
 {
-       int connected = 0;
-
-       connected = iks_connect_via(client->p, S_OR(client->serverhost, client->jid->server), client->port, client->jid->server);
+       /* If it's a component, connect to user, otherwise, connect to server */
+       int connected = iks_connect_via(client->p, S_OR(client->serverhost, client->jid->server), client->port, client->component ? client->user : client->jid->server);
 
        if (connected == IKS_NET_NOCONN) {
                ast_log(LOG_ERROR, "JABBER ERROR: No Connection\n");
@@ -1824,34 +1955,14 @@ static int aji_client_initialize(struct aji_client *client)
        } else  if (connected == IKS_NET_NODNS) {
                ast_log(LOG_ERROR, "JABBER ERROR: No DNS %s for client to  %s\n", client->name, S_OR(client->serverhost, client->jid->server));
                return IKS_HOOK;
-       } else
-               iks_recv(client->p, 30);
-       return IKS_OK;
-}
-
-/*!
- * \brief prepares component for connect.
- * \param aji_client struct.
- * \return 1.
- */
-static int aji_component_initialize(struct aji_client *client)
-{
-       int connected = 1;
-       connected = iks_connect_via(client->p, client->jid->server, client->port, client->user);
-       if (connected == IKS_NET_NOCONN) {
-               ast_log(LOG_ERROR, "JABBER ERROR: No Connection\n");
-               return IKS_HOOK;
-       } else if (connected == IKS_NET_NODNS) {
-               ast_log(LOG_ERROR, "JABBER ERROR: No DNS\n");
-               return IKS_HOOK;
-       } else if (!connected) 
+       } else /* if (!connected) phsultan: check if this is needed! */
                iks_recv(client->p, 30);
        return IKS_OK;
 }
 
 /*!
  * \brief disconnect from jabber server.
- * \param aji_client struct.
+ * \param client aji_client
  * \return 1.
  */
 int ast_aji_disconnect(struct aji_client *client)
@@ -1869,7 +1980,11 @@ int ast_aji_disconnect(struct aji_client *client)
 
 /*!
  * \brief set presence of client.
- * \param aji_client struct, user to send it to, and from, level, description.
+ * \param client aji_client
+ * \param to user send it to
+ * \param from user it came from
+ * \param level
+ * \param desc
  * \return void.
  */
 static void aji_set_presence(struct aji_client *client, char *to, char *from, int level, char *desc)
@@ -1901,7 +2016,9 @@ static void aji_set_presence(struct aji_client *client, char *to, char *from, in
 
 /*!
  * \brief turnon console debugging.
- * \param fd, number of args, args.
+ * \param fd
+ * \param argc Integer. Number of args
+ * \param argv List of arguements
  * \return RESULT_SUCCESS.
  */
 static int aji_do_debug(int fd, int argc, char *argv[])
@@ -1917,7 +2034,9 @@ static int aji_do_debug(int fd, int argc, char *argv[])
 
 /*!
  * \brief reload jabber module.
- * \param fd, number of args, args.
+ * \param fd
+ * \param argc no of args
+ * \param argv list of arguements
  * \return RESULT_SUCCESS.
  */
 static int aji_do_reload(int fd, int argc, char *argv[])
@@ -1929,7 +2048,9 @@ static int aji_do_reload(int fd, int argc, char *argv[])
 
 /*!
  * \brief turnoff console debugging.
- * \param fd, number of args, args.
+ * \param fd
+ * \param argc Integer. number of args
+ * \param argv list of arguements
  * \return RESULT_SUCCESS.
  */
 static int aji_no_debug(int fd, int argc, char *argv[])
@@ -1945,7 +2066,9 @@ static int aji_no_debug(int fd, int argc, char *argv[])
 
 /*!
  * \brief show client status.
- * \param fd, number of args, args.
+ * \param fd
+ * \param argc Integer. number of args
+ * \param argv list of arguements
  * \return RESULT_SUCCESS.
  */
 static int aji_show_clients(int fd, int argc, char *argv[])
@@ -1979,8 +2102,10 @@ static int aji_show_clients(int fd, int argc, char *argv[])
 
 /*!
  * \brief send test message for debugging.
- * \param fd, number of args, args.
- * \return RESULT_SUCCESS.
+ * \param fd
+ * \param argc Integer. number of args
+ * \param argv list of arguements
+ * \return RESULT_SUCCESS,RESULT_FAILURE.
  */
 static int aji_test(int fd, int argc, char *argv[])
 {
@@ -2030,7 +2155,9 @@ static int aji_test(int fd, int argc, char *argv[])
 
 /*!
  * \brief creates aji_client structure.
- * \param label, ast_variable, debug, pruneregister, component/client, aji_client to dump into. 
+ * \param label
+ * \param var ast_variable
+ * \param debug 
  * \return 0.
  */
 static int aji_create_client(char *label, struct ast_variable *var, int debug)
@@ -2042,12 +2169,11 @@ static int aji_create_client(char *label, struct ast_variable *var, int debug)
        client = ASTOBJ_CONTAINER_FIND(&clients,label);
        if (!client) {
                flag = 1;
-               client = (struct aji_client *) malloc(sizeof(struct aji_client));
+               client = ast_calloc(1, sizeof(*client));
                if (!client) {
                        ast_log(LOG_ERROR, "Out of memory!\n");
                        return 0;
                }
-               memset(client, 0, sizeof(struct aji_client));
                ASTOBJ_INIT(client);
                ASTOBJ_WRLOCK(client);
                ASTOBJ_CONTAINER_INIT(&client->buddies);
@@ -2059,6 +2185,7 @@ static int aji_create_client(char *label, struct ast_variable *var, int debug)
        ast_copy_string(client->name, label, sizeof(client->name));
        ast_copy_string(client->mid, "aaaaa", sizeof(client->mid));
 
+       /* Set default values for the client object */
        client->debug = debug;
        ast_copy_flags(client, &globalflags, AST_FLAGS_ALL);
        client->port = 5222;
@@ -2139,7 +2266,7 @@ static int aji_create_client(char *label, struct ast_variable *var, int debug)
                asprintf(&resource, "%s/asterisk", client->user);
                if (resource) {
                        client->jid = iks_id_new(client->stack, resource);
-                       free(resource);
+                       ast_free(resource);
                }
        } else
                client->jid = iks_id_new(client->stack, client->user);
@@ -2156,7 +2283,7 @@ static int aji_create_client(char *label, struct ast_variable *var, int debug)
                asprintf(&resource, "%s/asterisk", client->user);
                if (resource) {
                        client->jid = iks_id_new(client->stack, resource);
-                       free(resource);
+                       ast_free(resource);
                }
        } else
                client->jid = iks_id_new(client->stack, client->user);
@@ -2180,12 +2307,11 @@ static int aji_create_transport(char *label, struct aji_client *client)
 
        buddy = ASTOBJ_CONTAINER_FIND(&client->buddies,label);
        if (!buddy) {
-               buddy = malloc(sizeof(struct aji_buddy));
+               buddy = ast_calloc(1, sizeof(*buddy));
                if(!buddy) {
                        ast_log(LOG_WARNING, "Out of memory\n");
                        return 0;
                }
-               memset(buddy, 0, sizeof(struct aji_buddy));
                ASTOBJ_INIT(buddy);
        }
        ASTOBJ_WRLOCK(buddy);
@@ -2220,8 +2346,9 @@ static int aji_create_transport(char *label, struct aji_client *client)
 
 /*!
  * \brief creates buddy.
- * \param label, buddy to dump it into. 
- * \return 0.
+ * \param label char.
+ * \param client aji_client buddy to dump it into. 
+ * \return 1 on success, 0 on failure.
  */
 static int aji_create_buddy(char *label, struct aji_client *client)
 {
@@ -2230,12 +2357,11 @@ static int aji_create_buddy(char *label, struct aji_client *client)
        buddy = ASTOBJ_CONTAINER_FIND(&client->buddies,label);
        if (!buddy) {
                flag = 1;
-               buddy = malloc(sizeof(struct aji_buddy));
+               buddy = ast_calloc(1, sizeof(*buddy));
                if(!buddy) {
                        ast_log(LOG_WARNING, "Out of memory\n");
                        return 0;
                }
-               memset(buddy, 0, sizeof(struct aji_buddy));
                ASTOBJ_INIT(buddy);
        }
        ASTOBJ_WRLOCK(buddy);
@@ -2250,11 +2376,7 @@ static int aji_create_buddy(char *label, struct aji_client *client)
        return 1;
 }
 
-/*!
- * \brief load config file.
- * \param void. 
- * \return 1.
- */
+/*!< load config file. \return 1. */
 static int aji_load_config(void)
 {
        char *cat = NULL;
@@ -2293,8 +2415,8 @@ static int aji_load_config(void)
 
 /*!
  * \brief grab a aji_client structure by label name.
- * \param void. 
- * \return 1.
+ * \param name label name 
+ * \return aji_client.
  */
 struct aji_client *ast_aji_get_client(const char *name)
 {
@@ -2318,7 +2440,12 @@ static char mandescr_jabber_send[] =
 "  ScreenName: User Name to message.\n"
 "  Message:    Message to be sent to the buddy\n";
 
-/*! \brief  Send a Jabber Message via call from the Manager */
+/*! 
+ * \brief  Send a Jabber Message via call from the Manager 
+ * \param s mansession Manager session
+ * \param m message Message to send
+ * \return  0
+*/
 static int manager_jabber_send(struct mansession *s, const struct message *m)
 {
        struct aji_client *client = NULL;
@@ -2359,7 +2486,7 @@ static int manager_jabber_send(struct mansession *s, const struct message *m)
        return 0;
 }
 
-
+/*! \brief Reload the jabber module */
 static int aji_reload()
 {
        ASTOBJ_CONTAINER_MARKALL(&clients);
@@ -2381,17 +2508,29 @@ static int aji_reload()
        return 1;
 }
 
+/*! \brief Unload the jabber module */
 static int unload_module(void)
 {
+
+       /* Check if TLS is initialized. If that's the case, we can't unload this
+          module due to a bug in the iksemel library that will cause a crash or
+          a deadlock. We're trying to find a way to handle this, but in the meantime
+          we will simply refuse to die... 
+        */
+       if (tls_initialized) {
+               ast_log(LOG_ERROR, "Module can't be unloaded due to a bug in the Iksemel library when using TLS.\n");
+               return 1;       /* You need a forced unload to get rid of this module */
+       }
+
        ast_cli_unregister_multiple(aji_cli, sizeof(aji_cli) / sizeof(struct ast_cli_entry));
        ast_unregister_application(app_ajisend);
        ast_unregister_application(app_ajistatus);
        ast_manager_unregister("JabberSend");
+       
        ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
                ASTOBJ_RDLOCK(iterator);
-               if (option_verbose > 2)
-                       ast_verbose(VERBOSE_PREFIX_3 "JABBER: %s\n", iterator->name);
-               iterator->state = AJI_DISCONNECTED;
+               ast_debug(3, "JABBER: Releasing and disconneing client: %s\n", iterator->name);
+               iterator->state = AJI_DISCONNECTING;
                ast_aji_disconnect(iterator);
                pthread_join(iterator->thread, NULL);
                ASTOBJ_UNLOCK(iterator);
@@ -2399,11 +2538,10 @@ static int unload_module(void)
 
        ASTOBJ_CONTAINER_DESTROYALL(&clients, aji_client_destroy);
        ASTOBJ_CONTAINER_DESTROY(&clients);
-
-       ast_log(LOG_NOTICE, "res_jabber unloaded.\n");
        return 0;
 }
 
+/*! \brief Unload the jabber module */
 static int load_module(void)
 {
        ASTOBJ_CONTAINER_INIT(&clients);
@@ -2415,10 +2553,10 @@ static int load_module(void)
        ast_register_application(app_ajistatus, aji_status_exec, ajistatus_synopsis, ajistatus_descrip);
        ast_cli_register_multiple(aji_cli, sizeof(aji_cli) / sizeof(struct ast_cli_entry));
 
-       ast_log(LOG_NOTICE, "res_jabber.so loaded.\n");
        return 0;
 }
 
+/*! \brief Wrapper for aji_reload */
 static int reload(void)
 {
        aji_reload();