Sat Aug 6 00:39:31 2011

Asterisk developer's documentation


res_jabber.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2006, Digium, Inc.
00005  *
00006  * Matt O'Gorman <mogorman@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  * \brief A resource for interfacing asterisk directly as a client
00021  * or a component to a jabber compliant server.
00022  *
00023  * \todo If you unload this module, chan_gtalk/jingle will be dead. How do we handle that?
00024  * \todo If you have TLS, you can't unload this module. See bug #9738. This needs to be fixed,
00025  *       but the bug is in the unmantained Iksemel library
00026  *
00027  */
00028 
00029 /*** MODULEINFO
00030    <depend>iksemel</depend>
00031    <use>gnutls</use>
00032  ***/
00033 
00034 #include "asterisk.h"
00035 
00036 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 299002 $")
00037 
00038 #include <stdlib.h>
00039 #include <stdio.h>
00040 #include <iksemel.h>
00041 
00042 #include "asterisk/channel.h"
00043 #include "asterisk/jabber.h"
00044 #include "asterisk/file.h"
00045 #include "asterisk/config.h"
00046 #include "asterisk/callerid.h"
00047 #include "asterisk/lock.h"
00048 #include "asterisk/logger.h"
00049 #include "asterisk/options.h"
00050 #include "asterisk/cli.h"
00051 #include "asterisk/app.h"
00052 #include "asterisk/pbx.h"
00053 #include "asterisk/md5.h"
00054 #include "asterisk/acl.h"
00055 #include "asterisk/utils.h"
00056 #include "asterisk/module.h"
00057 #include "asterisk/astobj.h"
00058 #include "asterisk/astdb.h"
00059 #include "asterisk/manager.h"
00060 
00061 #define JABBER_CONFIG "jabber.conf"
00062 
00063 #ifndef FALSE
00064 #define FALSE 0
00065 #endif
00066 
00067 #ifndef TRUE
00068 #define TRUE 1
00069 #endif
00070 
00071 /*-- Forward declarations */
00072 static int aji_highest_bit(int number);
00073 static void aji_buddy_destroy(struct aji_buddy *obj);
00074 static void aji_client_destroy(struct aji_client *obj);
00075 static int aji_send_exec(struct ast_channel *chan, void *data);
00076 static int aji_status_exec(struct ast_channel *chan, void *data);
00077 static void aji_log_hook(void *data, const char *xmpp, size_t size, int is_incoming);
00078 static int aji_act_hook(void *data, int type, iks *node);
00079 static void aji_handle_iq(struct aji_client *client, iks *node);
00080 static void aji_handle_message(struct aji_client *client, ikspak *pak);
00081 static void aji_handle_presence(struct aji_client *client, ikspak *pak);
00082 static void aji_handle_subscribe(struct aji_client *client, ikspak *pak);
00083 static void *aji_recv_loop(void *data);
00084 static int aji_component_initialize(struct aji_client *client);
00085 static int aji_client_initialize(struct aji_client *client);
00086 static int aji_client_connect(void *data, ikspak *pak);
00087 static void aji_set_presence(struct aji_client *client, char *to, char *from, int level, char *desc);
00088 static int aji_do_debug(int fd, int argc, char *argv[]);
00089 static int aji_do_reload(int fd, int argc, char *argv[]);
00090 static int aji_no_debug(int fd, int argc, char *argv[]);
00091 static int aji_test(int fd, int argc, char *argv[]);
00092 static int aji_show_clients(int fd, int argc, char *argv[]);
00093 static int aji_create_client(char *label, struct ast_variable *var, int debug);
00094 static int aji_create_buddy(char *label, struct aji_client *client);
00095 static int aji_reload(void);
00096 static int aji_load_config(void);
00097 static void aji_pruneregister(struct aji_client *client);
00098 static int aji_filter_roster(void *data, ikspak *pak);
00099 static int aji_get_roster(struct aji_client *client);
00100 static int aji_client_info_handler(void *data, ikspak *pak);
00101 static int aji_dinfo_handler(void *data, ikspak *pak);
00102 static int aji_ditems_handler(void *data, ikspak *pak);
00103 static int aji_register_query_handler(void *data, ikspak *pak);
00104 static int aji_register_approve_handler(void *data, ikspak *pak);
00105 static int aji_reconnect(struct aji_client *client);
00106 static iks *jabber_make_auth(iksid * id, const char *pass, const char *sid);
00107 /* No transports in this version */
00108 /*
00109 static int aji_create_transport(char *label, struct aji_client *client);
00110 static int aji_register_transport(void *data, ikspak *pak);
00111 static int aji_register_transport2(void *data, ikspak *pak);
00112 */
00113 
00114 static char debug_usage[] = 
00115 "Usage: jabber debug\n" 
00116 "       Enables dumping of Jabber packets for debugging purposes.\n";
00117 
00118 static char no_debug_usage[] = 
00119 "Usage: jabber debug off\n" 
00120 "       Disables dumping of Jabber packets for debugging purposes.\n";
00121 
00122 static char reload_usage[] = 
00123 "Usage: jabber reload\n" 
00124 "       Enables reloading of Jabber module.\n";
00125 
00126 static char test_usage[] = 
00127 "Usage: jabber test [client]\n" 
00128 "       Sends test message for debugging purposes.  A specific client\n"
00129 "       as configured in jabber.conf can be optionally specified.\n";
00130 
00131 static struct ast_cli_entry aji_cli[] = {
00132    { { "jabber", "debug", NULL},
00133    aji_do_debug, "Enable Jabber debugging",
00134    debug_usage },
00135 
00136    { { "jabber", "reload", NULL},
00137    aji_do_reload, "Reload Jabber configuration",
00138    reload_usage },
00139 
00140    { { "jabber", "show", "connected", NULL},
00141    aji_show_clients, "Show state of clients and components",
00142    debug_usage },
00143 
00144    { { "jabber", "debug", "off", NULL},
00145    aji_no_debug, "Disable Jabber debug",
00146    no_debug_usage },
00147 
00148    { { "jabber", "test", NULL},
00149    aji_test, "Shows roster, but is generally used for mog's debugging.",
00150    test_usage },
00151 };
00152 
00153 static char *app_ajisend = "JabberSend";
00154 
00155 static char *ajisend_synopsis = "JabberSend(jabber,screenname,message)";
00156 
00157 static char *ajisend_descrip =
00158 "JabberSend(Jabber,ScreenName,Message)\n"
00159 "  Jabber - Client or transport Asterisk uses to connect to Jabber\n" 
00160 "  ScreenName - User Name to message.\n" 
00161 "  Message - Message to be sent to the buddy\n";
00162 
00163 static char *app_ajistatus = "JabberStatus";
00164 
00165 static char *ajistatus_synopsis = "JabberStatus(Jabber,ScreenName,Variable)";
00166 
00167 static char *ajistatus_descrip =
00168 "JabberStatus(Jabber,ScreenName,Variable)\n"
00169 "  Jabber - Client or transport Asterisk uses to connect to Jabber\n"
00170 "  ScreenName - User Name to retrieve status from.\n"
00171 "  Variable - Variable to store presence in will be 1-6.\n" 
00172 "             In order, Online, Chatty, Away, XAway, DND, Offline\n" 
00173 "             If not in roster variable will = 7\n";
00174 
00175 struct aji_client_container clients;
00176 struct aji_capabilities *capabilities = NULL;
00177 
00178 /*! \brief Global flags, initialized to default values */
00179 static struct ast_flags globalflags = { AJI_AUTOPRUNE | AJI_AUTOREGISTER };
00180 static int tls_initialized = FALSE;
00181 
00182 /*!
00183  * \brief Deletes the aji_client data structure.
00184  * \param obj is the structure we will delete.
00185  * \return void.
00186  */
00187 static void aji_client_destroy(struct aji_client *obj)
00188 {
00189    struct aji_message *tmp;
00190    ASTOBJ_CONTAINER_DESTROYALL(&obj->buddies, aji_buddy_destroy);
00191    ASTOBJ_CONTAINER_DESTROY(&obj->buddies);
00192    iks_filter_delete(obj->f);
00193    iks_parser_delete(obj->p);
00194    iks_stack_delete(obj->stack);
00195    AST_LIST_LOCK(&obj->messages);
00196    while ((tmp = AST_LIST_REMOVE_HEAD(&obj->messages, list))) {
00197       if (tmp->from)
00198          free(tmp->from);
00199       if (tmp->message)
00200          free(tmp->message);
00201    }
00202    AST_LIST_HEAD_DESTROY(&obj->messages);
00203    free(obj);
00204 }
00205 
00206 /*!
00207  * \brief Deletes the aji_buddy data structure.
00208  * \param obj is the structure we will delete.
00209  * \return void.
00210  */
00211 static void aji_buddy_destroy(struct aji_buddy *obj)
00212 {
00213    struct aji_resource *tmp;
00214 
00215    while ((tmp = obj->resources)) {
00216       obj->resources = obj->resources->next;
00217       free(tmp->description);
00218       free(tmp);
00219    }
00220 
00221    free(obj);
00222 }
00223 
00224 /*!
00225  * \brief Find version in XML stream and populate our capabilities list
00226  * \param node the node attribute in the caps element we'll look for or add to 
00227  * our list
00228  * \param version the version attribute in the caps element we'll look for or 
00229  * add to our list
00230  * \param pak the XML stanza we're processing
00231  * \return a pointer to the added or found aji_version structure
00232  */ 
00233 static struct aji_version *aji_find_version(char *node, char *version, ikspak *pak)
00234 {
00235    struct aji_capabilities *list = NULL;
00236    struct aji_version *res = NULL;
00237 
00238    list = capabilities;
00239 
00240    if(!node)
00241       node = pak->from->full;
00242    if(!version)
00243       version = "none supplied.";
00244    while(list) {
00245       if(!strcasecmp(list->node, node)) {
00246          res = list->versions;
00247          while(res) {
00248              if(!strcasecmp(res->version, version))
00249                 return res;
00250              res = res->next;
00251          }
00252          /* Specified version not found. Let's add it to 
00253             this node in our capabilities list */
00254          if(!res) {
00255             res = (struct aji_version *)malloc(sizeof(struct aji_version));
00256             if(!res) {
00257                ast_log(LOG_ERROR, "Out of memory!\n");
00258                return NULL;
00259             }
00260             res->jingle = 0;
00261             res->parent = list;
00262             ast_copy_string(res->version, version, sizeof(res->version));
00263             res->next = list->versions;
00264             list->versions = res;
00265             return res;
00266          }
00267       }
00268       list = list->next;
00269    }
00270    /* Specified node not found. Let's add it our capabilities list */
00271    if(!list) {
00272       list = (struct aji_capabilities *)malloc(sizeof(struct aji_capabilities));
00273       if(!list) {
00274          ast_log(LOG_ERROR, "Out of memory!\n");
00275          return NULL;
00276       }
00277       res = (struct aji_version *)malloc(sizeof(struct aji_version));
00278       if(!res) {
00279          ast_log(LOG_ERROR, "Out of memory!\n");
00280          ast_free(list);
00281          return NULL;
00282       }
00283       ast_copy_string(list->node, node, sizeof(list->node));
00284       ast_copy_string(res->version, version, sizeof(res->version));
00285       res->jingle = 0;
00286       res->parent = list;
00287       res->next = NULL;
00288       list->versions = res;
00289       list->next = capabilities;
00290       capabilities = list;
00291    }
00292    return res;
00293 }
00294 
00295 static struct aji_resource *aji_find_resource(struct aji_buddy *buddy, char *name)
00296 {
00297    struct aji_resource *res = NULL;
00298    if (!buddy || !name)
00299       return res;
00300    res = buddy->resources;
00301    while (res) {
00302       if (!strcasecmp(res->resource, name)) {
00303          break;
00304       }
00305       res = res->next;
00306    }
00307    return res;
00308 }
00309 
00310 static int gtalk_yuck(iks *node)
00311 {
00312    if (iks_find_with_attrib(node, "c", "node", "http://www.google.com/xmpp/client/caps"))
00313       return 1;
00314    return 0;
00315 }
00316 
00317 /*!
00318  * \brief Detects the highest bit in a number.
00319  * \param Number you want to have evaluated.
00320  * \return the highest power of 2 that can go into the number.
00321  */
00322 static int aji_highest_bit(int number)
00323 {
00324    int x = sizeof(number) * 8 - 1;
00325    if (!number)
00326       return 0;
00327    for (; x > 0; x--) {
00328       if (number & (1 << x))
00329          break;
00330    }
00331    return (1 << x);
00332 }
00333 
00334 static iks *jabber_make_auth(iksid * id, const char *pass, const char *sid)
00335 {
00336    iks *x, *y;
00337    x = iks_new("iq");
00338    iks_insert_attrib(x, "type", "set");
00339    y = iks_insert(x, "query");
00340    iks_insert_attrib(y, "xmlns", IKS_NS_AUTH);
00341    iks_insert_cdata(iks_insert(y, "username"), id->user, 0);
00342    iks_insert_cdata(iks_insert(y, "resource"), id->resource, 0);
00343    if (sid) {
00344       char buf[41];
00345       char sidpass[100];
00346       snprintf(sidpass, sizeof(sidpass), "%s%s", sid, pass);
00347       ast_sha1_hash(buf, sidpass);
00348       iks_insert_cdata(iks_insert(y, "digest"), buf, 0);
00349    } else {
00350       iks_insert_cdata(iks_insert(y, "password"), pass, 0);
00351    }
00352    return x;
00353 }
00354 
00355 /*!
00356  * \brief Dial plan function status(). puts the status of watched user 
00357    into a channel variable.
00358  * \param channel, and username,watched user, status var
00359  * \return 0.
00360  */
00361 static int aji_status_exec(struct ast_channel *chan, void *data)
00362 {
00363    struct aji_client *client = NULL;
00364    struct aji_buddy *buddy = NULL;
00365    struct aji_resource *r = NULL;
00366    char *s = NULL, *sender = NULL, *jid = NULL, *screenname = NULL, *resource = NULL, *variable = NULL;
00367    int stat = 7;
00368    char status[2];
00369 
00370    if (!data) {
00371       ast_log(LOG_ERROR, "This application requires arguments.\n");
00372       return 0;
00373    }
00374    s = ast_strdupa(data);
00375    if (s) {
00376       sender = strsep(&s, "|");
00377       if (sender && (sender[0] != '\0')) {
00378          jid = strsep(&s, "|");
00379          if (jid && (jid[0] != '\0')) {
00380             variable = s;
00381          } else {
00382             ast_log(LOG_ERROR, "Bad arguments\n");
00383             return -1;
00384          }
00385       }
00386    }
00387 
00388    if(!strchr(jid, '/')) {
00389       resource = NULL;
00390    } else {
00391       screenname = strsep(&jid, "/");
00392       resource = jid;
00393    }
00394    client = ast_aji_get_client(sender);
00395    if (!client) {
00396       ast_log(LOG_WARNING, "Could not find sender connection: %s\n", sender);
00397       return -1;
00398    }
00399    if(!&client->buddies) {
00400       ast_log(LOG_WARNING, "No buddies for connection : %s\n", sender);
00401       return -1;
00402    }
00403    buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, resource ? screenname: jid);
00404    if (!buddy) {
00405       ast_log(LOG_WARNING, "Could not find buddy in list : %s\n", resource ? screenname : jid);
00406       return -1;
00407    }
00408    r = aji_find_resource(buddy, resource);
00409    if(!r && buddy->resources) 
00410       r = buddy->resources;
00411    if(!r)
00412       ast_log(LOG_NOTICE, "Resource %s of buddy %s not found \n", resource, screenname);
00413    else
00414       stat = r->status;
00415    sprintf(status, "%d", stat);
00416    pbx_builtin_setvar_helper(chan, variable, status);
00417    return 0;
00418 }
00419 
00420 /*!
00421  * \brief Dial plan function to send a message.
00422  * \param channel, and data, data is sender, reciever, message.
00423  * \return 0.
00424  */
00425 static int aji_send_exec(struct ast_channel *chan, void *data)
00426 {
00427    struct aji_client *client = NULL;
00428 
00429    char *s = NULL, *sender = NULL, *recipient = NULL, *message = NULL;
00430 
00431    if (!data) {
00432       ast_log(LOG_ERROR, "This application requires arguments.\n");
00433       return 0;
00434    }
00435    s = ast_strdupa(data);
00436    if (s) {
00437       sender = strsep(&s, "|");
00438       if (sender && (sender[0] != '\0')) {
00439          recipient = strsep(&s, "|");
00440          if (recipient && (recipient[0] != '\0')) {
00441             message = s;
00442          } else {
00443             ast_log(LOG_ERROR, "Bad arguments: %s\n", (char *) data);
00444             return -1;
00445          }
00446       }
00447    }
00448    if (!(client = ast_aji_get_client(sender))) {
00449       ast_log(LOG_WARNING, "Could not find sender connection: %s\n", sender);
00450       return -1;
00451    }
00452    if (strchr(recipient, '@') && message)
00453       ast_aji_send(client, recipient, message);
00454    return 0;
00455 }
00456 
00457 /*!
00458  * \brief the debug loop.
00459  * \param aji_client structure, xml data as string, size of string, direction of packet, 1 for inbound 0 for outbound.
00460  */
00461 static void aji_log_hook(void *data, const char *xmpp, size_t size, int is_incoming)
00462 {
00463    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00464    manager_event(EVENT_FLAG_USER, "JabberEvent", "Account: %s\r\nPacket: %s\r\n", client->name, xmpp);
00465 
00466    if (client->debug) {
00467       if (is_incoming)
00468          ast_verbose("\nJABBER: %s INCOMING: %s\n", client->name, xmpp);
00469       else {
00470          if( strlen(xmpp) == 1) {
00471             if(option_debug > 2  && xmpp[0] == ' ')
00472             ast_verbose("\nJABBER: Keep alive packet\n");
00473          } else
00474             ast_verbose("\nJABBER: %s OUTGOING: %s\n", client->name, xmpp);
00475       }
00476 
00477    }
00478    ASTOBJ_UNREF(client, aji_client_destroy);
00479 }
00480 
00481 /*!
00482  * \brief The action hook parses the inbound packets, constantly running.
00483  * \param data aji client structure 
00484  * \param type type of packet 
00485  * \param node the actual packet.
00486  * \return IKS_OK or IKS_HOOK .
00487  */
00488 static int aji_act_hook(void *data, int type, iks *node)
00489 {
00490    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00491    ikspak *pak = NULL;
00492    iks *auth = NULL;
00493 
00494    if(!node) {
00495       ast_log(LOG_ERROR, "aji_act_hook was called with out a packet\n"); /* most likely cause type is IKS_NODE_ERROR lost connection */
00496       ASTOBJ_UNREF(client, aji_client_destroy);
00497       return IKS_HOOK;
00498    }
00499 
00500    if (client->state == AJI_DISCONNECTING) {
00501       ASTOBJ_UNREF(client, aji_client_destroy);
00502       return IKS_HOOK;
00503    }
00504 
00505    pak = iks_packet(node);
00506 
00507    if (!client->component) { /*client */
00508       switch (type) {
00509       case IKS_NODE_START:
00510          if (client->usetls && !iks_is_secure(client->p)) {
00511             if (iks_has_tls()) {
00512                iks_start_tls(client->p);
00513                tls_initialized = TRUE;
00514             } else
00515                ast_log(LOG_ERROR, "gnuTLS not installed. You need to recompile the Iksemel library with gnuTLS support\n");
00516             break;
00517          }
00518          if (!client->usesasl) {
00519             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, client->mid, IKS_RULE_DONE);
00520             auth = jabber_make_auth(client->jid, client->password, iks_find_attrib(node, "id"));
00521             if (auth) {
00522                iks_insert_attrib(auth, "id", client->mid);
00523                iks_insert_attrib(auth, "to", client->jid->server);
00524                ast_aji_increment_mid(client->mid);
00525                iks_send(client->p, auth);
00526                iks_delete(auth);
00527             } else
00528                ast_log(LOG_ERROR, "Out of memory.\n");
00529          }
00530          break;
00531 
00532       case IKS_NODE_NORMAL:
00533          if (!strcmp("stream:features", iks_name(node))) {
00534             int features = 0;
00535             features = iks_stream_features(node);
00536             if (client->usesasl) {
00537                if (client->usetls && !iks_is_secure(client->p))
00538                   break;
00539                if (client->authorized) {
00540                   if (features & IKS_STREAM_BIND) {
00541                      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);
00542                      auth = iks_make_resource_bind(client->jid);
00543                      if (auth) {
00544                         iks_insert_attrib(auth, "id", client->mid);
00545                         ast_aji_increment_mid(client->mid);
00546                         iks_send(client->p, auth);
00547                         iks_delete(auth);
00548                      } else {
00549                         ast_log(LOG_ERROR, "Out of memory.\n");
00550                         break;
00551                      }
00552                   }
00553                   if (features & IKS_STREAM_SESSION) {
00554                      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);
00555                      auth = iks_make_session();
00556                      if (auth) {
00557                         iks_insert_attrib(auth, "id", "auth");
00558                         ast_aji_increment_mid(client->mid);
00559                         iks_send(client->p, auth);
00560                         iks_delete(auth);
00561                      } else {
00562                         ast_log(LOG_ERROR, "Out of memory.\n");
00563                      }
00564                   }
00565                } else {
00566                   if (!client->jid->user) {
00567                      ast_log(LOG_ERROR, "Malformed Jabber ID : %s (domain missing?)\n", client->jid->full);
00568                      break;
00569                   }
00570                   features = aji_highest_bit(features);
00571                   if (features == IKS_STREAM_SASL_MD5)
00572                      iks_start_sasl(client->p, IKS_SASL_DIGEST_MD5, client->jid->user, client->password);
00573                   else {
00574                      if (features == IKS_STREAM_SASL_PLAIN) {
00575                         iks *x = NULL;
00576                         x = iks_new("auth");
00577                         if (x) {
00578                            int len = strlen(client->jid->user) + strlen(client->password) + 3;
00579                            /* XXX Check return values XXX */
00580                            char *s = ast_malloc(80 + len);
00581                            char *base64 = ast_malloc(80 + len * 2);
00582                            iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_SASL);
00583                            iks_insert_attrib(x, "mechanism", "PLAIN");
00584                            sprintf(s, "%c%s%c%s", 0, client->jid->user, 0, client->password);
00585                               
00586                            /* exclude the NULL training byte from the base64 encoding operation
00587                               as some XMPP servers will refuse it.
00588                               The format for authentication is [authzid]\0authcid\0password
00589                               not [authzid]\0authcid\0password\0 */
00590                            ast_base64encode(base64, (const unsigned char *) s, len - 1, len * 2);
00591                            iks_insert_cdata(x, base64, 0);
00592                            iks_send(client->p, x);
00593                            iks_delete(x);
00594                            if (base64)
00595                               free(base64);
00596                            if (s)
00597                               free(s);
00598                         } else {
00599                            ast_log(LOG_ERROR, "Out of memory.\n");
00600                         }
00601                      }
00602                   }
00603                }
00604             }
00605          } else if (!strcmp("failure", iks_name(node))) {
00606             ast_log(LOG_ERROR, "JABBER: encryption failure. possible bad password.\n");
00607          } else if (!strcmp("success", iks_name(node))) {
00608             client->authorized = 1;
00609             iks_send_header(client->p, client->jid->server);
00610          }
00611          break;
00612       case IKS_NODE_ERROR: 
00613             ast_log(LOG_ERROR, "JABBER: Node Error\n");
00614             ASTOBJ_UNREF(client, aji_client_destroy);
00615             return IKS_HOOK;
00616             break;
00617       case IKS_NODE_STOP: 
00618             ast_log(LOG_WARNING, "JABBER: Disconnected\n");
00619             ASTOBJ_UNREF(client, aji_client_destroy);
00620             return IKS_HOOK;
00621             break;
00622       }
00623    } else if (client->state != AJI_CONNECTED && client->component) {
00624       switch (type) {
00625       case IKS_NODE_START:
00626          if (client->state == AJI_DISCONNECTED) {
00627             char secret[160], shasum[320], *handshake;
00628 
00629             sprintf(secret, "%s%s", pak->id, client->password);
00630             ast_sha1_hash(shasum, secret);
00631             handshake = NULL;
00632             if (asprintf(&handshake, "<handshake>%s</handshake>", shasum) > 0) {
00633                iks_send_raw(client->p, handshake);
00634                free(handshake);
00635                handshake = NULL;
00636             }
00637             client->state = AJI_CONNECTING;
00638             if(iks_recv(client->p,1) == 2) /*XXX proper result for iksemel library on iks_recv of <handshake/> XXX*/
00639                client->state = AJI_CONNECTED;
00640             else
00641                ast_log(LOG_WARNING,"Jabber didn't seem to handshake, failed to authenicate.\n");
00642             break;
00643          }
00644          break;
00645 
00646       case IKS_NODE_NORMAL:
00647          break;
00648 
00649       case IKS_NODE_ERROR:
00650          ast_log(LOG_ERROR, "JABBER: Node Error\n");
00651          ASTOBJ_UNREF(client, aji_client_destroy);
00652          return IKS_HOOK;
00653 
00654       case IKS_NODE_STOP:
00655          ast_log(LOG_WARNING, "JABBER: Disconnected\n");
00656          ASTOBJ_UNREF(client, aji_client_destroy);
00657          return IKS_HOOK;
00658       }
00659    }
00660 
00661    switch (pak->type) {
00662    case IKS_PAK_NONE:
00663       if (option_debug)
00664          ast_log(LOG_DEBUG, "JABBER: I Don't know what to do with you NONE\n");
00665       break;
00666    case IKS_PAK_MESSAGE:
00667       aji_handle_message(client, pak);
00668       if (option_debug)
00669          ast_log(LOG_DEBUG, "JABBER: I Don't know what to do with you MESSAGE\n");
00670       break;
00671    case IKS_PAK_PRESENCE:
00672       aji_handle_presence(client, pak);
00673       if (option_debug)
00674          ast_log(LOG_DEBUG, "JABBER: I Do know how to handle presence!!\n");
00675       break;
00676    case IKS_PAK_S10N:
00677       aji_handle_subscribe(client, pak);
00678       if (option_debug)
00679          ast_log(LOG_DEBUG, "JABBER: I Don't know S10N subscribe!!\n");
00680       break;
00681    case IKS_PAK_IQ:
00682       if (option_debug)
00683          ast_log(LOG_DEBUG, "JABBER: I Don't have an IQ!!!\n");
00684       aji_handle_iq(client, node);
00685       break;
00686    default:
00687       if (option_debug)
00688          ast_log(LOG_DEBUG, "JABBER: I Don't know %i\n", pak->type);
00689       break;
00690    }
00691    
00692    iks_filter_packet(client->f, pak);
00693 
00694    if (node)
00695       iks_delete(node);
00696 
00697    ASTOBJ_UNREF(client, aji_client_destroy);
00698    return IKS_OK;
00699 }
00700 
00701 static int aji_register_approve_handler(void *data, ikspak *pak)
00702 {
00703    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00704    iks *iq = NULL, *presence = NULL, *x = NULL;
00705 
00706    iq = iks_new("iq");
00707    presence = iks_new("presence");
00708    x = iks_new("x");
00709    if (client && iq && presence && x) {
00710       if (!iks_find(pak->query, "remove")) {
00711          iks_insert_attrib(iq, "from", client->jid->full);
00712          iks_insert_attrib(iq, "to", pak->from->full);
00713          iks_insert_attrib(iq, "id", pak->id);
00714          iks_insert_attrib(iq, "type", "result");
00715          iks_send(client->p, iq);
00716 
00717          iks_insert_attrib(presence, "from", client->jid->full);
00718          iks_insert_attrib(presence, "to", pak->from->partial);
00719          iks_insert_attrib(presence, "id", client->mid);
00720          ast_aji_increment_mid(client->mid);
00721          iks_insert_attrib(presence, "type", "subscribe");
00722          iks_insert_attrib(x, "xmlns", "vcard-temp:x:update");
00723          iks_insert_node(presence, x);
00724          iks_send(client->p, presence); 
00725       }
00726    } else {
00727       ast_log(LOG_ERROR, "Out of memory.\n");
00728    }
00729 
00730    if (iq)
00731       iks_delete(iq);
00732    if(presence)
00733       iks_delete(presence);
00734    if (x)
00735       iks_delete(x);
00736    ASTOBJ_UNREF(client, aji_client_destroy);
00737    return IKS_FILTER_EAT;
00738 }
00739 
00740 static int aji_register_query_handler(void *data, ikspak *pak)
00741 {
00742    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00743    struct aji_buddy *buddy = NULL; 
00744    char *node = NULL;
00745 
00746    client = (struct aji_client *) data;
00747 
00748    buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
00749    if (!buddy) {
00750       iks *iq = NULL, *query = NULL, *error = NULL, *notacceptable = NULL;
00751       ast_verbose("Someone.... %s tried to register but they aren't allowed\n", pak->from->partial);
00752       iq = iks_new("iq");
00753       query = iks_new("query");
00754       error = iks_new("error");
00755       notacceptable = iks_new("not-acceptable");
00756       if(iq && query && error && notacceptable) {
00757          iks_insert_attrib(iq, "type", "error");
00758          iks_insert_attrib(iq, "from", client->user);
00759          iks_insert_attrib(iq, "to", pak->from->full);
00760          iks_insert_attrib(iq, "id", pak->id);
00761          iks_insert_attrib(query, "xmlns", "jabber:iq:register");
00762          iks_insert_attrib(error, "code" , "406");
00763          iks_insert_attrib(error, "type", "modify");
00764          iks_insert_attrib(notacceptable, "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas");
00765          iks_insert_node(iq, query);
00766          iks_insert_node(iq, error);
00767          iks_insert_node(error, notacceptable);
00768          iks_send(client->p, iq);
00769       } else {
00770          ast_log(LOG_ERROR, "Out of memory.\n");
00771       }
00772       if (iq)
00773          iks_delete(iq);
00774       if (query)
00775          iks_delete(query);
00776       if (error)
00777          iks_delete(error);
00778       if (notacceptable)
00779          iks_delete(notacceptable);
00780    } else   if (!(node = iks_find_attrib(pak->query, "node"))) {
00781       iks *iq = NULL, *query = NULL, *instructions = NULL;
00782       char *explain = "Welcome to Asterisk - the Open Source PBX.\n";
00783       iq = iks_new("iq");
00784       query = iks_new("query");
00785       instructions = iks_new("instructions");
00786       if (iq && query && instructions && client) {
00787          iks_insert_attrib(iq, "from", client->user);
00788          iks_insert_attrib(iq, "to", pak->from->full);
00789          iks_insert_attrib(iq, "id", pak->id);
00790          iks_insert_attrib(iq, "type", "result");
00791          iks_insert_attrib(query, "xmlns", "jabber:iq:register");
00792          iks_insert_cdata(instructions, explain, 0);
00793          iks_insert_node(iq, query);
00794          iks_insert_node(query, instructions);
00795          iks_send(client->p, iq);
00796       } else {
00797          ast_log(LOG_ERROR, "Out of memory.\n");
00798       }
00799       if (iq)
00800          iks_delete(iq);
00801       if (query)
00802          iks_delete(query);
00803       if (instructions)
00804          iks_delete(instructions);
00805    }
00806    ASTOBJ_UNREF(client, aji_client_destroy);
00807    return IKS_FILTER_EAT;
00808 }
00809 
00810 static int aji_ditems_handler(void *data, ikspak *pak)
00811 {
00812    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00813    char *node = NULL;
00814 
00815    if (!(node = iks_find_attrib(pak->query, "node"))) {
00816       iks *iq = NULL, *query = NULL, *item = NULL;
00817       iq = iks_new("iq");
00818       query = iks_new("query");
00819       item = iks_new("item");
00820 
00821       if (iq && query && item) {
00822          iks_insert_attrib(iq, "from", client->user);
00823          iks_insert_attrib(iq, "to", pak->from->full);
00824          iks_insert_attrib(iq, "id", pak->id);
00825          iks_insert_attrib(iq, "type", "result");
00826          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
00827          iks_insert_attrib(item, "node", "http://jabber.org/protocol/commands");
00828          iks_insert_attrib(item, "name", "Million Dollar Asterisk Commands");
00829          iks_insert_attrib(item, "jid", client->user);
00830 
00831          iks_insert_node(iq, query);
00832          iks_insert_node(query, item);
00833          iks_send(client->p, iq);
00834       } else {
00835          ast_log(LOG_ERROR, "Out of memory.\n");
00836       }
00837       if (iq)
00838          iks_delete(iq);
00839       if (query)
00840          iks_delete(query);
00841       if (item)
00842          iks_delete(item);
00843 
00844    } else if (!strcasecmp(node, "http://jabber.org/protocol/commands")) {
00845       iks *iq, *query, *confirm;
00846       iq = iks_new("iq");
00847       query = iks_new("query");
00848       confirm = iks_new("item");
00849       if (iq && query && confirm && client) {
00850          iks_insert_attrib(iq, "from", client->user);
00851          iks_insert_attrib(iq, "to", pak->from->full);
00852          iks_insert_attrib(iq, "id", pak->id);
00853          iks_insert_attrib(iq, "type", "result");
00854          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
00855          iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
00856          iks_insert_attrib(confirm, "node", "confirmaccount");
00857          iks_insert_attrib(confirm, "name", "Confirm AIM account");
00858          iks_insert_attrib(confirm, "jid", "blog.astjab.org");
00859 
00860          iks_insert_node(iq, query);
00861          iks_insert_node(query, confirm);
00862          iks_send(client->p, iq);
00863       } else {
00864          ast_log(LOG_ERROR, "Out of memory.\n");
00865       }
00866       if (iq)
00867          iks_delete(iq);
00868       if (query)
00869          iks_delete(query);
00870       if (confirm)
00871          iks_delete(confirm);
00872 
00873    } else if (!strcasecmp(node, "confirmaccount")) {
00874       iks *iq = NULL, *query = NULL, *feature = NULL;
00875 
00876       iq = iks_new("iq");
00877       query = iks_new("query");
00878       feature = iks_new("feature");
00879 
00880       if (iq && query && feature && client) {
00881          iks_insert_attrib(iq, "from", client->user);
00882          iks_insert_attrib(iq, "to", pak->from->full);
00883          iks_insert_attrib(iq, "id", pak->id);
00884          iks_insert_attrib(iq, "type", "result");
00885          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
00886          iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
00887          iks_insert_node(iq, query);
00888          iks_insert_node(query, feature);
00889          iks_send(client->p, iq);
00890       } else {
00891          ast_log(LOG_ERROR, "Out of memory.\n");
00892       }
00893       if (iq)
00894          iks_delete(iq);
00895       if (query)
00896          iks_delete(query);
00897       if (feature)
00898          iks_delete(feature);
00899    }
00900 
00901    ASTOBJ_UNREF(client, aji_client_destroy);
00902    return IKS_FILTER_EAT;
00903 
00904 }
00905 
00906 static int aji_client_info_handler(void *data, ikspak *pak)
00907 {
00908    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00909    struct aji_resource *resource = NULL;
00910    struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
00911 
00912    resource = aji_find_resource(buddy, pak->from->resource);
00913    if (pak->subtype == IKS_TYPE_RESULT) {
00914       if (!resource) {
00915          ast_log(LOG_NOTICE,"JABBER: Received client info from %s when not requested.\n", pak->from->full);
00916          ASTOBJ_UNREF(client, aji_client_destroy);
00917          return IKS_FILTER_EAT;
00918       }
00919       if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
00920          resource->cap->jingle = 1;
00921       } else
00922          resource->cap->jingle = 0;
00923    } else if (pak->subtype == IKS_TYPE_GET) {
00924       iks *iq, *disco, *ident, *google, *query;
00925       iq = iks_new("iq");
00926       query = iks_new("query");
00927       ident = iks_new("identity");
00928       disco = iks_new("feature");
00929       google = iks_new("feature");
00930       if (iq && ident && disco && google) {
00931          iks_insert_attrib(iq, "from", client->jid->full);
00932          iks_insert_attrib(iq, "to", pak->from->full);
00933          iks_insert_attrib(iq, "type", "result");
00934          iks_insert_attrib(iq, "id", pak->id);
00935          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
00936          iks_insert_attrib(ident, "category", "client");
00937          iks_insert_attrib(ident, "type", "pc");
00938          iks_insert_attrib(ident, "name", "asterisk");
00939          iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco#info");
00940          iks_insert_attrib(google, "var", "http://www.google.com/xmpp/protocol/voice/v1");
00941          iks_insert_node(iq, query);
00942          iks_insert_node(query, ident);
00943          iks_insert_node(query, google);
00944          iks_insert_node(query, disco);
00945          iks_send(client->p, iq);
00946       } else
00947          ast_log(LOG_ERROR, "Out of Memory.\n");
00948       if (iq)
00949          iks_delete(iq);
00950       if (query)
00951          iks_delete(query);
00952       if (ident)
00953          iks_delete(ident);
00954       if (google)
00955          iks_delete(google);
00956       if (disco)
00957          iks_delete(disco);
00958    } else if (pak->subtype == IKS_TYPE_ERROR) {
00959       ast_log(LOG_NOTICE, "User %s does not support discovery.\n", pak->from->full);
00960    }
00961    ASTOBJ_UNREF(client, aji_client_destroy);
00962    return IKS_FILTER_EAT;
00963 }
00964 
00965 static int aji_dinfo_handler(void *data, ikspak *pak)
00966 {
00967    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00968    char *node = NULL;
00969    struct aji_resource *resource = NULL;
00970    struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
00971 
00972    resource = aji_find_resource(buddy, pak->from->resource);
00973    if (pak->subtype == IKS_TYPE_ERROR) {
00974       ast_log(LOG_WARNING, "Received error from a client, turn on jabber debug!\n");
00975       return IKS_FILTER_EAT;
00976    }
00977    if (pak->subtype == IKS_TYPE_RESULT) {
00978       if (!resource) {
00979          ast_log(LOG_NOTICE,"JABBER: Received client info from %s when not requested.\n", pak->from->full);
00980          ASTOBJ_UNREF(client, aji_client_destroy);
00981          return IKS_FILTER_EAT;
00982       }
00983       if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
00984          resource->cap->jingle = 1;
00985       } else
00986          resource->cap->jingle = 0;
00987    } else if (pak->subtype == IKS_TYPE_GET && !(node = iks_find_attrib(pak->query, "node"))) {
00988       iks *iq, *query, *identity, *disco, *reg, *commands, *gateway, *version, *vcard, *search;
00989 
00990       iq = iks_new("iq");
00991       query = iks_new("query");
00992       identity = iks_new("identity");
00993       disco = iks_new("feature");
00994       reg = iks_new("feature");
00995       commands = iks_new("feature");
00996       gateway = iks_new("feature");
00997       version = iks_new("feature");
00998       vcard = iks_new("feature");
00999       search = iks_new("feature");
01000 
01001       if (iq && query && identity && disco && reg && commands && gateway && version && vcard && search && client) {
01002          iks_insert_attrib(iq, "from", client->user);
01003          iks_insert_attrib(iq, "to", pak->from->full);
01004          iks_insert_attrib(iq, "id", pak->id);
01005          iks_insert_attrib(iq, "type", "result");
01006          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01007          iks_insert_attrib(identity, "category", "gateway");
01008          iks_insert_attrib(identity, "type", "pstn");
01009          iks_insert_attrib(identity, "name", "Asterisk The Open Source PBX");
01010          iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco");
01011          iks_insert_attrib(reg, "var", "jabber:iq:register");
01012          iks_insert_attrib(commands, "var", "http://jabber.org/protocol/commands");
01013          iks_insert_attrib(gateway, "var", "jabber:iq:gateway");
01014          iks_insert_attrib(version, "var", "jabber:iq:version");
01015          iks_insert_attrib(vcard, "var", "vcard-temp");
01016          iks_insert_attrib(search, "var", "jabber:iq:search");
01017 
01018          iks_insert_node(iq, query);
01019          iks_insert_node(query, identity);
01020          iks_insert_node(query, disco);
01021          iks_insert_node(query, reg);
01022          iks_insert_node(query, commands);
01023          iks_insert_node(query, gateway);
01024          iks_insert_node(query, version);
01025          iks_insert_node(query, vcard);
01026          iks_insert_node(query, search);
01027          iks_send(client->p, iq);
01028       } else {
01029          ast_log(LOG_ERROR, "Out of memory.\n");
01030       }
01031 
01032       if (iq)
01033          iks_delete(iq);
01034       if (query)
01035          iks_delete(query);
01036       if (identity)
01037          iks_delete(identity);
01038       if (disco)
01039          iks_delete(disco);
01040       if (reg)
01041          iks_delete(reg);
01042       if (commands)
01043          iks_delete(commands);
01044       if (gateway)
01045          iks_delete(gateway);
01046       if (version)
01047          iks_delete(version);
01048       if (vcard)
01049          iks_delete(vcard);
01050       if (search)
01051          iks_delete(search);
01052 
01053    } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "http://jabber.org/protocol/commands")) {
01054       iks *iq, *query, *confirm;
01055       iq = iks_new("iq");
01056       query = iks_new("query");
01057       confirm = iks_new("item");
01058 
01059       if (iq && query && confirm && client) {
01060          iks_insert_attrib(iq, "from", client->user);
01061          iks_insert_attrib(iq, "to", pak->from->full);
01062          iks_insert_attrib(iq, "id", pak->id);
01063          iks_insert_attrib(iq, "type", "result");
01064          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01065          iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
01066          iks_insert_attrib(confirm, "node", "confirmaccount");
01067          iks_insert_attrib(confirm, "name", "Confirm AIM account");
01068          iks_insert_attrib(confirm, "jid", client->user);
01069          iks_insert_node(iq, query);
01070          iks_insert_node(query, confirm);
01071          iks_send(client->p, iq);
01072       } else {
01073          ast_log(LOG_ERROR, "Out of memory.\n");
01074       }
01075       if (iq)
01076          iks_delete(iq);
01077       if (query)
01078          iks_delete(query);
01079       if (confirm)
01080          iks_delete(confirm);
01081 
01082    } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "confirmaccount")) {
01083       iks *iq, *query, *feature;
01084 
01085       iq = iks_new("iq");
01086       query = iks_new("query");
01087       feature = iks_new("feature");
01088 
01089       if (iq && query && feature && client) {
01090          iks_insert_attrib(iq, "from", client->user);
01091          iks_insert_attrib(iq, "to", pak->from->full);
01092          iks_insert_attrib(iq, "id", pak->id);
01093          iks_insert_attrib(iq, "type", "result");
01094          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01095          iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
01096          iks_insert_node(iq, query);
01097          iks_insert_node(query, feature);
01098          iks_send(client->p, iq);
01099       } else {
01100          ast_log(LOG_ERROR, "Out of memory.\n");
01101       }
01102       if (iq)
01103          iks_delete(iq);
01104       if (query)
01105          iks_delete(query);
01106       if (feature)
01107          iks_delete(feature);
01108    }
01109 
01110    ASTOBJ_UNREF(client, aji_client_destroy);
01111    return IKS_FILTER_EAT;
01112 }
01113 
01114 /*!
01115  * \brief Handles <iq> tags.
01116  * \param client structure and the iq node.
01117  * \return void.
01118  */
01119 static void aji_handle_iq(struct aji_client *client, iks *node)
01120 {
01121    /*Nothing to see here */
01122 }
01123 
01124 /*!
01125  * \brief Handles presence packets.
01126  * \param client structure and the node.
01127  * \return void.
01128  */
01129 static void aji_handle_message(struct aji_client *client, ikspak *pak)
01130 {
01131    struct aji_message *insert, *tmp;
01132    int flag = 0;
01133    
01134    if (!(insert = ast_calloc(1, sizeof(struct aji_message))))
01135       return;
01136    time(&insert->arrived);
01137    if (iks_find_cdata(pak->x, "body"))
01138       insert->message = ast_strdup(iks_find_cdata(pak->x, "body"));
01139    if(pak->id)
01140       ast_copy_string(insert->id, pak->id, sizeof(insert->message));
01141    if (pak->from)
01142       insert->from = ast_strdup(pak->from->full);
01143    AST_LIST_LOCK(&client->messages);
01144    AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, tmp, list) {
01145       if (flag) {
01146          AST_LIST_REMOVE_CURRENT(&client->messages, list);
01147          if (tmp->from)
01148             free(tmp->from);
01149          if (tmp->message)
01150             free(tmp->message);
01151       } else if (difftime(time(NULL), tmp->arrived) >= client->message_timeout) {
01152          flag = 1;
01153          AST_LIST_REMOVE_CURRENT(&client->messages, list);
01154          if (tmp->from)
01155             free(tmp->from);
01156          if (tmp->message)
01157             free(tmp->message);
01158       }
01159    }
01160    AST_LIST_TRAVERSE_SAFE_END;
01161    AST_LIST_INSERT_HEAD(&client->messages, insert, list);
01162    AST_LIST_UNLOCK(&client->messages);
01163 }
01164 
01165 static void aji_handle_presence(struct aji_client *client, ikspak *pak)
01166 {
01167    int status, priority;
01168    struct aji_buddy *buddy;
01169    struct aji_resource *tmp = NULL, *last = NULL, *found = NULL;
01170    char *ver, *node, *descrip, *type;
01171    
01172    if(client->state != AJI_CONNECTED)
01173       aji_create_buddy(pak->from->partial, client);
01174 
01175    buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01176    if (!buddy && pak->from->partial) {
01177       /* allow our jid to be used to log in with another resource */
01178       if (!strcmp((const char *)pak->from->partial, (const char *)client->jid->partial))
01179          aji_create_buddy(pak->from->partial, client);
01180       else
01181          ast_log(LOG_NOTICE, "Got presence packet from %s, someone not in our roster!!!!\n", pak->from->partial);
01182       return;
01183    }
01184    type = iks_find_attrib(pak->x, "type");
01185    if(client->component && type &&!strcasecmp("probe", type)) {
01186       aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), 1, client->statusmessage);
01187       ast_verbose("what i was looking for \n");
01188    }
01189    ASTOBJ_WRLOCK(buddy);
01190    status = (pak->show) ? pak->show : 6;
01191    priority = atoi((iks_find_cdata(pak->x, "priority")) ? iks_find_cdata(pak->x, "priority") : "0");
01192    tmp = buddy->resources;
01193    descrip = ast_strdup(iks_find_cdata(pak->x,"status"));
01194 
01195    while (tmp && pak->from->resource) {
01196       if (!strcasecmp(tmp->resource, pak->from->resource)) {
01197          tmp->status = status;
01198          if (tmp->description) free(tmp->description);
01199          tmp->description = descrip;
01200          found = tmp;
01201          if (status == 6) {   /* Sign off Destroy resource */
01202             if (last && found->next) {
01203                last->next = found->next;
01204             } else if (!last) {
01205                if (found->next)
01206                   buddy->resources = found->next;
01207                else
01208                   buddy->resources = NULL;
01209             } else if (!found->next) {
01210                if (last)
01211                   last->next = NULL;
01212                else
01213                   buddy->resources = NULL;
01214             }
01215             free(found);
01216             found = NULL;
01217             break;
01218          }
01219          /* resource list is sorted by descending priority */
01220          if (tmp->priority != priority) {
01221             found->priority = priority;
01222             if (!last && !found->next)
01223                /* resource was found to be unique,
01224                   leave loop */
01225                break;
01226             /* search for resource in our list
01227                and take it out for the moment */
01228             if (last)
01229                last->next = found->next;
01230             else
01231                buddy->resources = found->next;
01232 
01233             last = NULL;
01234             tmp = buddy->resources;
01235             if (!buddy->resources)
01236                buddy->resources = found;
01237             /* priority processing */
01238             while (tmp) {
01239                /* insert resource back according to 
01240                   its priority value */
01241                if (found->priority > tmp->priority) {
01242                   if (last)
01243                      /* insert within list */
01244                      last->next = found;
01245                   found->next = tmp;
01246                   if (!last)
01247                      /* insert on top */
01248                      buddy->resources = found;
01249                   break;
01250                }
01251                if (!tmp->next) {
01252                   /* insert at the end of the list */
01253                   tmp->next = found;
01254                   found->next = NULL;
01255                   break;
01256                }
01257                last = tmp;
01258                tmp = tmp->next;
01259             }
01260          }
01261          break;
01262       }
01263       last = tmp;
01264       tmp = tmp->next;
01265    }
01266 
01267    /* resource not found in our list, create it */
01268    if (!found && status != 6 && pak->from->resource) {
01269       found = (struct aji_resource *) malloc(sizeof(struct aji_resource));
01270       memset(found, 0, sizeof(struct aji_resource));
01271 
01272       if (!found) {
01273          ast_log(LOG_ERROR, "Out of memory!\n");
01274          return;
01275       }
01276       ast_copy_string(found->resource, pak->from->resource, sizeof(found->resource));
01277       found->status = status;
01278       found->description = descrip;
01279       found->priority = priority;
01280       found->next = NULL;
01281       last = NULL;
01282       tmp = buddy->resources;
01283       while (tmp) {
01284          if (found->priority > tmp->priority) {
01285             if (last)
01286                last->next = found;
01287             found->next = tmp;
01288             if (!last)
01289                buddy->resources = found;
01290             break;
01291          }
01292          if (!tmp->next) {
01293             tmp->next = found;
01294             break;
01295          }
01296          last = tmp;
01297          tmp = tmp->next;
01298       }
01299       if (!tmp)
01300          buddy->resources = found;
01301    }
01302    
01303    ASTOBJ_UNLOCK(buddy);
01304    ASTOBJ_UNREF(buddy, aji_buddy_destroy);
01305 
01306    node = iks_find_attrib(iks_find(pak->x, "c"), "node");
01307    ver = iks_find_attrib(iks_find(pak->x, "c"), "ver");
01308 
01309    /* handle gmail client's special caps:c tag */
01310    if (!node && !ver) {
01311       node = iks_find_attrib(iks_find(pak->x, "caps:c"), "node");
01312       ver = iks_find_attrib(iks_find(pak->x, "caps:c"), "ver");
01313    }
01314 
01315    /* retrieve capabilites of the new resource */
01316    if(status !=6 && found && !found->cap) {
01317       found->cap = aji_find_version(node, ver, pak);
01318       if(gtalk_yuck(pak->x)) /* gtalk should do discover */
01319          found->cap->jingle = 1;
01320       if(found->cap->jingle && option_debug > 4)
01321          ast_log(LOG_DEBUG,"Special case for google till they support discover.\n");
01322       else {
01323          iks *iq, *query;
01324          iq = iks_new("iq");
01325          query = iks_new("query");
01326          if(query && iq)  {
01327             iks_insert_attrib(iq, "type", "get");
01328             iks_insert_attrib(iq, "to", pak->from->full);
01329             iks_insert_attrib(iq,"from", client->jid->full);
01330             iks_insert_attrib(iq, "id", client->mid);
01331             ast_aji_increment_mid(client->mid);
01332             iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01333             iks_insert_node(iq, query);
01334             iks_send(client->p, iq);
01335             
01336          } else
01337             ast_log(LOG_ERROR, "Out of memory.\n");
01338          if(query)
01339             iks_delete(query);
01340          if(iq)
01341             iks_delete(iq);
01342       }
01343    }
01344    if (option_verbose > 4) {
01345       switch (pak->subtype) {
01346       case IKS_TYPE_AVAILABLE:
01347          ast_verbose(VERBOSE_PREFIX_3 "JABBER: I am available ^_* %i\n", pak->subtype);
01348          break;
01349       case IKS_TYPE_UNAVAILABLE:
01350          ast_verbose(VERBOSE_PREFIX_3 "JABBER: I am unavailable ^_* %i\n", pak->subtype);
01351          break;
01352       default:
01353          ast_verbose(VERBOSE_PREFIX_3 "JABBER: Ohh sexy and the wrong type: %i\n", pak->subtype);
01354       }
01355       switch (pak->show) {
01356       case IKS_SHOW_UNAVAILABLE:
01357          ast_verbose(VERBOSE_PREFIX_3 "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01358          break;
01359       case IKS_SHOW_AVAILABLE:
01360          ast_verbose(VERBOSE_PREFIX_3 "JABBER: type is available\n");
01361          break;
01362       case IKS_SHOW_CHAT:
01363          ast_verbose(VERBOSE_PREFIX_3 "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01364          break;
01365       case IKS_SHOW_AWAY:
01366          ast_verbose(VERBOSE_PREFIX_3 "JABBER: type is away\n");
01367          break;
01368       case IKS_SHOW_XA:
01369          ast_verbose(VERBOSE_PREFIX_3 "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01370          break;
01371       case IKS_SHOW_DND:
01372          ast_verbose(VERBOSE_PREFIX_3 "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01373          break;
01374       default:
01375          ast_verbose(VERBOSE_PREFIX_3 "JABBER: Kinky! how did that happen %i\n", pak->show);
01376       }
01377    }
01378 }
01379 
01380 /*!
01381  * \brief handles subscription requests.
01382  * \param aji_client struct and xml packet.
01383  * \return void.
01384  */
01385 static void aji_handle_subscribe(struct aji_client *client, ikspak *pak)
01386 {
01387    iks *presence = NULL, *status = NULL;
01388    struct aji_buddy* buddy = NULL;
01389 
01390    switch (pak->subtype) { 
01391    case IKS_TYPE_SUBSCRIBE:
01392       presence = iks_new("presence");
01393       status = iks_new("status");
01394       if(presence && status) {
01395          iks_insert_attrib(presence, "type", "subscribed");
01396          iks_insert_attrib(presence, "to", pak->from->full);
01397          iks_insert_attrib(presence, "from", client->jid->full);
01398          if(pak->id)
01399             iks_insert_attrib(presence, "id", pak->id);
01400          iks_insert_cdata(status, "Asterisk has approved subscription", 0);
01401          iks_insert_node(presence, status);
01402          iks_send(client->p, presence);
01403       } else
01404          ast_log(LOG_ERROR, "Unable to allocate nodes\n");
01405       if(presence)
01406          iks_delete(presence);
01407       if(status)
01408          iks_delete(status);
01409       if(client->component)
01410          aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), 1, client->statusmessage);
01411    case IKS_TYPE_SUBSCRIBED:
01412       buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01413       if (!buddy && pak->from->partial) {
01414          aji_create_buddy(pak->from->partial, client);
01415       }
01416    default:
01417       if (option_verbose > 4) {
01418          ast_verbose(VERBOSE_PREFIX_3 "JABBER: This is a subcription of type %i\n", pak->subtype);
01419       }
01420    }
01421 }
01422 
01423 /*!
01424  * \brief sends messages.
01425  * \param aji_client struct , reciever, message.
01426  * \return 1.
01427  */
01428 int ast_aji_send(struct aji_client *client, const char *address, const char *message)
01429 {
01430    int res = 0;
01431    iks *message_packet = NULL;
01432    if (client->state == AJI_CONNECTED) {
01433       message_packet = iks_make_msg(IKS_TYPE_CHAT, address, message);
01434       if (message_packet) {
01435          iks_insert_attrib(message_packet, "from", client->jid->full);
01436          res = iks_send(client->p, message_packet);
01437       } else {
01438          ast_log(LOG_ERROR, "Out of memory.\n");
01439       }
01440       if (message_packet)
01441          iks_delete(message_packet);
01442    } else
01443       ast_log(LOG_WARNING, "JABBER: Not connected can't send\n");
01444    return 1;
01445 }
01446 
01447 /*!
01448  * \brief create a chatroom.
01449  * \param aji_client struct , room, server, topic for the room.
01450  * \return 0.
01451  */
01452 int ast_aji_create_chat(struct aji_client *client, char *room, char *server, char *topic)
01453 {
01454    int res = 0;
01455    iks *iq = NULL;
01456    iq = iks_new("iq");
01457 
01458    if (iq && client) {
01459       iks_insert_attrib(iq, "type", "get");
01460       iks_insert_attrib(iq, "to", server);
01461       iks_insert_attrib(iq, "id", client->mid);
01462       ast_aji_increment_mid(client->mid);
01463       iks_send(client->p, iq);
01464    } else 
01465       ast_log(LOG_ERROR, "Out of memory.\n");
01466 
01467    iks_delete(iq);
01468 
01469    return res;
01470 }
01471 
01472 /*!
01473  * \brief join a chatroom.
01474  * \param aji_client struct , room.
01475  * \return res.
01476  */
01477 int ast_aji_join_chat(struct aji_client *client, char *room)
01478 {
01479    int res = 0;
01480    iks *presence = NULL, *priority = NULL;
01481    presence = iks_new("presence");
01482    priority = iks_new("priority");
01483    if (presence && priority && client) {
01484       iks_insert_cdata(priority, "0", 1);
01485       iks_insert_attrib(presence, "to", room);
01486       iks_insert_node(presence, priority);
01487       res = iks_send(client->p, presence);
01488       iks_insert_cdata(priority, "5", 1);
01489       iks_insert_attrib(presence, "to", room);
01490       res = iks_send(client->p, presence);
01491    } else 
01492       ast_log(LOG_ERROR, "Out of memory.\n");
01493    if (presence)
01494       iks_delete(presence);
01495    if (priority)
01496       iks_delete(priority);
01497    return res;
01498 }
01499 
01500 /*!
01501  * \brief invite to a chatroom.
01502  * \param aji_client struct ,user, room, message.
01503  * \return res.
01504  */
01505 int ast_aji_invite_chat(struct aji_client *client, char *user, char *room, char *message)
01506 {
01507    int res = 0;
01508    iks *invite, *body, *namespace;
01509 
01510    invite = iks_new("message");
01511    body = iks_new("body");
01512    namespace = iks_new("x");
01513    if (client && invite && body && namespace) {
01514       iks_insert_attrib(invite, "to", user);
01515       iks_insert_attrib(invite, "id", client->mid);
01516       ast_aji_increment_mid(client->mid);
01517       iks_insert_cdata(body, message, 0);
01518       iks_insert_attrib(namespace, "xmlns", "jabber:x:conference");
01519       iks_insert_attrib(namespace, "jid", room);
01520       iks_insert_node(invite, body);
01521       iks_insert_node(invite, namespace);
01522       res = iks_send(client->p, invite);
01523    } else 
01524       ast_log(LOG_ERROR, "Out of memory.\n");
01525    if (body)
01526       iks_delete(body);
01527    if (namespace)
01528       iks_delete(namespace);
01529    if (invite)
01530       iks_delete(invite);
01531    return res;
01532 }
01533 
01534 
01535 /*!
01536  * \brief receive message loop.
01537  * \param aji_client struct.
01538  * \return void.
01539  */
01540 static void *aji_recv_loop(void *data)
01541 {
01542    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01543    int res = IKS_HOOK;
01544    do {
01545       if (res != IKS_OK) {
01546          while(res != IKS_OK) {
01547             if(option_verbose > 3)
01548                ast_verbose("JABBER: reconnecting.\n");
01549             res = aji_reconnect(client);
01550             sleep(4);
01551          }
01552       }
01553 
01554       res = iks_recv(client->p, 1);
01555 
01556       if (client->state == AJI_DISCONNECTING) {
01557          if (option_debug > 1)
01558             ast_log(LOG_DEBUG, "Ending our Jabber client's thread due to a disconnect\n");
01559          pthread_exit(NULL);
01560       }
01561       client->timeout--;
01562       if (res == IKS_HOOK) 
01563          ast_log(LOG_WARNING, "JABBER: Got hook event.\n");
01564       else if (res == IKS_NET_TLSFAIL)
01565          ast_log(LOG_WARNING, "JABBER:  Failure in TLS.\n");
01566       else if (client->timeout == 0 && client->state == AJI_CONNECTED) {
01567          res = client->keepalive ? iks_send_raw(client->p, " ") : IKS_OK;
01568          if(res == IKS_OK)
01569             client->timeout = 50;
01570          else
01571             ast_log(LOG_WARNING, "JABBER:  Network Timeout\n");
01572       } else if (res == IKS_NET_RWERR)
01573          ast_log(LOG_WARNING, "JABBER: socket read error\n");
01574    } while (client);
01575    ASTOBJ_UNREF(client, aji_client_destroy);
01576    return 0;
01577 }
01578 
01579 /*!
01580  * \brief increments the mid field for messages and other events.
01581  * \param message id.
01582  * \return void.
01583  */
01584 void ast_aji_increment_mid(char *mid)
01585 {
01586    int i = 0;
01587 
01588    for (i = strlen(mid) - 1; i >= 0; i--) {
01589       if (mid[i] != 'z') {
01590          mid[i] = mid[i] + 1;
01591          i = 0;
01592       } else
01593          mid[i] = 'a';
01594    }
01595 }
01596 
01597 
01598 /*!
01599  * \brief attempts to register to a transport.
01600  * \param aji_client struct, and xml packet.
01601  * \return IKS_FILTER_EAT.
01602  */
01603 /*allows for registering to transport , was too sketch and is out for now. */
01604 /*static int aji_register_transport(void *data, ikspak *pak)
01605 {
01606    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01607    int res = 0;
01608    struct aji_buddy *buddy = NULL;
01609    iks *send = iks_make_iq(IKS_TYPE_GET, "jabber:iq:register");
01610 
01611    if (client && send) {
01612       ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
01613          ASTOBJ_RDLOCK(iterator); 
01614          if (iterator->btype == AJI_TRANS) {
01615               buddy = iterator;
01616          }
01617          ASTOBJ_UNLOCK(iterator);
01618       });
01619       iks_filter_remove_hook(client->f, aji_register_transport);
01620       iks_filter_add_rule(client->f, aji_register_transport2, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_NS, IKS_NS_REGISTER, IKS_RULE_DONE);
01621       iks_insert_attrib(send, "to", buddy->host);
01622       iks_insert_attrib(send, "id", client->mid);
01623       ast_aji_increment_mid(client->mid);
01624       iks_insert_attrib(send, "from", client->user);
01625       res = iks_send(client->p, send);
01626    } else 
01627       ast_log(LOG_ERROR, "Out of memory.\n");
01628 
01629    if (send)
01630       iks_delete(send);
01631    ASTOBJ_UNREF(client, aji_client_destroy);
01632    return IKS_FILTER_EAT;
01633 
01634 }
01635 */
01636 /*!
01637  * \brief attempts to register to a transport step 2.
01638  * \param aji_client struct, and xml packet.
01639  * \return IKS_FILTER_EAT.
01640  */
01641 /* more of the same blob of code, too wonky for now*/
01642 /* static int aji_register_transport2(void *data, ikspak *pak)
01643 {
01644    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01645    int res = 0;
01646    struct aji_buddy *buddy = NULL;
01647 
01648    iks *regiq = iks_new("iq");
01649    iks *regquery = iks_new("query");
01650    iks *reguser = iks_new("username");
01651    iks *regpass = iks_new("password");
01652 
01653    if (client && regquery && reguser && regpass && regiq) {
01654       ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
01655          ASTOBJ_RDLOCK(iterator);
01656          if (iterator->btype == AJI_TRANS)
01657             buddy = iterator; ASTOBJ_UNLOCK(iterator);
01658       });
01659       iks_filter_remove_hook(client->f, aji_register_transport2);
01660       iks_insert_attrib(regiq, "to", buddy->host);
01661       iks_insert_attrib(regiq, "type", "set");
01662       iks_insert_attrib(regiq, "id", client->mid);
01663       ast_aji_increment_mid(client->mid);
01664       iks_insert_attrib(regiq, "from", client->user);
01665       iks_insert_attrib(regquery, "xmlns", "jabber:iq:register");
01666       iks_insert_cdata(reguser, buddy->user, 0);
01667       iks_insert_cdata(regpass, buddy->pass, 0);
01668       iks_insert_node(regiq, regquery);
01669       iks_insert_node(regquery, reguser);
01670       iks_insert_node(regquery, regpass);
01671       res = iks_send(client->p, regiq);
01672    } else
01673       ast_log(LOG_ERROR, "Out of memory.\n");
01674    if (regiq)
01675       iks_delete(regiq);
01676    if (regquery)
01677       iks_delete(regquery);
01678    if (reguser)
01679       iks_delete(reguser);
01680    if (regpass)
01681       iks_delete(regpass);
01682    ASTOBJ_UNREF(client, aji_client_destroy);
01683    return IKS_FILTER_EAT;
01684 }
01685 */
01686 /*!
01687  * \brief goes through roster and prunes users not needed in list, or adds them accordingly.
01688  * \param aji_client struct.
01689  * \return void.
01690  */
01691 static void aji_pruneregister(struct aji_client *client)
01692 {
01693    int res = 0;
01694    iks *removeiq = iks_new("iq");
01695    iks *removequery = iks_new("query");
01696    iks *removeitem = iks_new("item");
01697    iks *send = iks_make_iq(IKS_TYPE_GET, "http://jabber.org/protocol/disco#items");
01698 
01699    if (client && removeiq && removequery && removeitem && send) {
01700       iks_insert_node(removeiq, removequery);
01701       iks_insert_node(removequery, removeitem);
01702       ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
01703          ASTOBJ_RDLOCK(iterator);
01704          /* For an aji_buddy, both AUTOPRUNE and AUTOREGISTER will never
01705           * be called at the same time */
01706          if (ast_test_flag(iterator, AJI_AUTOPRUNE)) {
01707             res = iks_send(client->p, iks_make_s10n(IKS_TYPE_UNSUBSCRIBE, iterator->name,
01708                   "GoodBye your status is no longer needed by Asterisk the Open Source PBX"
01709                   " so I am no longer subscribing to your presence.\n"));
01710             res = iks_send(client->p, iks_make_s10n(IKS_TYPE_UNSUBSCRIBED, iterator->name,
01711                   "GoodBye you are no longer in the asterisk config file so I am removing"
01712                   " your access to my presence.\n"));
01713             iks_insert_attrib(removeiq, "from", client->jid->full); 
01714             iks_insert_attrib(removeiq, "type", "set"); 
01715             iks_insert_attrib(removequery, "xmlns", "jabber:iq:roster");
01716             iks_insert_attrib(removeitem, "jid", iterator->name);
01717             iks_insert_attrib(removeitem, "subscription", "remove");
01718             res = iks_send(client->p, removeiq);
01719          } else if (ast_test_flag(iterator, AJI_AUTOREGISTER)) {
01720             res = iks_send(client->p, iks_make_s10n(IKS_TYPE_SUBSCRIBE, iterator->name, 
01721                   "Greetings I am the Asterisk Open Source PBX and I want to subscribe to your presence\n"));
01722             ast_clear_flag(iterator, AJI_AUTOREGISTER);
01723          }
01724          ASTOBJ_UNLOCK(iterator);
01725       });
01726    } else
01727       ast_log(LOG_ERROR, "Out of memory.\n");
01728    if (removeiq)
01729       iks_delete(removeiq);
01730    if (removequery)
01731       iks_delete(removequery);
01732    if (removeitem)
01733       iks_delete(removeitem);
01734    if (send)
01735       iks_delete(send);
01736    ASTOBJ_CONTAINER_PRUNE_MARKED(&client->buddies, aji_buddy_destroy);
01737 }
01738 
01739 /*!
01740  * \brief filters the roster packet we get back from server.
01741  * \param aji_client struct, and xml packet.
01742  * \return IKS_FILTER_EAT.
01743  */
01744 static int aji_filter_roster(void *data, ikspak *pak)
01745 {
01746    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01747    int flag = 0;
01748    iks *x = NULL;
01749    struct aji_buddy *buddy;
01750    
01751    client->state = AJI_CONNECTED;
01752    ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
01753       ASTOBJ_RDLOCK(iterator);
01754       x = iks_child(pak->query);
01755       flag = 0;
01756       while (x) {
01757          if (!iks_strcmp(iks_name(x), "item")) {
01758             if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid"))) {
01759                flag = 1;
01760                ast_clear_flag(iterator, AJI_AUTOPRUNE | AJI_AUTOREGISTER);
01761             }
01762          }
01763          x = iks_next(x);
01764       }
01765       if (!flag)
01766          ast_copy_flags(iterator, client, AJI_AUTOREGISTER);
01767       if (x)
01768          iks_delete(x);
01769       ASTOBJ_UNLOCK(iterator);
01770    });
01771 
01772    x = iks_child(pak->query);
01773    while (x) {
01774       flag = 0;
01775       if (iks_strcmp(iks_name(x), "item") == 0) {
01776          ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
01777             ASTOBJ_RDLOCK(iterator);
01778             if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid")))
01779                flag = 1;
01780             ASTOBJ_UNLOCK(iterator);
01781          });
01782 
01783          if (!flag) {
01784             buddy = (struct aji_buddy *) malloc(sizeof(struct aji_buddy));
01785             if (!buddy) {
01786                ast_log(LOG_WARNING, "Out of memory\n");
01787                return 0;
01788             }
01789             memset(buddy, 0, sizeof(struct aji_buddy));
01790             ASTOBJ_INIT(buddy);
01791             ASTOBJ_WRLOCK(buddy);
01792             ast_copy_string(buddy->name, iks_find_attrib(x, "jid"), sizeof(buddy->name));
01793             ast_clear_flag(buddy, AST_FLAGS_ALL);
01794             if(ast_test_flag(client, AJI_AUTOPRUNE)) {
01795                ast_set_flag(buddy, AJI_AUTOPRUNE);
01796                buddy->objflags |= ASTOBJ_FLAG_MARKED;
01797             } else
01798                ast_set_flag(buddy, AJI_AUTOREGISTER);
01799             ASTOBJ_UNLOCK(buddy);
01800             if (buddy) {
01801                ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
01802                ASTOBJ_UNREF(buddy, aji_buddy_destroy);
01803             }
01804          }
01805       }
01806       x = iks_next(x);
01807    }
01808    if (x)
01809       iks_delete(x);
01810    aji_pruneregister(client);
01811 
01812    ASTOBJ_UNREF(client, aji_client_destroy);
01813    return IKS_FILTER_EAT;
01814 }
01815 
01816 static int aji_reconnect(struct aji_client *client)
01817 {
01818    int res = 0;
01819 
01820    if (client->state)
01821       client->state = AJI_DISCONNECTED;
01822    client->timeout=50;
01823    if (client->p)
01824       iks_parser_reset(client->p);
01825    if (client->authorized)
01826       client->authorized = 0;
01827 
01828    if(client->component)
01829       res = aji_component_initialize(client);
01830    else
01831       res = aji_client_initialize(client);
01832 
01833    return res;
01834 }
01835 
01836 static int aji_get_roster(struct aji_client *client)
01837 {
01838    iks *roster = NULL;
01839    roster = iks_make_iq(IKS_TYPE_GET, IKS_NS_ROSTER);
01840    if(roster) {
01841       iks_insert_attrib(roster, "id", "roster");
01842       aji_set_presence(client, NULL, client->jid->full, 1, client->statusmessage);
01843       iks_send(client->p, roster);
01844    }
01845    if (roster)
01846       iks_delete(roster);
01847    return 1;
01848 }
01849 
01850 /*!
01851  * \brief connects as a client to jabber server.
01852  * \param aji_client struct, and xml packet.
01853  * \return res.
01854  */
01855 static int aji_client_connect(void *data, ikspak *pak)
01856 {
01857    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01858    int res = IKS_FILTER_PASS;
01859 
01860    if (client) {
01861       if (client->state == AJI_DISCONNECTED) {
01862          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);
01863          client->state = AJI_CONNECTING;
01864          client->jid = (iks_find_cdata(pak->query, "jid")) ? iks_id_new(client->stack, iks_find_cdata(pak->query, "jid")) : client->jid;
01865          if (!client->component) { /*client*/
01866             aji_get_roster(client);
01867          }
01868          iks_filter_remove_hook(client->f, aji_client_connect);
01869          /* Once we remove the hook for this routine, we must return EAT or we will crash or corrupt memory */
01870          res = IKS_FILTER_EAT;
01871       }
01872    } else
01873       ast_log(LOG_ERROR, "Out of memory.\n");
01874 
01875    ASTOBJ_UNREF(client, aji_client_destroy);
01876    return res;
01877 }
01878 
01879 /*!
01880  * \brief prepares client for connect.
01881  * \param aji_client struct.
01882  * \return 1.
01883  */
01884 static int aji_client_initialize(struct aji_client *client)
01885 {
01886    int connected = 0;
01887 
01888    connected = iks_connect_via(client->p, S_OR(client->serverhost, client->jid->server), client->port, client->jid->server);
01889 
01890    if (connected == IKS_NET_NOCONN) {
01891       ast_log(LOG_ERROR, "JABBER ERROR: No Connection\n");
01892       return IKS_HOOK;
01893    } else   if (connected == IKS_NET_NODNS) {
01894       ast_log(LOG_ERROR, "JABBER ERROR: No DNS %s for client to  %s\n", client->name, S_OR(client->serverhost, client->jid->server));
01895       return IKS_HOOK;
01896    } else
01897       iks_recv(client->p, 30);
01898    return IKS_OK;
01899 }
01900 
01901 /*!
01902  * \brief prepares component for connect.
01903  * \param aji_client struct.
01904  * \return 1.
01905  */
01906 static int aji_component_initialize(struct aji_client *client)
01907 {
01908    int connected = 1;
01909 
01910    connected = iks_connect_via(client->p, S_OR(client->serverhost, client->jid->server), client->port, client->user);
01911    if (connected == IKS_NET_NOCONN) {
01912       ast_log(LOG_ERROR, "JABBER ERROR: No Connection\n");
01913       return IKS_HOOK;
01914    } else if (connected == IKS_NET_NODNS) {
01915       ast_log(LOG_ERROR, "JABBER ERROR: No DNS %s for client to  %s\n", client->name, S_OR(client->serverhost, client->jid->server));
01916       return IKS_HOOK;
01917    } else if (!connected) 
01918       iks_recv(client->p, 30);
01919    return IKS_OK;
01920 }
01921 
01922 /*!
01923  * \brief disconnect from jabber server.
01924  * \param aji_client struct.
01925  * \return 1.
01926  */
01927 int ast_aji_disconnect(struct aji_client *client)
01928 {
01929    if (client) {
01930       if (option_verbose > 3)
01931          ast_verbose(VERBOSE_PREFIX_3 "JABBER: Disconnecting\n");
01932       iks_disconnect(client->p);
01933       iks_parser_delete(client->p);
01934       ASTOBJ_UNREF(client, aji_client_destroy);
01935    }
01936 
01937    return 1;
01938 }
01939 
01940 /*!
01941  * \brief set presence of client.
01942  * \param aji_client struct, user to send it to, and from, level, description.
01943  * \return void.
01944  */
01945 static void aji_set_presence(struct aji_client *client, char *to, char *from, int level, char *desc)
01946 {
01947    int res = 0;
01948    iks *presence = iks_make_pres(level, desc);
01949    iks *cnode = iks_new("c");
01950    iks *priority = iks_new("priority");
01951 
01952    iks_insert_cdata(priority, "0", 1);
01953    if (presence && cnode && client) {
01954       if(to)
01955          iks_insert_attrib(presence, "to", to);
01956       if(from)
01957          iks_insert_attrib(presence, "from", from);
01958       iks_insert_attrib(cnode, "node", "http://www.asterisk.org/xmpp/client/caps");
01959       iks_insert_attrib(cnode, "ver", "asterisk-xmpp");
01960       iks_insert_attrib(cnode, "ext", "voice-v1");
01961       iks_insert_attrib(cnode, "xmlns", "http://jabber.org/protocol/caps");
01962       iks_insert_node(presence, cnode);
01963       res = iks_send(client->p, presence);
01964    } else
01965       ast_log(LOG_ERROR, "Out of memory.\n");
01966    if (cnode)
01967       iks_delete(cnode);
01968    if (presence)
01969       iks_delete(presence);
01970 }
01971 
01972 /*!
01973  * \brief turnon console debugging.
01974  * \param fd, number of args, args.
01975  * \return RESULT_SUCCESS.
01976  */
01977 static int aji_do_debug(int fd, int argc, char *argv[])
01978 {
01979    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
01980       ASTOBJ_RDLOCK(iterator); 
01981       iterator->debug = 1;
01982       ASTOBJ_UNLOCK(iterator);
01983    });
01984    ast_cli(fd, "Jabber Debugging Enabled.\n");
01985    return RESULT_SUCCESS;
01986 }
01987 
01988 /*!
01989  * \brief reload jabber module.
01990  * \param fd, number of args, args.
01991  * \return RESULT_SUCCESS.
01992  */
01993 static int aji_do_reload(int fd, int argc, char *argv[])
01994 {
01995    aji_reload();
01996    ast_cli(fd, "Jabber Reloaded.\n");
01997    return RESULT_SUCCESS;
01998 }
01999 
02000 /*!
02001  * \brief turnoff console debugging.
02002  * \param fd, number of args, args.
02003  * \return RESULT_SUCCESS.
02004  */
02005 static int aji_no_debug(int fd, int argc, char *argv[])
02006 {
02007    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02008       ASTOBJ_RDLOCK(iterator);
02009       iterator->debug = 0;
02010       ASTOBJ_UNLOCK(iterator);
02011    });
02012    ast_cli(fd, "Jabber Debugging Disabled.\n");
02013    return RESULT_SUCCESS;
02014 }
02015 
02016 /*!
02017  * \brief show client status.
02018  * \param fd, number of args, args.
02019  * \return RESULT_SUCCESS.
02020  */
02021 static int aji_show_clients(int fd, int argc, char *argv[])
02022 {
02023    char *status;
02024    int count = 0;
02025    ast_cli(fd, "Jabber Users and their status:\n");
02026    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02027       ASTOBJ_RDLOCK(iterator);
02028       count++;
02029       switch (iterator->state) {
02030       case AJI_DISCONNECTED:
02031          status = "Disconnected";
02032          break;
02033       case AJI_CONNECTING:
02034          status = "Connecting";
02035          break;
02036       case AJI_CONNECTED:
02037          status = "Connected";
02038          break;
02039       default:
02040          status = "Unknown";
02041       }
02042       ast_cli(fd, "       User: %s     - %s\n", iterator->user, status);
02043       ASTOBJ_UNLOCK(iterator);
02044    });
02045    ast_cli(fd, "----\n");
02046    ast_cli(fd, "   Number of users: %d\n", count);
02047    return RESULT_SUCCESS;
02048 }
02049 
02050 /*!
02051  * \brief send test message for debugging.
02052  * \param fd, number of args, args.
02053  * \return RESULT_SUCCESS.
02054  */
02055 static int aji_test(int fd, int argc, char *argv[])
02056 {
02057    struct aji_client *client;
02058    struct aji_resource *resource;
02059    const char *name = "asterisk";
02060    struct aji_message *tmp;
02061 
02062    if (argc > 3)
02063       return RESULT_SHOWUSAGE;
02064    else if (argc == 3)
02065       name = argv[2];
02066 
02067    if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
02068       ast_cli(fd, "Unable to find client '%s'!\n", name);
02069       return RESULT_FAILURE;
02070    }
02071 
02072    /* XXX Does Matt really want everyone to use his personal address for tests? */ /* XXX yes he does */
02073    ast_aji_send(client, "mogorman@astjab.org", "blahblah");
02074    ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02075       ASTOBJ_RDLOCK(iterator);
02076       ast_verbose("User: %s\n", iterator->name);
02077       for (resource = iterator->resources; resource; resource = resource->next) {
02078          ast_verbose("Resource: %s\n", resource->resource);
02079          if(resource->cap) {
02080             ast_verbose("   client: %s\n", resource->cap->parent->node);
02081             ast_verbose("   version: %s\n", resource->cap->version);
02082             ast_verbose("   Jingle Capable: %d\n", resource->cap->jingle);
02083          }
02084          ast_verbose("  Priority: %d\n", resource->priority);
02085          ast_verbose("  Status: %d\n", resource->status); 
02086          ast_verbose("  Message: %s\n", S_OR(resource->description,"")); 
02087       }
02088       ASTOBJ_UNLOCK(iterator);
02089    });
02090    ast_verbose("\nOooh a working message stack!\n");
02091    AST_LIST_LOCK(&client->messages);
02092    AST_LIST_TRAVERSE(&client->messages, tmp, list) {
02093       ast_verbose("  Message from: %s with id %s @ %s %s\n",tmp->from, S_OR(tmp->id,""), ctime(&tmp->arrived), S_OR(tmp->message, ""));
02094    }
02095    AST_LIST_UNLOCK(&client->messages);
02096    ASTOBJ_UNREF(client, aji_client_destroy);
02097 
02098    return RESULT_SUCCESS;
02099 }
02100 
02101 /*!
02102  * \brief creates aji_client structure.
02103  * \param label, ast_variable, debug, pruneregister, component/client, aji_client to dump into. 
02104  * \return 0.
02105  */
02106 static int aji_create_client(char *label, struct ast_variable *var, int debug)
02107 {
02108    char *resource;
02109    struct aji_client *client = NULL;
02110    int flag = 0;
02111 
02112    client = ASTOBJ_CONTAINER_FIND(&clients,label);
02113    if (!client) {
02114       flag = 1;
02115       client = (struct aji_client *) malloc(sizeof(struct aji_client));
02116       if (!client) {
02117          ast_log(LOG_ERROR, "Out of memory!\n");
02118          return 0;
02119       }
02120       memset(client, 0, sizeof(struct aji_client));
02121       ASTOBJ_INIT(client);
02122       ASTOBJ_WRLOCK(client);
02123       ASTOBJ_CONTAINER_INIT(&client->buddies);
02124    } else {
02125       ASTOBJ_WRLOCK(client);
02126       ASTOBJ_UNMARK(client);
02127    }
02128    ASTOBJ_CONTAINER_MARKALL(&client->buddies);
02129    ast_copy_string(client->name, label, sizeof(client->name));
02130    ast_copy_string(client->mid, "aaaaa", sizeof(client->mid));
02131 
02132    /* Set default values for the client object */
02133    client->debug = debug;
02134    ast_copy_flags(client, &globalflags, AST_FLAGS_ALL);
02135    client->port = 5222;
02136    client->usetls = 1;
02137    client->usesasl = 1;
02138    client->forcessl = 0;
02139    client->keepalive = 1;
02140    client->timeout = 50;
02141    client->message_timeout = 100;
02142    AST_LIST_HEAD_INIT(&client->messages);
02143    client->component = 0;
02144    ast_copy_string(client->statusmessage, "Online and Available", sizeof(client->statusmessage));
02145 
02146    if (flag) {
02147       client->authorized = 0;
02148       client->state = AJI_DISCONNECTED;
02149    }
02150    while (var) {
02151       if (!strcasecmp(var->name, "username"))
02152          ast_copy_string(client->user, var->value, sizeof(client->user));
02153       else if (!strcasecmp(var->name, "serverhost"))
02154          ast_copy_string(client->serverhost, var->value, sizeof(client->serverhost));
02155       else if (!strcasecmp(var->name, "secret"))
02156          ast_copy_string(client->password, var->value, sizeof(client->password));
02157       else if (!strcasecmp(var->name, "statusmessage"))
02158          ast_copy_string(client->statusmessage, var->value, sizeof(client->statusmessage));
02159       else if (!strcasecmp(var->name, "port"))
02160          client->port = atoi(var->value);
02161       else if (!strcasecmp(var->name, "timeout"))
02162          client->message_timeout = atoi(var->value);
02163       else if (!strcasecmp(var->name, "debug"))
02164          client->debug = (ast_false(var->value)) ? 0 : 1;
02165       else if (!strcasecmp(var->name, "type")) {
02166          if (!strcasecmp(var->value, "component"))
02167             client->component = 1;
02168       } else if (!strcasecmp(var->name, "usetls")) {
02169          client->usetls = (ast_false(var->value)) ? 0 : 1;
02170       } else if (!strcasecmp(var->name, "usesasl")) {
02171          client->usesasl = (ast_false(var->value)) ? 0 : 1;
02172       } else if (!strcasecmp(var->name, "forceoldssl"))
02173          client->forcessl = (ast_false(var->value)) ? 0 : 1;
02174       else if (!strcasecmp(var->name, "keepalive"))
02175          client->keepalive = (ast_false(var->value)) ? 0 : 1;
02176       else if (!strcasecmp(var->name, "autoprune"))
02177          ast_set2_flag(client, ast_true(var->value), AJI_AUTOPRUNE);
02178       else if (!strcasecmp(var->name, "autoregister"))
02179          ast_set2_flag(client, ast_true(var->value), AJI_AUTOREGISTER);
02180       else if (!strcasecmp(var->name, "buddy"))
02181             aji_create_buddy(var->value, client);
02182    /* no transport support in this version */
02183    /* else if (!strcasecmp(var->name, "transport"))
02184             aji_create_transport(var->value, client);
02185    */
02186       var = var->next;
02187    }
02188    if (!flag) {
02189       ASTOBJ_UNLOCK(client);
02190       ASTOBJ_UNREF(client, aji_client_destroy);
02191       return 1;
02192    }
02193    client->p = iks_stream_new(((client->component) ? "jabber:component:accept" : "jabber:client"), client, aji_act_hook);
02194    if (!client->p) {
02195       ast_log(LOG_ERROR, "Failed to create stream for client '%s'!\n", client->name);
02196       return 0;
02197    }
02198    client->stack = iks_stack_new(8192, 8192);
02199    if (!client->stack) {
02200       ast_log(LOG_ERROR, "Failed to allocate stack for client '%s'\n", client->name);
02201       return 0;
02202    }
02203    client->f = iks_filter_new();
02204    if (!client->f) {
02205       ast_log(LOG_ERROR, "Failed to create filter for client '%s'\n", client->name);
02206       return 0;
02207    }
02208    if (!strchr(client->user, '/') && !client->component) { /*client */
02209       resource = NULL;
02210       if (asprintf(&resource, "%s/asterisk", client->user) > 0) {
02211          client->jid = iks_id_new(client->stack, resource);
02212          free(resource);
02213       }
02214    } else
02215       client->jid = iks_id_new(client->stack, client->user);
02216    if (client->component) {
02217       iks_filter_add_rule(client->f, aji_dinfo_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
02218       iks_filter_add_rule(client->f, aji_ditems_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#items", IKS_RULE_DONE);
02219       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);
02220       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);
02221    } else {
02222       iks_filter_add_rule(client->f, aji_client_info_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
02223    }
02224    if (!strchr(client->user, '/') && !client->component) { /*client */
02225       resource = NULL;
02226       if (asprintf(&resource, "%s/asterisk", client->user) > 0) {
02227          client->jid = iks_id_new(client->stack, resource);
02228          free(resource);
02229       }
02230    } else
02231       client->jid = iks_id_new(client->stack, client->user);
02232    iks_set_log_hook(client->p, aji_log_hook);
02233    ASTOBJ_UNLOCK(client);
02234    ASTOBJ_CONTAINER_LINK(&clients,client);
02235    return 1;
02236 }
02237 
02238 /*!
02239  * \brief creates transport.
02240  * \param label, buddy to dump it into. 
02241  * \return 0.
02242  */
02243 /* no connecting to transports today */
02244 /*
02245 static int aji_create_transport(char *label, struct aji_client *client)
02246 {
02247    char *server = NULL, *buddyname = NULL, *user = NULL, *pass = NULL;
02248    struct aji_buddy *buddy = NULL;
02249 
02250    buddy = ASTOBJ_CONTAINER_FIND(&client->buddies,label);
02251    if (!buddy) {
02252       buddy = malloc(sizeof(struct aji_buddy));
02253       if(!buddy) {
02254          ast_log(LOG_WARNING, "Out of memory\n");
02255          return 0;
02256       }
02257       memset(buddy, 0, sizeof(struct aji_buddy));
02258       ASTOBJ_INIT(buddy);
02259    }
02260    ASTOBJ_WRLOCK(buddy);
02261    server = label;
02262    if ((buddyname = strchr(label, ','))) {
02263       *buddyname = '\0';
02264       buddyname++;
02265       if (buddyname && buddyname[0] != '\0') {
02266          if ((user = strchr(buddyname, ','))) {
02267             *user = '\0';
02268             user++;
02269             if (user && user[0] != '\0') {
02270                if ((pass = strchr(user, ','))) {
02271                   *pass = '\0';
02272                   pass++;
02273                   ast_copy_string(buddy->pass, pass, sizeof(buddy->pass));
02274                   ast_copy_string(buddy->user, user, sizeof(buddy->user));
02275                   ast_copy_string(buddy->name, buddyname, sizeof(buddy->name));
02276                   ast_copy_string(buddy->server, server, sizeof(buddy->server));
02277                   return 1;
02278                }
02279             }
02280          }
02281       }
02282    }
02283    ASTOBJ_UNLOCK(buddy);
02284    ASTOBJ_UNMARK(buddy);
02285    ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
02286    return 0;
02287 }
02288 */
02289 
02290 /*!
02291  * \brief creates buddy.
02292  * \param label, buddy to dump it into. 
02293  * \return 0.
02294  */
02295 static int aji_create_buddy(char *label, struct aji_client *client)
02296 {
02297    struct aji_buddy *buddy = NULL;
02298    int flag = 0;
02299    buddy = ASTOBJ_CONTAINER_FIND(&client->buddies,label);
02300    if (!buddy) {
02301       flag = 1;
02302       buddy = malloc(sizeof(struct aji_buddy));
02303       if(!buddy) {
02304          ast_log(LOG_WARNING, "Out of memory\n");
02305          return 0;
02306       }
02307       memset(buddy, 0, sizeof(struct aji_buddy));
02308       ASTOBJ_INIT(buddy);
02309    }
02310    ASTOBJ_WRLOCK(buddy);
02311    ast_copy_string(buddy->name, label, sizeof(buddy->name));
02312    ASTOBJ_UNLOCK(buddy);
02313    if(flag)
02314       ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
02315    else {
02316       ASTOBJ_UNMARK(buddy);
02317       ASTOBJ_UNREF(buddy, aji_buddy_destroy);
02318    }
02319    return 1;
02320 }
02321 
02322 /*!
02323  * \brief load config file.
02324  * \param void. 
02325  * \return 1.
02326  */
02327 static int aji_load_config(void)
02328 {
02329    char *cat = NULL;
02330    int debug = 0;
02331    struct ast_config *cfg = NULL;
02332    struct ast_variable *var = NULL;
02333 
02334    cfg = ast_config_load(JABBER_CONFIG);
02335    if (!cfg) {
02336       ast_log(LOG_WARNING, "No such configuration file %s\n", JABBER_CONFIG);
02337       return 0;
02338    }
02339 
02340    cat = ast_category_browse(cfg, NULL);
02341    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
02342       if (!strcasecmp(var->name, "debug"))
02343          debug = (ast_false(ast_variable_retrieve(cfg, "general", "debug"))) ? 0 : 1;
02344       else if (!strcasecmp(var->name, "autoprune"))
02345          ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOPRUNE);
02346       else if (!strcasecmp(var->name, "autoregister"))
02347          ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOREGISTER);
02348    }
02349 
02350    while (cat) {
02351       if (strcasecmp(cat, "general")) {
02352             var = ast_variable_browse(cfg, cat);
02353             aji_create_client(cat, var, debug);
02354       }
02355       cat = ast_category_browse(cfg, cat);
02356    }
02357    ast_config_destroy(cfg); /* or leak memory */
02358    return 1;
02359 }
02360 
02361 /*!
02362   * \brief grab a aji_client structure by label name or JID 
02363   * (without the resource string)
02364   * \param name label or JID 
02365   * \return aji_client.
02366  */
02367 struct aji_client *ast_aji_get_client(const char *name)
02368 {
02369    struct aji_client *client = NULL;
02370    char *aux = NULL;
02371 
02372    client = ASTOBJ_CONTAINER_FIND(&clients, name);
02373    if (!client && strchr(name, '@')) {
02374       ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02375          aux = ast_strdupa(iterator->user);
02376          if (strchr(aux, '/')) {
02377             /* strip resource for comparison */
02378             aux = strsep(&aux, "/");
02379          }
02380          if (!strncasecmp(aux, name, strlen(aux))) {
02381             client = iterator;
02382          }           
02383       });
02384    }
02385  
02386    return client;
02387 }
02388 
02389 struct aji_client_container *ast_aji_get_clients(void)
02390 {
02391    return &clients;
02392 }
02393 
02394 static char mandescr_jabber_send[] =
02395 "Description: Sends a message to a Jabber Client.\n"
02396 "Variables: \n"
02397 "  Jabber:  Client or transport Asterisk uses to connect to JABBER.\n"
02398 "  ScreenName: User Name to message.\n"
02399 "  Message: Message to be sent to the buddy\n";
02400 
02401 /*! \brief  Send a Jabber Message via call from the Manager */
02402 static int manager_jabber_send(struct mansession *s, const struct message *m)
02403 {
02404    struct aji_client *client = NULL;
02405    const char *id = astman_get_header(m,"ActionID");
02406    const char *jabber = astman_get_header(m,"Jabber");
02407    const char *screenname = astman_get_header(m,"ScreenName");
02408    const char *message = astman_get_header(m,"Message");
02409 
02410    if (ast_strlen_zero(jabber)) {
02411       astman_send_error(s, m, "No transport specified");
02412       return 0;
02413    }
02414    if (ast_strlen_zero(screenname)) {
02415       astman_send_error(s, m, "No ScreenName specified");
02416       return 0;
02417    }
02418    if (ast_strlen_zero(message)) {
02419       astman_send_error(s, m, "No Message specified");
02420       return 0;
02421    }
02422 
02423    astman_send_ack(s, m, "Attempting to send Jabber Message");
02424    client = ast_aji_get_client(jabber);
02425    if (!client) {
02426       astman_send_error(s, m, "Could not find Sender");
02427       return 0;
02428    }  
02429    if (strchr(screenname, '@') && message) {
02430       ast_aji_send(client, screenname, message);
02431       astman_append(s, "Response: Success\r\n");
02432    } else {
02433       astman_append(s, "Response: Failure\r\n");
02434    }
02435    if (!ast_strlen_zero(id)) {
02436       astman_append(s, "ActionID: %s\r\n", id);
02437    }
02438    astman_append(s, "\r\n");
02439    return 0;
02440 }
02441 
02442 
02443 static int aji_reload()
02444 {
02445    ASTOBJ_CONTAINER_MARKALL(&clients);
02446    if (!aji_load_config()) {
02447       ast_log(LOG_ERROR, "JABBER: Failed to load config.\n");
02448       return 0;
02449    }
02450    ASTOBJ_CONTAINER_PRUNE_MARKED(&clients, aji_client_destroy);
02451    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02452       ASTOBJ_RDLOCK(iterator);
02453       if(iterator->state == AJI_DISCONNECTED) {
02454          if (!iterator->thread)
02455             ast_pthread_create_background(&iterator->thread, NULL, aji_recv_loop, iterator);
02456       } else if (iterator->state == AJI_CONNECTING)
02457          aji_get_roster(iterator);
02458       ASTOBJ_UNLOCK(iterator);
02459    });
02460    
02461    return 1;
02462 }
02463 
02464 static int unload_module(void)
02465 {
02466 
02467    /* Check if TLS is initialized. If that's the case, we can't unload this
02468       module due to a bug in the iksemel library that will cause a crash or
02469       a deadlock. We're trying to find a way to handle this, but in the meantime
02470       we will simply refuse to die... 
02471     */
02472    if (tls_initialized) {
02473       ast_log(LOG_ERROR, "Module can't be unloaded due to a bug in the Iksemel library when using TLS.\n");
02474       return 1;   /* You need a forced unload to get rid of this module */
02475    }
02476 
02477    ast_cli_unregister_multiple(aji_cli, sizeof(aji_cli) / sizeof(struct ast_cli_entry));
02478    ast_unregister_application(app_ajisend);
02479    ast_unregister_application(app_ajistatus);
02480    ast_manager_unregister("JabberSend");
02481    
02482    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02483       ASTOBJ_RDLOCK(iterator);
02484       if (option_debug > 2)
02485          ast_log(LOG_DEBUG, "JABBER: Releasing and disconneing client: %s\n", iterator->name);
02486       iterator->state = AJI_DISCONNECTING;
02487       ast_aji_disconnect(iterator);
02488       pthread_join(iterator->thread, NULL);
02489       ASTOBJ_UNLOCK(iterator);
02490    });
02491 
02492    ASTOBJ_CONTAINER_DESTROYALL(&clients, aji_client_destroy);
02493    ASTOBJ_CONTAINER_DESTROY(&clients);
02494    return 0;
02495 }
02496 
02497 static int load_module(void)
02498 {
02499    ASTOBJ_CONTAINER_INIT(&clients);
02500    if(!aji_reload())
02501       return AST_MODULE_LOAD_DECLINE;
02502    ast_manager_register2("JabberSend", EVENT_FLAG_SYSTEM, manager_jabber_send,
02503          "Sends a message to a Jabber Client", mandescr_jabber_send);
02504    ast_register_application(app_ajisend, aji_send_exec, ajisend_synopsis, ajisend_descrip);
02505    ast_register_application(app_ajistatus, aji_status_exec, ajistatus_synopsis, ajistatus_descrip);
02506    ast_cli_register_multiple(aji_cli, sizeof(aji_cli) / sizeof(struct ast_cli_entry));
02507 
02508    return 0;
02509 }
02510 
02511 static int reload(void)
02512 {
02513    aji_reload();
02514    return 0;
02515 }
02516 
02517 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "AJI - Asterisk Jabber Interface",
02518       .load = load_module,
02519       .unload = unload_module,
02520       .reload = reload,
02521           );

Generated on Sat Aug 6 00:39:31 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7