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 6fff231..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"
@@ -50,9 +58,20 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/module.h"
 #include "asterisk/astobj.h"
 #include "asterisk/astdb.h"
+#include "asterisk/manager.h"
 
 #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);
@@ -65,10 +84,9 @@ 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 *user, int level, char *desc);
+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[]);
 static int aji_do_reload(int fd, int argc, char *argv[]);
 static int aji_no_debug(int fd, int argc, char *argv[]);
@@ -76,12 +94,9 @@ static int aji_test(int fd, int argc, char *argv[]);
 static int aji_show_clients(int fd, int argc, char *argv[]);
 static int aji_create_client(char *label, struct ast_variable *var, int debug);
 static int aji_create_buddy(char *label, struct aji_client *client);
-static int aji_create_transport(char *label, struct aji_client *client);
-static void aji_reload(void);
+static int aji_reload(void);
 static int aji_load_config(void);
 static void aji_pruneregister(struct aji_client *client);
-static int aji_register_transport(void *data, ikspak *pak);
-static int aji_register_transport2(void *data, ikspak *pak);
 static int aji_filter_roster(void *data, ikspak *pak);
 static int aji_get_roster(struct aji_client *client);
 static int aji_client_info_handler(void *data, ikspak *pak);
@@ -91,66 +106,84 @@ static int aji_register_query_handler(void *data, ikspak *pak);
 static int aji_register_approve_handler(void *data, ikspak *pak);
 static int aji_reconnect(struct aji_client *client);
 static iks *jabber_make_auth(iksid * id, const char *pass, const char *sid);
+/* No transports in this version */
+/*
+static int aji_create_transport(char *label, struct aji_client *client);
+static int aji_register_transport(void *data, ikspak *pak);
+static int aji_register_transport2(void *data, ikspak *pak);
+*/
 
-static char debug_usage[] = 
-"Usage: JABBER debug\n" 
-"       Enables dumping of JABBER packets for debugging purposes.\n";
+static const char debug_usage[] = 
+"Usage: jabber debug\n" 
+"       Enables dumping of Jabber packets for debugging purposes.\n";
 
-static char no_debug_usage[] = 
-"Usage: JABBER no debug\n" 
-"       Disables dumping of JABBER packets for debugging purposes.\n";
+static const char no_debug_usage[] = 
+"Usage: jabber debug off\n" 
+"       Disables dumping of Jabber packets for debugging purposes.\n";
 
-static char reload_usage[] = 
-"Usage: JABBER reload\n" 
-"       Enables reloading of JABBER module.\n";
+static const char reload_usage[] = 
+"Usage: jabber reload\n" 
+"       Enables reloading of Jabber module.\n";
 
-static char test_usage[] = 
-"Usage: JABBER test [client]\n" 
+static const char test_usage[] = 
+"Usage: jabber test [client]\n" 
 "       Sends test message for debugging purposes.  A specific client\n"
 "       as configured in jabber.conf can be optionally specified.\n";
 
 static struct ast_cli_entry aji_cli[] = {
-       {{ "jabber", "debug", NULL}, aji_do_debug, "Enable JABBER debugging", debug_usage },
-       {{ "jabber", "reload", NULL}, aji_do_reload, "Enable JABBER debugging", reload_usage },
-       {{ "jabber", "show", "connected", NULL}, aji_show_clients, "Show state of clients and components", debug_usage },
-       {{ "jabber", "no", "debug", NULL}, aji_no_debug, "Disable JABBER debug", no_debug_usage },
-       {{ "jabber", "test", NULL}, aji_test, "Shows roster, but is genearlly used for mog's debugging.", test_usage },
- };
+       { { "jabber", "debug", NULL},
+       aji_do_debug, "Enable Jabber debugging",
+       debug_usage },
+
+       { { "jabber", "reload", NULL},
+       aji_do_reload, "Reload Jabber configuration",
+       reload_usage },
+
+       { { "jabber", "show", "connected", NULL},
+       aji_show_clients, "Show state of clients and components",
+       debug_usage },
 
-static const char *tdesc = "AJI - Asterisk JABBER Interface";
+       { { "jabber", "debug", "off", NULL},
+       aji_no_debug, "Disable Jabber debug",
+       no_debug_usage },
 
-static char *app_ajisend = "JABBERSend";
+       { { "jabber", "test", NULL},
+       aji_test, "Shows roster, but is generally used for mog's debugging.",
+       test_usage },
+};
 
-static char *ajisend_synopsis = "JABBERSend(JABBER,ScreenName,Message)";
+static char *app_ajisend = "JabberSend";
+
+static char *ajisend_synopsis = "JabberSend(jabber,screenname,message)";
 
 static char *ajisend_descrip =
-"JABBERSend(JABBER,ScreenName,Message)\n"
-"  JABBER - Client or transport Asterisk uses to connect to JABBER\n" 
+"JabberSend(Jabber,ScreenName,Message)\n"
+"  Jabber - Client or transport Asterisk uses to connect to Jabber\n" 
 "  ScreenName - User Name to message.\n" 
 "  Message - Message to be sent to the buddy\n";
 
-static char *app_ajistatus = "JABBERStatus";
+static char *app_ajistatus = "JabberStatus";
 
-static char *ajistatus_synopsis = "JABBERStatus(JABBER,ScreenName,Variable)";
+static char *ajistatus_synopsis = "JabberStatus(Jabber,ScreenName,Variable)";
 
 static char *ajistatus_descrip =
-"JABBERStatus(JABBER,ScreenName,Variable)\n"
-"  JABBER - Client or transport Asterisk uses to connect to JABBER\n"
+"JabberStatus(Jabber,ScreenName,Variable)\n"
+"  Jabber - Client or transport Asterisk uses to connect to Jabber\n"
 "  ScreenName - User Name to retrieve status from.\n"
 "  Variable - Variable to store presence in will be 1-6.\n" 
 "             In order, Online, Chatty, Away, XAway, DND, Offline\n" 
 "             If not in roster variable will = 7\n";
 
 struct aji_client_container clients;
+struct aji_capabilities *capabilities = NULL;
 
-struct aji_capabilities *capabilities;
-
-/*! Global flags, initialized to default values */
+/*! \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)
@@ -161,20 +194,20 @@ static void aji_client_destroy(struct aji_client *obj)
        iks_filter_delete(obj->f);
        iks_parser_delete(obj->p);
        iks_stack_delete(obj->stack);
-       AST_LIST_LOCK(&client->messages);
-       while(tmp = AST_LIST_REMOVE_HEAD(&client->messages, list)) {
+       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(&client->messages);
-       free(obj);
+       AST_LIST_HEAD_DESTROY(&obj->messages);
+       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)
@@ -183,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;
@@ -209,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;
@@ -225,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;
@@ -240,22 +285,27 @@ 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;
 }
-
-static struct aji_resource *aji_find_resource(struct aji_buddy *buddy, char *rname)
+/*!
+ * \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;
-       if (!buddy)
+       if (!buddy || !name)
                return res;
        res = buddy->resources;
        while (res) {
-               if (!strcasecmp(res->resource, rname)) {
+               if (!strcasecmp(res->resource, name)) {
                        break;
                }
                res = res->next;
@@ -263,6 +313,11 @@ static struct aji_resource *aji_find_resource(struct aji_buddy *buddy, char *rna
        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"))
@@ -272,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)
@@ -287,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;
@@ -311,77 +373,64 @@ 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)
 {
        struct aji_client *client = NULL;
+       struct aji_buddy *buddy = NULL;
        struct aji_resource *r = NULL;
-       char *s = NULL, *sender = NULL, *screenname = NULL, *resource = NULL, *variable = NULL;
-       int stat = 7, found = 0;
+       char *s = NULL, *sender = NULL, *jid = NULL, *screenname = NULL, *resource = NULL, *variable = NULL;
+       int stat = 7;
        char status[2];
-       if (data) {
-               s = ast_strdupa((char *) data);
-               if (s) {
-                       sender = strsep(&s, "|");
-                       if (sender && (sender[0] != '\0')) {
-                               screenname = strsep(&s, "|");
-                               if (screenname && (screenname[0] != '\0')) {
-                                       variable = s;
-                               } else {
-                                       ast_log(LOG_ERROR, "Bad arguments\n");
-                                       return -1;
-                               }
+
+       if (!data) {
+               ast_log(LOG_ERROR, "This application requires arguments.\n");
+               return 0;
+       }
+       s = ast_strdupa(data);
+       if (s) {
+               sender = strsep(&s, "|");
+               if (sender && (sender[0] != '\0')) {
+                       jid = strsep(&s, "|");
+                       if (jid && (jid[0] != '\0')) {
+                               variable = s;
+                       } else {
+                               ast_log(LOG_ERROR, "Bad arguments\n");
+                               return -1;
                        }
                }
-       } else {
-               ast_log(LOG_ERROR, "Out of memory\n");
-               return -1;
        }
 
-       if(!strchr(screenname, '/')) {
+       if(!strchr(jid, '/')) {
                resource = NULL;
        } else {
-               resource = strsep(&screenname, "/");
+               screenname = strsep(&jid, "/");
+               resource = jid;
        }
-
        client = ast_aji_get_client(sender);
        if (!client) {
-               ast_log(LOG_WARNING, "Could not find Connection.\n");
+               ast_log(LOG_WARNING, "Could not find sender connection: %s\n", sender);
                return -1;
        }
-       
        if(!&client->buddies) {
-               ast_log(LOG_WARNING, "No buddies for connection.\n");
+               ast_log(LOG_WARNING, "No buddies for connection : %s\n", sender);
                return -1;
        }
-       ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
-               ASTOBJ_RDLOCK(iterator); 
-               if (!strcasecmp(iterator->user, screenname)) {
-                       found = 1; 
-                       r = iterator->resources; 
-                       if (r) {        /* client has signed on */
-                               if (resource) {
-                                       while (r) {
-                                               if (!strcasecmp(r->resource, resource)) {
-                                                       stat = r->status; 
-                                               }
-                                               r = r->next;
-                                       }
-                                       if (stat == 7) ast_log(LOG_NOTICE, "Resource not found %s\n", resource);
-                               } else {
-                                       stat = r->status; 
-                               }
-                       }
-               }
-       ASTOBJ_UNLOCK(iterator);
-       });
-
-       if (!found) {                           /* just a label */
-               ast_log(LOG_WARNING, "Could not find Buddy in list.\n");
+       buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, resource ? screenname: jid);
+       if (!buddy) {
+               ast_log(LOG_WARNING, "Could not find buddy in list : %s\n", resource ? screenname : jid);
                return -1;
        }
+       r = aji_find_resource(buddy, resource);
+       if(!r && buddy->resources) 
+               r = buddy->resources;
+       if(!r)
+               ast_log(LOG_NOTICE, "Resource %s of buddy %s not found \n", resource, screenname);
+       else
+               stat = r->status;
        sprintf(status, "%d", stat);
        pbx_builtin_setvar_helper(chan, variable, status);
        return 0;
@@ -389,35 +438,35 @@ 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)
 {
        struct aji_client *client = NULL;
 
        char *s = NULL, *sender = NULL, *recipient = NULL, *message = NULL;
-       if (data) {
-               s = ast_strdupa((char *) data);
-               if (s) {
-                       sender = strsep(&s, "|");
-                       if (sender && (sender[0] != '\0')) {
-                               recipient = strsep(&s, "|");
-                               if (recipient && (recipient[0] != '\0')) {
-                                       message = s;
-                               } else {
-                                       ast_log(LOG_ERROR, "Bad arguments \n");
-                                       return -1;
-                               }
+
+       if (!data) {
+               ast_log(LOG_ERROR, "This application requires arguments.\n");
+               return 0;
+       }
+       s = ast_strdupa(data);
+       if (s) {
+               sender = strsep(&s, "|");
+               if (sender && (sender[0] != '\0')) {
+                       recipient = strsep(&s, "|");
+                       if (recipient && (recipient[0] != '\0')) {
+                               message = s;
+                       } else {
+                               ast_log(LOG_ERROR, "Bad arguments: %s\n", (char *) data);
+                               return -1;
                        }
                }
-               client = ast_aji_get_client(sender);
-               if (!client) {
-                       ast_log(LOG_WARNING, "Could not find Sender.\n");
-                       return -1;
-               }
-       } else {
-               ast_log(LOG_ERROR, "Out of memory\n");
+       }
+       if (!(client = ast_aji_get_client(sender))) {
+               ast_log(LOG_WARNING, "Could not find sender connection: %s\n", sender);
                return -1;
        }
        if (strchr(recipient, '@') && message)
@@ -427,24 +476,85 @@ 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);
-       if (client->debug == 1) {
+
+       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)
                        ast_verbose("\nJABBER: %s INCOMING: %s\n", client->name, xmpp);
-               else
-                       ast_verbose("\nJABBER: %s OUTGOING: %s\n", client->name, xmpp);
+               else {
+                       if( strlen(xmpp) == 1) {
+                               if(option_debug > 2  && xmpp[0] == ' ')
+                               ast_verbose("\nJABBER: Keep alive packet\n");
+                       } else
+                               ast_verbose("\nJABBER: %s OUTGOING: %s\n", client->name, xmpp);
+               }
 
        }
        ASTOBJ_UNREF(client, aji_client_destroy);
 }
 
 /*!
+ * \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)
@@ -452,17 +562,30 @@ 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 */
+               ASTOBJ_UNREF(client, aji_client_destroy);
+               return IKS_HOOK;
+       }
+
+       if (client->state == AJI_DISCONNECTING) {
+               ASTOBJ_UNREF(client, aji_client_destroy);
+               return IKS_HOOK;
+       }
 
        pak = iks_packet(node);
 
-       if (client->component == AJI_CLIENT) {
+       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) {
@@ -480,157 +603,131 @@ 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) {
-                                                                               iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_SASL);
-                                                                               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, "mechanism", "PLAIN");
-                                                                               sprintf(s, "%c%s%c%s", 0, client->jid->user, 0, client->password);
-                                                                               ast_base64encode(base64, 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);
                        }
-               case IKS_NODE_ERROR:{
+                       break;
+               case IKS_NODE_ERROR: 
                                ast_log(LOG_ERROR, "JABBER: Node Error\n");
                                ASTOBJ_UNREF(client, aji_client_destroy);
                                return IKS_HOOK;
                                break;
-                       }
-               case IKS_NODE_STOP:{
+               case IKS_NODE_STOP: 
                                ast_log(LOG_WARNING, "JABBER: Disconnected\n");
                                ASTOBJ_UNREF(client, aji_client_destroy);
                                return IKS_HOOK;
                                break;
-                       }
                }
-       } else if (client->state != AJI_CONNECTED && client->component == AJI_COMPONENT) {
+       } else if (client->state != AJI_CONNECTED && client->component) {
                switch (type) {
-               case IKS_NODE_START:{
+               case IKS_NODE_START:
+                       if (client->state == AJI_DISCONNECTED) {
                                char secret[160], shasum[320], *handshake;
-                               if (client->state == AJI_DISCONNECTED) {
-                                       sprintf(secret, "%s%s", pak->id, client->password);
-                                       ast_sha1_hash(shasum, secret);
+
+                               sprintf(secret, "%s%s", pak->id, client->password);
+                               ast_sha1_hash(shasum, secret);
+                               handshake = NULL;
+                               asprintf(&handshake, "<handshake>%s</handshake>", shasum);
+                               if (handshake) {
+                                       iks_send_raw(client->p, handshake);
+                                       ast_free(handshake);
                                        handshake = NULL;
-                                       asprintf(&handshake, "<handshake>%s</handshake>", shasum);
-                                       if (handshake) {
-                                               iks_send_raw(client->p, handshake);
-                                               free(handshake);
-                                               handshake = NULL;
-                                       }
-                                       client->state = AJI_CONNECTED;
-                                       break;
                                }
-                       }
-
-               case IKS_NODE_NORMAL:{
+                               client->state = AJI_CONNECTING;
+                               if(iks_recv(client->p,1) == 2) /*XXX proper result for iksemel library on iks_recv of <handshake/> XXX*/
+                                       client->state = AJI_CONNECTED;
+                               else
+                                       ast_log(LOG_WARNING,"Jabber didn't seem to handshake, failed to authenicate.\n");
                                break;
                        }
+                       break;
 
-               case IKS_NODE_ERROR:{
-                               ast_log(LOG_ERROR, "JABBER: Node Error\n");
-                               ASTOBJ_UNREF(client, aji_client_destroy);
-                               return IKS_HOOK;
-                               break;
-                       }
-               case IKS_NODE_STOP:{
-                               ast_log(LOG_WARNING, "JABBER: Disconnected\n");
-                               ASTOBJ_UNREF(client, aji_client_destroy);
-                               return IKS_HOOK;
-                               break;
-                       }
+               case IKS_NODE_NORMAL:
+                       break;
+
+               case IKS_NODE_ERROR:
+                       ast_log(LOG_ERROR, "JABBER: Node Error\n");
+                       ASTOBJ_UNREF(client, aji_client_destroy);
+                       return IKS_HOOK;
+
+               case IKS_NODE_STOP:
+                       ast_log(LOG_WARNING, "JABBER: Disconnected\n");
+                       ASTOBJ_UNREF(client, aji_client_destroy);
+                       return IKS_HOOK;
                }
        }
 
        switch (pak->type) {
        case IKS_PAK_NONE:
-               if (option_verbose > 30)
-                       ast_verbose(VERBOSE_PREFIX_3 "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_verbose > 30)
-                       ast_verbose(VERBOSE_PREFIX_3 "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_verbose > 30)
-                       ast_verbose(VERBOSE_PREFIX_3 "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_verbose > 30)
-                       ast_verbose(VERBOSE_PREFIX_3 "JABBER: I Dont know S10N subscribe!!\n");
+               ast_debug(1, "JABBER: I Dont know S10N subscribe!!\n");
                break;
        case IKS_PAK_IQ:
-               if (option_verbose > 30)
-                       ast_verbose(VERBOSE_PREFIX_3 "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_verbose > 30)
-                       ast_verbose(VERBOSE_PREFIX_3 "JABBER: I Dont know %i\n", pak->type);
+               ast_debug(1, "JABBER: I Dont know %i\n", pak->type);
                break;
        }
        
@@ -642,60 +739,100 @@ 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);
-       iks *iq = NULL, *query = NULL, *item = NULL;
+       iks *iq = NULL, *presence = NULL, *x = NULL;
 
        iq = iks_new("iq");
-       query = iks_new("query");
-       item = iks_new("item");
-
-       if (client && iq && query && item) {
+       presence = iks_new("presence");
+       x = iks_new("x");
+       if (client && iq && presence && x) {
                if (!iks_find(pak->query, "remove")) {
                        iks_insert_attrib(iq, "from", client->jid->full);
                        iks_insert_attrib(iq, "to", pak->from->full);
                        iks_insert_attrib(iq, "id", pak->id);
                        iks_insert_attrib(iq, "type", "result");
-                       iks_insert_attrib(query, "xmlns", "jabber:iq:register");
-
-                       iks_insert_node(iq, query);
                        iks_send(client->p, iq);
-                       iks_insert_attrib(iq, "from", pak->from->full);
-                       iks_insert_attrib(iq, "to", pak->from->full);
-                       iks_insert_attrib(iq, "id", client->mid);
+
+                       iks_insert_attrib(presence, "from", client->jid->full);
+                       iks_insert_attrib(presence, "to", pak->from->partial);
+                       iks_insert_attrib(presence, "id", client->mid);
                        ast_aji_increment_mid(client->mid);
-                       iks_insert_attrib(iq, "type", "set");
-                       iks_insert_attrib(query, "xmlns", "jabber:iq:roster");
-                       iks_insert_attrib(item, "subscription", "none");
-                       iks_insert_attrib(item, "jid", client->jid->full);
-                       iks_insert_node(query, item);
-                       iks_send(client->p, iq);
+                       iks_insert_attrib(presence, "type", "subscribe");
+                       iks_insert_attrib(x, "xmlns", "vcard-temp:x:update");
+                       iks_insert_node(presence, x);
+                       iks_send(client->p, presence); 
                }
        } else {
                ast_log(LOG_ERROR, "Out of memory.\n");
        }
+
        if (iq)
                iks_delete(iq);
-       if (query)
-               iks_delete(query);
-       if (item)
-               iks_delete(item);
+       if(presence)
+               iks_delete(presence);
+       if (x)
+               iks_delete(x);
        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);
+       struct aji_buddy *buddy = NULL; 
        char *node = NULL;
 
        client = (struct aji_client *) data;
 
-       if (!(node = iks_find_attrib(pak->query, "node"))) {
+       buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
+       if (!buddy) {
+               iks *iq = NULL, *query = NULL, *error = NULL, *notacceptable = NULL;
+
+               ast_verbose("Someone.... %s tried to register but they aren't allowed\n", pak->from->partial);
+               iq = iks_new("iq");
+               query = iks_new("query");
+               error = iks_new("error");
+               notacceptable = iks_new("not-acceptable");
+               if(iq && query && error && notacceptable) {
+                       iks_insert_attrib(iq, "type", "error");
+                       iks_insert_attrib(iq, "from", client->user);
+                       iks_insert_attrib(iq, "to", pak->from->full);
+                       iks_insert_attrib(iq, "id", pak->id);
+                       iks_insert_attrib(query, "xmlns", "jabber:iq:register");
+                       iks_insert_attrib(error, "code" , "406");
+                       iks_insert_attrib(error, "type", "modify");
+                       iks_insert_attrib(notacceptable, "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas");
+                       iks_insert_node(iq, query);
+                       iks_insert_node(iq, error);
+                       iks_insert_node(error, notacceptable);
+                       iks_send(client->p, iq);
+               } else {
+                       ast_log(LOG_ERROR, "Out of memory.\n");
+               }
+               if (iq)
+                       iks_delete(iq);
+               if (query)
+                       iks_delete(query);
+               if (error)
+                       iks_delete(error);
+               if (notacceptable)
+                       iks_delete(notacceptable);
+       } else  if (!(node = iks_find_attrib(pak->query, "node"))) {
                iks *iq = NULL, *query = NULL, *instructions = NULL;
-               char *explain = "Welcome to Asterisk the Open Source PBX.\n";
+               char *explain = "Welcome to Asterisk - the Open Source PBX.\n";
                iq = iks_new("iq");
                query = iks_new("query");
                instructions = iks_new("instructions");
@@ -723,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);
@@ -818,16 +961,19 @@ 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);
-       struct aji_buddy *buddy = NULL;
        struct aji_resource *resource = NULL;
-       buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
+       struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
 
        resource = aji_find_resource(buddy, pak->from->resource);
-
        if (pak->subtype == IKS_TYPE_RESULT) {
                if (!resource) {
                        ast_log(LOG_NOTICE,"JABBER: Received client info from %s when not requested.\n", pak->from->full);
@@ -879,14 +1025,36 @@ 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);
        char *node = NULL;
+       struct aji_resource *resource = NULL;
+       struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
 
-       if (!(node = iks_find_attrib(pak->query, "node"))) {
-               iks *iq = NULL, *query = NULL, *identity = NULL, *disco = NULL, *reg = NULL, *commands = NULL, *gateway = NULL, *version = NULL, *vcard = NULL, *search = NULL;
+       resource = aji_find_resource(buddy, pak->from->resource);
+       if (pak->subtype == IKS_TYPE_ERROR) {
+               ast_log(LOG_WARNING, "Recieved error from a client, turn on jabber debug!\n");
+               return IKS_FILTER_EAT;
+       }
+       if (pak->subtype == IKS_TYPE_RESULT) {
+               if (!resource) {
+                       ast_log(LOG_NOTICE,"JABBER: Received client info from %s when not requested.\n", pak->from->full);
+                       ASTOBJ_UNREF(client, aji_client_destroy);
+                       return IKS_FILTER_EAT;
+               }
+               if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
+                       resource->cap->jingle = 1;
+               } else
+                       resource->cap->jingle = 0;
+       } else if (pak->subtype == IKS_TYPE_GET && !(node = iks_find_attrib(pak->query, "node"))) {
+               iks *iq, *query, *identity, *disco, *reg, *commands, *gateway, *version, *vcard, *search;
 
                iq = iks_new("iq");
                query = iks_new("query");
@@ -951,8 +1119,8 @@ static int aji_dinfo_handler(void *data, ikspak *pak)
                if (search)
                        iks_delete(search);
 
-       } else if (!strcasecmp(node, "http://jabber.org/protocol/commands")) {
-               iks *iq = NULL, *query = NULL, *confirm = NULL;
+       } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "http://jabber.org/protocol/commands")) {
+               iks *iq, *query, *confirm;
                iq = iks_new("iq");
                query = iks_new("query");
                confirm = iks_new("item");
@@ -980,12 +1148,13 @@ static int aji_dinfo_handler(void *data, ikspak *pak)
                if (confirm)
                        iks_delete(confirm);
 
-       } else if (!strcasecmp(node, "confirmaccount")) {
-               iks *iq = NULL, *query = NULL, *feature = NULL;
+       } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "confirmaccount")) {
+               iks *iq, *query, *feature;
 
                iq = iks_new("iq");
                query = iks_new("query");
                feature = iks_new("feature");
+
                if (iq && query && feature && client) {
                        iks_insert_attrib(iq, "from", client->user);
                        iks_insert_attrib(iq, "to", pak->from->full);
@@ -1012,66 +1181,81 @@ 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)
 {
-       if (option_verbose > 77)
-               ast_verbose("MWAHHAHAHA NOTHING TO SEE HERE!\n");
+       /*Nothing to see here */
 }
 
 /*!
  * \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;
-       insert = ast_calloc(1,sizeof(struct aji_message));
+       
+       if (!(insert = ast_calloc(1, sizeof(*insert))))
+               return;
        time(&insert->arrived);
-       insert->message = ast_strdup(iks_find_cdata(pak->x, "body"));
-       ast_copy_string(insert->id, pak->id, sizeof(insert->message));
-       insert->from = ast_strdup(pak->from->full);
+       if (iks_find_cdata(pak->x, "body"))
+               insert->message = ast_strdup(iks_find_cdata(pak->x, "body"));
+       if (pak->id)
+               ast_copy_string(insert->id, pak->id, sizeof(insert->message));
+       if (pak->from)
+               insert->from = ast_strdup(pak->from->full);
        AST_LIST_LOCK(&client->messages);
        AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, tmp, list) {
-               if(flag) {
-                       AST_LIST_REMOVE_CURRENT(&client->messages,list);
+               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);
+                       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_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;
-       struct aji_buddy *buddy = NULL;
+       struct aji_buddy *buddy;
        struct aji_resource *tmp = NULL, *last = NULL, *found = NULL;
-       char *ver, *node, *descrip;
+       char *ver, *node, *descrip, *type;
        
-       if(client->state != AJI_CONNECTED) {
-               aji_create_buddy(pak->from->partial,client);
-       }
+       if(client->state != AJI_CONNECTED)
+               aji_create_buddy(pak->from->partial, client);
+
        buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
        if (!buddy) {
-               ast_log(LOG_WARNING, "Got presence packet from %s, someone not in our roster!!!!\n", pak->from->partial);
+               ast_log(LOG_NOTICE, "Got presence packet from %s, someone not in our roster!!!!\n", pak->from->partial);
                return;
        }
+       type = iks_find_attrib(pak->x, "type");
+       if(client->component && type &&!strcasecmp("probe", type)) {
+               aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), 1, client->statusmessage);
+               ast_verbose("what i was looking for \n");
+       }
        ASTOBJ_WRLOCK(buddy);
        status = (pak->show) ? pak->show : 6;
        priority = atoi((iks_find_cdata(pak->x, "priority")) ? iks_find_cdata(pak->x, "priority") : "0");
@@ -1081,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 */
@@ -1098,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;
                        }
@@ -1138,8 +1322,8 @@ 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");
                        return;
@@ -1180,8 +1364,9 @@ static void aji_handle_presence(struct aji_client *client, ikspak *pak)
                found->cap = aji_find_version(node, ver, pak);
                if(gtalk_yuck(pak->x)) /* gtalk should do discover */
                        found->cap->jingle = 1;
-               if(found->cap->jingle)
-                       ast_log(LOG_DEBUG,"Special case for google till they support discover.\n");
+               if(found->cap->jingle && option_debug > 4) {
+                       ast_debug(1,"Special case for google till they support discover.\n");
+               }
                else {
                        iks *iq, *query;
                        iq = iks_new("iq");
@@ -1189,6 +1374,7 @@ static void aji_handle_presence(struct aji_client *client, ikspak *pak)
                        if(query && iq)  {
                                iks_insert_attrib(iq, "type", "get");
                                iks_insert_attrib(iq, "to", pak->from->full);
+                               iks_insert_attrib(iq,"from",iks_find_attrib(pak->x,"to"));
                                iks_insert_attrib(iq, "id", client->mid);
                                ast_aji_increment_mid(client->mid);
                                iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
@@ -1203,7 +1389,7 @@ static void aji_handle_presence(struct aji_client *client, ikspak *pak)
                                iks_delete(iq);
                }
        }
-       if (option_verbose > 30) {
+       if (option_verbose > 4) {
                switch (pak->subtype) {
                case IKS_TYPE_AVAILABLE:
                        ast_verbose(VERBOSE_PREFIX_3 "JABBER: I am available ^_* %i\n", pak->subtype);
@@ -1212,7 +1398,7 @@ static void aji_handle_presence(struct aji_client *client, ikspak *pak)
                        ast_verbose(VERBOSE_PREFIX_3 "JABBER: I am unavailable ^_* %i\n", pak->subtype);
                        break;
                default:
-                       ast_verbose(VERBOSE_PREFIX_3 "JABBER: Ohh sexy and the wrong type%i\n", pak->subtype);
+                       ast_verbose(VERBOSE_PREFIX_3 "JABBER: Ohh sexy and the wrong type: %i\n", pak->subtype);
                }
                switch (pak->show) {
                case IKS_SHOW_UNAVAILABLE:
@@ -1241,14 +1427,35 @@ 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)
 {
-       if(pak->subtype == IKS_TYPE_SUBSCRIBE)
-               iks_send(client->p, iks_make_s10n(IKS_TYPE_SUBSCRIBED, iks_find_attrib(pak->x, "from"), "Asterisk has approved subscription"));
-       if (option_verbose > 30) {
+       if(pak->subtype == IKS_TYPE_SUBSCRIBE) { 
+               iks *presence = NULL, *status = NULL;
+               presence = iks_new("presence");
+               status = iks_new("status");
+               if(presence && status) {
+                       iks_insert_attrib(presence, "type", "subscribed");
+                       iks_insert_attrib(presence, "to", pak->from->full);
+                       iks_insert_attrib(presence, "from", client->jid->full);
+                       if(pak->id)
+                               iks_insert_attrib(presence, "id", pak->id);
+                       iks_insert_cdata(status, "Asterisk has approved subscription", 0);
+                       iks_insert_node(presence, status);
+                       iks_send(client->p, presence);
+               } else
+                       ast_log(LOG_ERROR, "Unable to allocate nodes\n");
+               if(presence)
+                       iks_delete(presence);
+               if(status)
+                       iks_delete(status);
+               if(client->component)
+                       aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), 1, client->statusmessage);
+       }
+       if (option_verbose > 4) {
                switch (pak->subtype) {
                case IKS_TYPE_SUBSCRIBE:
                        ast_verbose(VERBOSE_PREFIX_3 "JABBER: This is a subcription of type %i\n", pak->subtype);
@@ -1271,10 +1478,12 @@ 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, char *address, char *message)
+int ast_aji_send(struct aji_client *client, const char *address, const char *message)
 {
        int res = 0;
        iks *message_packet = NULL;
@@ -1295,7 +1504,10 @@ int ast_aji_send(struct aji_client *client, char *address, char *message)
 
 /*!
  * \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)
@@ -1309,15 +1521,15 @@ int ast_aji_create_chat(struct aji_client *client, char *room, char *server, cha
                iks_insert_attrib(iq, "id", client->mid);
                ast_aji_increment_mid(client->mid);
                iks_send(client->p, iq);
-       } else {
+       } else 
                ast_log(LOG_ERROR, "Out of memory.\n");
-       }
        return res;
 }
 
 /*!
  * \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)
@@ -1334,9 +1546,8 @@ int ast_aji_join_chat(struct aji_client *client, char *room)
                iks_insert_cdata(priority, "5", 1);
                iks_insert_attrib(presence, "to", room);
                res = iks_send(client->p, presence);
-       } else {
+       } else 
                ast_log(LOG_ERROR, "Out of memory.\n");
-       }
        if (presence)
                iks_delete(presence);
        if (priority)
@@ -1346,13 +1557,17 @@ 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)
 {
        int res = 0;
-       iks *invite = NULL, *body = NULL, *namespace = NULL;
+       iks *invite, *body, *namespace;
+
        invite = iks_new("message");
        body = iks_new("body");
        namespace = iks_new("x");
@@ -1360,15 +1575,14 @@ int ast_aji_invite_chat(struct aji_client *client, char *user, char *room, char
                iks_insert_attrib(invite, "to", user);
                iks_insert_attrib(invite, "id", client->mid);
                ast_aji_increment_mid(client->mid);
-               iks_insert_cdata(body, message, strlen(message));
+               iks_insert_cdata(body, message, 0);
                iks_insert_attrib(namespace, "xmlns", "jabber:x:conference");
                iks_insert_attrib(namespace, "jid", room);
                iks_insert_node(invite, body);
                iks_insert_node(invite, namespace);
                res = iks_send(client->p, invite);
-       } else {
+       } else 
                ast_log(LOG_ERROR, "Out of memory.\n");
-       }
        if (body)
                iks_delete(body);
        if (namespace)
@@ -1381,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)
@@ -1391,24 +1605,32 @@ static void *aji_recv_loop(void *data)
        do {
                if (res != IKS_OK) {
                        while(res != IKS_OK) {
-                               if(option_verbose > 3) ast_verbose("JABBER: reconnecting.\n");
+                               if(option_verbose > 3)
+                                       ast_verbose("JABBER: reconnecting.\n");
                                res = aji_reconnect(client);
                                sleep(4);
                        }
                }
 
                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) {
+               if (res == IKS_HOOK) 
                        ast_log(LOG_WARNING, "JABBER: Got hook event.\n");
-               } else if (res == IKS_NET_TLSFAIL) {
-                       ast_log(LOG_WARNING, "JABBER:  Failure in tls.\n");
-               } else if (client->timeout == 0 && client->state == AJI_CONNECTED) {
-                       res = -1;
-                       ast_log(LOG_WARNING, "JABBER:  Network Timeout\n");
-               } else if (res == IKS_NET_RWERR) {
+               else if (res == IKS_NET_TLSFAIL)
+                       ast_log(LOG_WARNING, "JABBER:  Failure in TLS.\n");
+               else if (client->timeout == 0 && client->state == AJI_CONNECTED) {
+                       res = iks_send_raw(client->p, " ");
+                       if(res == IKS_OK)
+                               client->timeout = 50;
+                       else
+                               ast_log(LOG_WARNING, "JABBER:  Network Timeout\n");
+               } else if (res == IKS_NET_RWERR)
                        ast_log(LOG_WARNING, "JABBER: socket read error\n");
-               }
        } while (client);
        ASTOBJ_UNREF(client, aji_client_destroy);
        return 0;
@@ -1416,12 +1638,13 @@ 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)
 {
        int i = 0;
+
        for (i = strlen(mid) - 1; i >= 0; i--) {
                if (mid[i] != 'z') {
                        mid[i] = mid[i] + 1;
@@ -1437,13 +1660,14 @@ void ast_aji_increment_mid(char *mid)
  * \param aji_client struct, and xml packet.
  * \return IKS_FILTER_EAT.
  */
-static int aji_register_transport(void *data, ikspak *pak)
+/*allows for registering to transport , was too sketch and is out for now. */
+/*static int aji_register_transport(void *data, ikspak *pak)
 {
        struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
        int res = 0;
        struct aji_buddy *buddy = NULL;
-       iks *send = NULL;
-       send = iks_make_iq(IKS_TYPE_GET, "jabber:iq:register");
+       iks *send = iks_make_iq(IKS_TYPE_GET, "jabber:iq:register");
+
        if (client && send) {
                ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
                        ASTOBJ_RDLOCK(iterator); 
@@ -1459,31 +1683,32 @@ static int aji_register_transport(void *data, ikspak *pak)
                ast_aji_increment_mid(client->mid);
                iks_insert_attrib(send, "from", client->user);
                res = iks_send(client->p, send);
-       } else {
+       } else 
                ast_log(LOG_ERROR, "Out of memory.\n");
-       }
+
        if (send)
                iks_delete(send);
        ASTOBJ_UNREF(client, aji_client_destroy);
        return IKS_FILTER_EAT;
 
 }
-
+*/
 /*!
  * \brief attempts to register to a transport step 2.
  * \param aji_client struct, and xml packet.
  * \return IKS_FILTER_EAT.
  */
-static int aji_register_transport2(void *data, ikspak *pak)
+/* more of the same blob of code, too wonky for now*/
+/* static int aji_register_transport2(void *data, ikspak *pak)
 {
        struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
        int res = 0;
        struct aji_buddy *buddy = NULL;
-       iks *regquery = NULL, *reguser = NULL, *regpass = NULL, *regiq = NULL;
-       regiq = iks_new("iq");
-       regquery = iks_new("query");
-       reguser = iks_new("username");
-       regpass = iks_new("password");
+
+       iks *regiq = iks_new("iq");
+       iks *regquery = iks_new("query");
+       iks *reguser = iks_new("username");
+       iks *regpass = iks_new("password");
 
        if (client && regquery && reguser && regpass && regiq) {
                ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
@@ -1498,15 +1723,14 @@ static int aji_register_transport2(void *data, ikspak *pak)
                ast_aji_increment_mid(client->mid);
                iks_insert_attrib(regiq, "from", client->user);
                iks_insert_attrib(regquery, "xmlns", "jabber:iq:register");
-               iks_insert_cdata(reguser, buddy->user, strlen(buddy->user));
-               iks_insert_cdata(regpass, buddy->pass, strlen(buddy->pass));
+               iks_insert_cdata(reguser, buddy->user, 0);
+               iks_insert_cdata(regpass, buddy->pass, 0);
                iks_insert_node(regiq, regquery);
                iks_insert_node(regquery, reguser);
                iks_insert_node(regquery, regpass);
                res = iks_send(client->p, regiq);
-       } else {
+       } else
                ast_log(LOG_ERROR, "Out of memory.\n");
-       }
        if (regiq)
                iks_delete(regiq);
        if (regquery)
@@ -1518,20 +1742,19 @@ static int aji_register_transport2(void *data, ikspak *pak)
        ASTOBJ_UNREF(client, aji_client_destroy);
        return IKS_FILTER_EAT;
 }
-
+*/
 /*!
  * \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)
 {
        int res = 0;
-       iks *removeiq = NULL, *removequery = NULL, *removeitem = NULL, *send = NULL;
-       removeiq = iks_new("iq");
-       removequery = iks_new("query");
-       removeitem = iks_new("item");
-       send = iks_make_iq(IKS_TYPE_GET, "http://jabber.org/protocol/disco#items");
+       iks *removeiq = iks_new("iq");
+       iks *removequery = iks_new("query");
+       iks *removeitem = iks_new("item");
+       iks *send = iks_make_iq(IKS_TYPE_GET, "http://jabber.org/protocol/disco#items");
 
        if (client && removeiq && removequery && removeitem && send) {
                iks_insert_node(removeiq, removequery);
@@ -1554,24 +1777,14 @@ static void aji_pruneregister(struct aji_client *client)
                                iks_insert_attrib(removeitem, "subscription", "remove");
                                res = iks_send(client->p, removeiq);
                        } else if (ast_test_flag(iterator, AJI_AUTOREGISTER)) {
-                               if (iterator->btype == AJI_USER) {      /*if it is not a transport */
-                                       res = iks_send(client->p, iks_make_s10n(IKS_TYPE_SUBSCRIBE, iterator->name, 
-                                                       "Greetings I am the Asterisk Open Source PBX and I want to subscribe to your presence\n"));
-                               } else {
-                                       iks_filter_add_rule(client->f, aji_register_transport, client,
-                                                                 IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_NS,
-                                                                 "http://jabber.org/protocol/disco#items", IKS_RULE_DONE);
-                                       iks_insert_attrib(send, "to", iterator->host);
-                                       iks_insert_attrib(send, "from", client->jid->full);
-                                       res = iks_send(client->p, send);
-                               }
+                               res = iks_send(client->p, iks_make_s10n(IKS_TYPE_SUBSCRIBE, iterator->name, 
+                                               "Greetings I am the Asterisk Open Source PBX and I want to subscribe to your presence\n"));
                                ast_clear_flag(iterator, AJI_AUTOREGISTER);
                        }
                        ASTOBJ_UNLOCK(iterator);
                });
-       } else {
+       } else
                ast_log(LOG_ERROR, "Out of memory.\n");
-       }
        if (removeiq)
                iks_delete(removeiq);
        if (removequery)
@@ -1585,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)
@@ -1602,16 +1816,9 @@ static int aji_filter_roster(void *data, ikspak *pak)
                flag = 0;
                while (x) {
                        if (!iks_strcmp(iks_name(x), "item")) {
-                               if (!ast_strlen_zero(iterator->pass)) {
-                                       if (!strcasecmp(iterator->host, iks_find_attrib(x, "jid"))) {
-                                                 ast_clear_flag(iterator, AJI_AUTOPRUNE | AJI_AUTOREGISTER); 
-                                                 flag = 1;
-                                       }
-                               } else {
-                                       if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid"))) {
-                                                 flag = 1;
-                                                 ast_clear_flag(iterator, AJI_AUTOPRUNE | AJI_AUTOREGISTER);
-                                       }
+                               if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid"))) {
+                                       flag = 1;
+                                       ast_clear_flag(iterator, AJI_AUTOPRUNE | AJI_AUTOREGISTER);
                                }
                        }
                        x = iks_next(x);
@@ -1629,23 +1836,17 @@ static int aji_filter_roster(void *data, ikspak *pak)
                if (iks_strcmp(iks_name(x), "item") == 0) {
                        ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
                                ASTOBJ_RDLOCK(iterator);
-                               if (!ast_strlen_zero(iterator->pass)) {
-                                       if (!strcasecmp(iterator->host, iks_find_attrib(x, "jid")))
+                               if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid")))
                                        flag = 1;
-                               } else {
-                                       if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid")))
-                                               flag = 1;
-                               }
                                ASTOBJ_UNLOCK(iterator);
                        });
 
                        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));
@@ -1671,37 +1872,39 @@ 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;
 
        if (client->state)
                client->state = AJI_DISCONNECTED;
-       client->timeout=20;
+       client->timeout=50;
        if (client->p)
                iks_parser_reset(client->p);
        if (client->authorized)
                client->authorized = 0;
 
-       switch (client->component) {
-       case AJI_COMPONENT:
-               res = aji_component_initialize(client);
-               break;
-       case AJI_CLIENT:
-               res = aji_client_initialize(client);
-               break;
-       }
+       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;
        roster = iks_make_iq(IKS_TYPE_GET, IKS_NS_ROSTER);
        if(roster) {
                iks_insert_attrib(roster, "id", "roster");
-               aji_set_presence(client, client->jid->full, 1, client->statusmessage);
+               aji_set_presence(client, NULL, client->jid->full, 1, client->statusmessage);
                iks_send(client->p, roster);
        }
        if (roster)
@@ -1711,25 +1914,26 @@ 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)
 {
        struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
        int res = 0;
+
        if (client) {
                if (client->state == AJI_DISCONNECTED) {
                        iks_filter_add_rule(client->f, aji_filter_roster, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, "roster", IKS_RULE_DONE);
                        client->state = AJI_CONNECTING;
                        client->jid = (iks_find_cdata(pak->query, "jid")) ? iks_id_new(client->stack, iks_find_cdata(pak->query, "jid")) : client->jid;
                        iks_filter_remove_hook(client->f, aji_client_connect);
-                       if(client->component == AJI_CLIENT)
+                       if(!client->component) /*client*/
                                aji_get_roster(client);
                }
-       } else {
+       } else
                ast_log(LOG_ERROR, "Out of memory.\n");
-       }
 
        ASTOBJ_UNREF(client, aji_client_destroy);
        return res;
@@ -1737,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");
@@ -1752,32 +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
+       } else /* if (!connected) phsultan: check if this is needed! */
                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");
-       if (connected == IKS_NET_NODNS)
-               ast_log(LOG_ERROR, "JABBER ERROR: No DNS");
-       if (!connected)
-               iks_recv(client->p, 30);
-       return 1;
-}
-
-/*!
  * \brief disconnect from jabber server.
- * \param aji_client struct.
+ * \param client aji_client
  * \return 1.
  */
 int ast_aji_disconnect(struct aji_client *client)
@@ -1795,27 +1980,34 @@ int ast_aji_disconnect(struct aji_client *client)
 
 /*!
  * \brief set presence of client.
- * \param aji_client struct, user to send it to, 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 *user, int level, char *desc)
+static void aji_set_presence(struct aji_client *client, char *to, char *from, int level, char *desc)
 {
        int res = 0;
-       iks *presence = NULL, *priority, *cnode = NULL;
-       presence = iks_make_pres(level, desc);
-       cnode = iks_new("c");
-       priority = iks_new("priority");
+       iks *presence = iks_make_pres(level, desc);
+       iks *cnode = iks_new("c");
+       iks *priority = iks_new("priority");
+
        iks_insert_cdata(priority, "0", 1);
        if (presence && cnode && client) {
+               if(to)
+                       iks_insert_attrib(presence, "to", to);
+               if(from)
+                       iks_insert_attrib(presence, "from", from);
                iks_insert_attrib(cnode, "node", "http://www.asterisk.org/xmpp/client/caps");
                iks_insert_attrib(cnode, "ver", "asterisk-xmpp");
                iks_insert_attrib(cnode, "ext", "voice-v1");
                iks_insert_attrib(cnode, "xmlns", "http://jabber.org/protocol/caps");
                iks_insert_node(presence, cnode);
                res = iks_send(client->p, presence);
-       } else {
+       } else
                ast_log(LOG_ERROR, "Out of memory.\n");
-       }
        if (cnode)
                iks_delete(cnode);
        if (presence)
@@ -1824,7 +2016,9 @@ static void aji_set_presence(struct aji_client *client, char *user, int level, c
 
 /*!
  * \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[])
@@ -1834,27 +2028,29 @@ static int aji_do_debug(int fd, int argc, char *argv[])
                iterator->debug = 1;
                ASTOBJ_UNLOCK(iterator);
        });
-       if (option_verbose > 3)
-               ast_verbose(VERBOSE_PREFIX_3 "JABBER: Debugging Enabled.\n");
+       ast_cli(fd, "Jabber Debugging Enabled.\n");
        return RESULT_SUCCESS;
 }
 
 /*!
  * \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[])
 {
        aji_reload();
-       if (option_verbose > 3)
-               ast_verbose(VERBOSE_PREFIX_3 "JABBER: Reloaded.\n");
+       ast_cli(fd, "Jabber Reloaded.\n");
        return RESULT_SUCCESS;
 }
 
 /*!
  * \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[])
@@ -1864,21 +2060,25 @@ static int aji_no_debug(int fd, int argc, char *argv[])
                iterator->debug = 0;
                ASTOBJ_UNLOCK(iterator);
        });
-       if (option_verbose > 2)
-               ast_verbose(VERBOSE_PREFIX_3 "JABBER: Debugging Disabled\n");
+       ast_cli(fd, "Jabber Debugging Disabled.\n");
        return RESULT_SUCCESS;
 }
 
 /*!
  * \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[])
 {
-       char *status = "";
+       char *status;
+       int count = 0;
+       ast_cli(fd, "Jabber Users and their status:\n");
        ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
                ASTOBJ_RDLOCK(iterator);
+               count++;
                switch (iterator->state) {
                case AJI_DISCONNECTED:
                        status = "Disconnected";
@@ -1892,16 +2092,20 @@ static int aji_show_clients(int fd, int argc, char *argv[])
                default:
                        status = "Unknown";
                }
-               ast_verbose("JABBER: User: %s is %s\n", iterator->user, status);
+               ast_cli(fd, "       User: %s     - %s\n", iterator->user, status);
                ASTOBJ_UNLOCK(iterator);
        });
+       ast_cli(fd, "----\n");
+       ast_cli(fd, "   Number of users: %d\n", count);
        return RESULT_SUCCESS;
 }
 
 /*!
- * \brief send test message for debuging.
- * \param fd, number of args, args.
- * \return RESULT_SUCCESS.
+ * \brief send test message for debugging.
+ * \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[])
 {
@@ -1909,6 +2113,7 @@ static int aji_test(int fd, int argc, char *argv[])
        struct aji_resource *resource;
        const char *name = "asterisk";
        struct aji_message *tmp;
+
        if (argc > 3)
                return RESULT_SHOWUSAGE;
        else if (argc == 3)
@@ -1919,6 +2124,7 @@ static int aji_test(int fd, int argc, char *argv[])
                return RESULT_FAILURE;
        }
 
+       /* XXX Does Matt really want everyone to use his personal address for tests? */ /* XXX yes he does */
        ast_aji_send(client, "mogorman@astjab.org", "blahblah");
        ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
                ASTOBJ_RDLOCK(iterator);
@@ -1939,7 +2145,7 @@ static int aji_test(int fd, int argc, char *argv[])
        ast_verbose("\nOooh a working message stack!\n");
        AST_LIST_LOCK(&client->messages);
        AST_LIST_TRAVERSE(&client->messages, tmp, list) {
-               ast_verbose("   Message from: %s with id %s @ %s        %s\n",tmp->from, tmp->id, ctime(&tmp->arrived), tmp->message);
+               ast_verbose("   Message from: %s with id %s @ %s        %s\n",tmp->from, S_OR(tmp->id,""), ctime(&tmp->arrived), S_OR(tmp->message, ""));
        }
        AST_LIST_UNLOCK(&client->messages);
        ASTOBJ_UNREF(client, aji_client_destroy);
@@ -1949,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)
@@ -1957,19 +2165,18 @@ static int aji_create_client(char *label, struct ast_variable *var, int debug)
        char *resource;
        struct aji_client *client = NULL;
        int flag = 0;
+
        client = ASTOBJ_CONTAINER_FIND(&clients,label);
-       if(!client) {
+       if (!client) {
                flag = 1;
-               client = (struct aji_client *) malloc(sizeof(struct aji_client));
-               if(client) {
-                       memset(client, 0, sizeof(struct aji_client));
-                       ASTOBJ_INIT(client);
-                       ASTOBJ_WRLOCK(client);
-                       ASTOBJ_CONTAINER_INIT(&client->buddies);
-               } else {
+               client = ast_calloc(1, sizeof(*client));
+               if (!client) {
                        ast_log(LOG_ERROR, "Out of memory!\n");
                        return 0;
                }
+               ASTOBJ_INIT(client);
+               ASTOBJ_WRLOCK(client);
+               ASTOBJ_CONTAINER_INIT(&client->buddies);
        } else {
                ASTOBJ_WRLOCK(client);
                ASTOBJ_UNMARK(client);
@@ -1978,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;
@@ -1985,14 +2193,16 @@ static int aji_create_client(char *label, struct ast_variable *var, int debug)
        client->usesasl = 1;
        client->forcessl = 0;
        client->keepalive = 1;
-       client->timeout = 20;
+       client->timeout = 50;
        client->message_timeout = 100;
        AST_LIST_HEAD_INIT(&client->messages);
-       client->component = AJI_CLIENT;
+       client->component = 0;
        ast_copy_string(client->statusmessage, "Online and Available", sizeof(client->statusmessage));
 
-       if (flag) client->authorized = 0;
-       if (flag) client->state = AJI_DISCONNECTED;
+       if (flag) {
+               client->authorized = 0;
+               client->state = AJI_DISCONNECTED;
+       }
        while (var) {
                if (!strcasecmp(var->name, "username"))
                        ast_copy_string(client->user, var->value, sizeof(client->user));
@@ -2008,9 +2218,9 @@ static int aji_create_client(char *label, struct ast_variable *var, int debug)
                        client->message_timeout = atoi(var->value);
                else if (!strcasecmp(var->name, "debug"))
                        client->debug = (ast_false(var->value)) ? 0 : 1;
-               else if (!strcasecmp(var->name, "type")){
+               else if (!strcasecmp(var->name, "type")) {
                        if (!strcasecmp(var->value, "component"))
-                               client->component = AJI_COMPONENT;
+                               client->component = 1;
                } else if (!strcasecmp(var->name, "usetls")) {
                        client->usetls = (ast_false(var->value)) ? 0 : 1;
                } else if (!strcasecmp(var->name, "usesasl")) {
@@ -2025,59 +2235,61 @@ static int aji_create_client(char *label, struct ast_variable *var, int debug)
                        ast_set2_flag(client, ast_true(var->value), AJI_AUTOREGISTER);
                else if (!strcasecmp(var->name, "buddy"))
                                aji_create_buddy(var->value, client);
-               else if (!strcasecmp(var->name, "transport"))
+       /* no transport support in this version */
+       /*      else if (!strcasecmp(var->name, "transport"))
                                aji_create_transport(var->value, client);
+       */
                var = var->next;
        }
-       if(flag) {
-               client->p = iks_stream_new(((client->component == AJI_CLIENT) ? "jabber:client" : "jabber:component:accept"), client, aji_act_hook);
-               if (!client->p) {
-                       ast_log(LOG_WARNING, "Failed to create stream for client '%s'!\n", client->name);
-                       return 0;
-               }
-               client->stack = iks_stack_new(8192, 8192);
-               if (!client->stack) {
-                       ast_log(LOG_WARNING, "Failed to allocate stack for client '%s'\n", client->name);
-                       return 0;
-               }
-               client->f = iks_filter_new();
-               if (!client->f) {
-                       ast_log(LOG_WARNING, "Failed to create filter for client '%s'\n", client->name);
-                       return 0;
-               }
-               if (!strchr(client->user, '/') && client->component == AJI_CLIENT) {
-                       resource = NULL;
-                       asprintf(&resource, "%s/asterisk", client->user);
-                       if (resource) {
-                               client->jid = iks_id_new(client->stack, resource);
-                               free(resource);
-                       }
-               } else
-                       client->jid = iks_id_new(client->stack, client->user);
-               if (client->component == AJI_COMPONENT) {
-                       iks_filter_add_rule(client->f, aji_dinfo_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
-                       iks_filter_add_rule(client->f, aji_ditems_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#items", IKS_RULE_DONE);
-                       iks_filter_add_rule(client->f, aji_register_query_handler, client, IKS_RULE_SUBTYPE, IKS_TYPE_GET, IKS_RULE_NS, "jabber:iq:register", IKS_RULE_DONE);
-                       iks_filter_add_rule(client->f, aji_register_approve_handler, client, IKS_RULE_SUBTYPE, IKS_TYPE_SET, IKS_RULE_NS, "jabber:iq:register", IKS_RULE_DONE);
-               } else {
-                       iks_filter_add_rule(client->f, aji_client_info_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
-               }
-               if (!strchr(client->user, '/') && client->component == AJI_CLIENT) {
-                       resource = NULL;
-                       asprintf(&resource, "%s/asterisk", client->user);
-                       if (resource) {
-                               client->jid = iks_id_new(client->stack, resource);
-                               free(resource);
-                       }
-               } else
-                       client->jid = iks_id_new(client->stack, client->user);
-               iks_set_log_hook(client->p, aji_log_hook);
-               ASTOBJ_UNLOCK(client);
-               ASTOBJ_CONTAINER_LINK(&clients,client);
-       } else {
+       if (!flag) {
                ASTOBJ_UNLOCK(client);
                ASTOBJ_UNREF(client, aji_client_destroy);
+               return 1;
+       }
+       client->p = iks_stream_new(((client->component) ? "jabber:component:accept" : "jabber:client"), client, aji_act_hook);
+       if (!client->p) {
+               ast_log(LOG_ERROR, "Failed to create stream for client '%s'!\n", client->name);
+               return 0;
+       }
+       client->stack = iks_stack_new(8192, 8192);
+       if (!client->stack) {
+               ast_log(LOG_ERROR, "Failed to allocate stack for client '%s'\n", client->name);
+               return 0;
        }
+       client->f = iks_filter_new();
+       if (!client->f) {
+               ast_log(LOG_ERROR, "Failed to create filter for client '%s'\n", client->name);
+               return 0;
+       }
+       if (!strchr(client->user, '/') && !client->component) { /*client */
+               resource = NULL;
+               asprintf(&resource, "%s/asterisk", client->user);
+               if (resource) {
+                       client->jid = iks_id_new(client->stack, resource);
+                       ast_free(resource);
+               }
+       } else
+               client->jid = iks_id_new(client->stack, client->user);
+       if (client->component) {
+               iks_filter_add_rule(client->f, aji_dinfo_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
+               iks_filter_add_rule(client->f, aji_ditems_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#items", IKS_RULE_DONE);
+               iks_filter_add_rule(client->f, aji_register_query_handler, client, IKS_RULE_SUBTYPE, IKS_TYPE_GET, IKS_RULE_NS, "jabber:iq:register", IKS_RULE_DONE);
+               iks_filter_add_rule(client->f, aji_register_approve_handler, client, IKS_RULE_SUBTYPE, IKS_TYPE_SET, IKS_RULE_NS, "jabber:iq:register", IKS_RULE_DONE);
+       } else {
+               iks_filter_add_rule(client->f, aji_client_info_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
+       }
+       if (!strchr(client->user, '/') && !client->component) { /*client */
+               resource = NULL;
+               asprintf(&resource, "%s/asterisk", client->user);
+               if (resource) {
+                       client->jid = iks_id_new(client->stack, resource);
+                       ast_free(resource);
+               }
+       } else
+               client->jid = iks_id_new(client->stack, client->user);
+       iks_set_log_hook(client->p, aji_log_hook);
+       ASTOBJ_UNLOCK(client);
+       ASTOBJ_CONTAINER_LINK(&clients,client);
        return 1;
 }
 
@@ -2086,6 +2298,8 @@ static int aji_create_client(char *label, struct ast_variable *var, int debug)
  * \param label, buddy to dump it into. 
  * \return 0.
  */
+/* no connecting to transports today */
+/*
 static int aji_create_transport(char *label, struct aji_client *client)
 {
        char *server = NULL, *buddyname = NULL, *user = NULL, *pass = NULL;
@@ -2093,15 +2307,12 @@ 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;
-               } else {
-                       memset(buddy, 0, sizeof(struct aji_buddy));
-                       ASTOBJ_INIT(buddy);
-                       
                }
+               ASTOBJ_INIT(buddy);
        }
        ASTOBJ_WRLOCK(buddy);
        server = label;
@@ -2131,11 +2342,13 @@ static int aji_create_transport(char *label, struct aji_client *client)
        ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
        return 0;
 }
+*/
 
 /*!
  * \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)
 {
@@ -2144,15 +2357,12 @@ 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;
-               } else {
-                       memset(buddy, 0, sizeof(struct aji_buddy));
-                       ASTOBJ_INIT(buddy);
-                       
                }
+               ASTOBJ_INIT(buddy);
        }
        ASTOBJ_WRLOCK(buddy);
        ast_copy_string(buddy->name, label, sizeof(buddy->name));
@@ -2166,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;
@@ -2178,6 +2384,9 @@ static int aji_load_config(void)
        struct ast_config *cfg = NULL;
        struct ast_variable *var = NULL;
 
+       /* Reset flags to default value */
+       ast_set_flag(&globalflags, AJI_AUTOPRUNE | AJI_AUTOREGISTER);
+
        cfg = ast_config_load(JABBER_CONFIG);
        if (!cfg) {
                ast_log(LOG_WARNING, "No such configuration file %s\n", JABBER_CONFIG);
@@ -2206,13 +2415,13 @@ 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(char *name)
+struct aji_client *ast_aji_get_client(const char *name)
 {
        struct aji_client *client = NULL;
+
        client = ASTOBJ_CONTAINER_FIND(&clients, name);
        if (!client && !strchr(name, '@'))
                client = ASTOBJ_CONTAINER_FIND_FULL(&clients, name, user,,, strcasecmp);
@@ -2224,36 +2433,104 @@ struct aji_client_container *ast_aji_get_clients(void)
        return &clients;
 }
 
-static void aji_reload()
+static char mandescr_jabber_send[] =
+"Description: Sends a message to a Jabber Client.\n"
+"Variables: \n"
+"  Jabber:     Client or transport Asterisk uses to connect to JABBER.\n"
+"  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 
+ * \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;
+       const char *id = astman_get_header(m,"ActionID");
+       const char *jabber = astman_get_header(m,"Jabber");
+       const char *screenname = astman_get_header(m,"ScreenName");
+       const char *message = astman_get_header(m,"Message");
+
+       if (ast_strlen_zero(jabber)) {
+               astman_send_error(s, m, "No transport specified");
+               return 0;
+       }
+       if (ast_strlen_zero(screenname)) {
+               astman_send_error(s, m, "No ScreenName specified");
+               return 0;
+       }
+       if (ast_strlen_zero(message)) {
+               astman_send_error(s, m, "No Message specified");
+               return 0;
+       }
+
+       astman_send_ack(s, m, "Attempting to send Jabber Message");
+       client = ast_aji_get_client(jabber);
+       if (!client) {
+               astman_send_error(s, m, "Could not find Sender");
+               return 0;
+       }       
+       if (strchr(screenname, '@') && message){
+               ast_aji_send(client, screenname, message);      
+               if (!ast_strlen_zero(id))
+                       astman_append(s, "ActionID: %s\r\n",id);
+               astman_append(s, "Response: Success\r\n");
+               return 0;
+       }
+       if (!ast_strlen_zero(id))
+               astman_append(s, "ActionID: %s\r\n",id);
+       astman_append(s, "Response: Failure\r\n");
+       return 0;
+}
+
+/*! \brief Reload the jabber module */
+static int aji_reload()
 {
        ASTOBJ_CONTAINER_MARKALL(&clients);
-       if (!aji_load_config())
+       if (!aji_load_config()) {
                ast_log(LOG_ERROR, "JABBER: Failed to load config.\n");
-       else {
-               ASTOBJ_CONTAINER_PRUNE_MARKED(&clients, aji_client_destroy);
-               ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
-                       ASTOBJ_RDLOCK(iterator);
-                       if(iterator->state == AJI_DISCONNECTED) {
-                               if (!iterator->thread)
-                                       ast_pthread_create(&iterator->thread, NULL, aji_recv_loop, iterator);
-                       } else if (iterator->state == AJI_CONNECTING) {
-                               aji_get_roster(iterator);
-                       }
-                       ASTOBJ_UNLOCK(iterator);
-               });
+               return 0;
        }
+       ASTOBJ_CONTAINER_PRUNE_MARKED(&clients, aji_client_destroy);
+       ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
+               ASTOBJ_RDLOCK(iterator);
+               if(iterator->state == AJI_DISCONNECTED) {
+                       if (!iterator->thread)
+                               ast_pthread_create_background(&iterator->thread, NULL, aji_recv_loop, iterator);
+               } else if (iterator->state == AJI_CONNECTING)
+                       aji_get_roster(iterator);
+               ASTOBJ_UNLOCK(iterator);
+       });
+       
+       return 1;
 }
 
-static int unload_module(void *mod)
+/*! \brief Unload the jabber module */
+static int unload_module(void)
 {
-       ast_cli_unregister_multiple(aji_cli, sizeof(aji_cli) / sizeof(aji_cli[0]));
-       ast_unregister_application(app_ajisend);
 
+       /* 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);
@@ -2261,36 +2538,33 @@ static int unload_module(void *mod)
 
        ASTOBJ_CONTAINER_DESTROYALL(&clients, aji_client_destroy);
        ASTOBJ_CONTAINER_DESTROY(&clients);
-
-       ast_log(LOG_NOTICE, "res_jabber unloaded.\n");
        return 0;
 }
 
-static int load_module(void *mod)
+/*! \brief Unload the jabber module */
+static int load_module(void)
 {
        ASTOBJ_CONTAINER_INIT(&clients);
-       aji_reload();
+       if(!aji_reload())
+               return AST_MODULE_LOAD_DECLINE;
+       ast_manager_register2("JabberSend", EVENT_FLAG_SYSTEM, manager_jabber_send,
+                       "Sends a message to a Jabber Client", mandescr_jabber_send);
        ast_register_application(app_ajisend, aji_send_exec, ajisend_synopsis, ajisend_descrip);
        ast_register_application(app_ajistatus, aji_status_exec, ajistatus_synopsis, ajistatus_descrip);
-       ast_cli_register_multiple(aji_cli, sizeof(aji_cli) / sizeof(aji_cli[0]));
-       ast_log(LOG_NOTICE, "res_jabber.so loaded.\n");
+       ast_cli_register_multiple(aji_cli, sizeof(aji_cli) / sizeof(struct ast_cli_entry));
+
        return 0;
 }
 
-static int reload(void *mod)
+/*! \brief Wrapper for aji_reload */
+static int reload(void)
 {
        aji_reload();
        return 0;
 }
 
-static const char *description(void)
-{
-       return tdesc;
-}
-
-static const char *key(void)
-{
-       return ASTERISK_GPL_KEY;
-}
-
-STD_MOD(MOD_0, reload, NULL, NULL);
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "AJI - Asterisk Jabber Interface",
+               .load = load_module,
+               .unload = unload_module,
+               .reload = reload,
+              );