Mon Jul 14 17:25:00 2008

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: 120675 $")
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             asprintf(&handshake, "<handshake>%s</handshake>", shasum);
00633             if (handshake) {
00634                iks_send_raw(client->p, handshake);
00635                free(handshake);
00636                handshake = NULL;
00637             }
00638             client->state = AJI_CONNECTING;
00639             if(iks_recv(client->p,1) == 2) /*XXX proper result for iksemel library on iks_recv of <handshake/> XXX*/
00640                client->state = AJI_CONNECTED;
00641             else
00642                ast_log(LOG_WARNING,"Jabber didn't seem to handshake, failed to authenicate.\n");
00643             break;
00644          }
00645          break;
00646 
00647       case IKS_NODE_NORMAL:
00648          break;
00649 
00650       case IKS_NODE_ERROR:
00651          ast_log(LOG_ERROR, "JABBER: Node Error\n");
00652          ASTOBJ_UNREF(client, aji_client_destroy);
00653          return IKS_HOOK;
00654 
00655       case IKS_NODE_STOP:
00656          ast_log(LOG_WARNING, "JABBER: Disconnected\n");
00657          ASTOBJ_UNREF(client, aji_client_destroy);
00658          return IKS_HOOK;
00659       }
00660    }
00661 
00662    switch (pak->type) {
00663    case IKS_PAK_NONE:
00664       if (option_debug)
00665          ast_log(LOG_DEBUG, "JABBER: I Don't know what to do with you NONE\n");
00666       break;
00667    case IKS_PAK_MESSAGE:
00668       aji_handle_message(client, pak);
00669       if (option_debug)
00670          ast_log(LOG_DEBUG, "JABBER: I Don't know what to do with you MESSAGE\n");
00671       break;
00672    case IKS_PAK_PRESENCE:
00673       aji_handle_presence(client, pak);
00674       if (option_debug)
00675          ast_log(LOG_DEBUG, "JABBER: I Do know how to handle presence!!\n");
00676       break;
00677    case IKS_PAK_S10N:
00678       aji_handle_subscribe(client, pak);
00679       if (option_debug)
00680          ast_log(LOG_DEBUG, "JABBER: I Dont know S10N subscribe!!\n");
00681       break;
00682    case IKS_PAK_IQ:
00683       if (option_debug)
00684          ast_log(LOG_DEBUG, "JABBER: I Dont have an IQ!!!\n");
00685       aji_handle_iq(client, node);
00686       break;
00687    default:
00688       if (option_debug)
00689          ast_log(LOG_DEBUG, "JABBER: I Dont know %i\n", pak->type);
00690       break;
00691    }
00692    
00693    iks_filter_packet(client->f, pak);
00694 
00695    if (node)
00696       iks_delete(node);
00697 
00698    ASTOBJ_UNREF(client, aji_client_destroy);
00699    return IKS_OK;
00700 }
00701 
00702 static int aji_register_approve_handler(void *data, ikspak *pak)
00703 {
00704    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00705    iks *iq = NULL, *presence = NULL, *x = NULL;
00706 
00707    iq = iks_new("iq");
00708    presence = iks_new("presence");
00709    x = iks_new("x");
00710    if (client && iq && presence && x) {
00711       if (!iks_find(pak->query, "remove")) {
00712          iks_insert_attrib(iq, "from", client->jid->full);
00713          iks_insert_attrib(iq, "to", pak->from->full);
00714          iks_insert_attrib(iq, "id", pak->id);
00715          iks_insert_attrib(iq, "type", "result");
00716          iks_send(client->p, iq);
00717 
00718          iks_insert_attrib(presence, "from", client->jid->full);
00719          iks_insert_attrib(presence, "to", pak->from->partial);
00720          iks_insert_attrib(presence, "id", client->mid);
00721          ast_aji_increment_mid(client->mid);
00722          iks_insert_attrib(presence, "type", "subscribe");
00723          iks_insert_attrib(x, "xmlns", "vcard-temp:x:update");
00724          iks_insert_node(presence, x);
00725          iks_send(client->p, presence); 
00726       }
00727    } else {
00728       ast_log(LOG_ERROR, "Out of memory.\n");
00729    }
00730 
00731    if (iq)
00732       iks_delete(iq);
00733    if(presence)
00734       iks_delete(presence);
00735    if (x)
00736       iks_delete(x);
00737    ASTOBJ_UNREF(client, aji_client_destroy);
00738    return IKS_FILTER_EAT;
00739 }
00740 
00741 static int aji_register_query_handler(void *data, ikspak *pak)
00742 {
00743    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00744    struct aji_buddy *buddy = NULL; 
00745    char *node = NULL;
00746 
00747    client = (struct aji_client *) data;
00748 
00749    buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
00750    if (!buddy) {
00751       iks *iq = NULL, *query = NULL, *error = NULL, *notacceptable = NULL;
00752       ast_verbose("Someone.... %s tried to register but they aren't allowed\n", pak->from->partial);
00753       iq = iks_new("iq");
00754       query = iks_new("query");
00755       error = iks_new("error");
00756       notacceptable = iks_new("not-acceptable");
00757       if(iq && query && error && notacceptable) {
00758          iks_insert_attrib(iq, "type", "error");
00759          iks_insert_attrib(iq, "from", client->user);
00760          iks_insert_attrib(iq, "to", pak->from->full);
00761          iks_insert_attrib(iq, "id", pak->id);
00762          iks_insert_attrib(query, "xmlns", "jabber:iq:register");
00763          iks_insert_attrib(error, "code" , "406");
00764          iks_insert_attrib(error, "type", "modify");
00765          iks_insert_attrib(notacceptable, "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas");
00766          iks_insert_node(iq, query);
00767          iks_insert_node(iq, error);
00768          iks_insert_node(error, notacceptable);
00769          iks_send(client->p, iq);
00770       } else {
00771          ast_log(LOG_ERROR, "Out of memory.\n");
00772       }
00773       if (iq)
00774          iks_delete(iq);
00775       if (query)
00776          iks_delete(query);
00777       if (error)
00778          iks_delete(error);
00779       if (notacceptable)
00780          iks_delete(notacceptable);
00781    } else   if (!(node = iks_find_attrib(pak->query, "node"))) {
00782       iks *iq = NULL, *query = NULL, *instructions = NULL;
00783       char *explain = "Welcome to Asterisk - the Open Source PBX.\n";
00784       iq = iks_new("iq");
00785       query = iks_new("query");
00786       instructions = iks_new("instructions");
00787       if (iq && query && instructions && client) {
00788          iks_insert_attrib(iq, "from", client->user);
00789          iks_insert_attrib(iq, "to", pak->from->full);
00790          iks_insert_attrib(iq, "id", pak->id);
00791          iks_insert_attrib(iq, "type", "result");
00792          iks_insert_attrib(query, "xmlns", "jabber:iq:register");
00793          iks_insert_cdata(instructions, explain, 0);
00794          iks_insert_node(iq, query);
00795          iks_insert_node(query, instructions);
00796          iks_send(client->p, iq);
00797       } else {
00798          ast_log(LOG_ERROR, "Out of memory.\n");
00799       }
00800       if (iq)
00801          iks_delete(iq);
00802       if (query)
00803          iks_delete(query);
00804       if (instructions)
00805          iks_delete(instructions);
00806    }
00807    ASTOBJ_UNREF(client, aji_client_destroy);
00808    return IKS_FILTER_EAT;
00809 }
00810 
00811 static int aji_ditems_handler(void *data, ikspak *pak)
00812 {
00813    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00814    char *node = NULL;
00815 
00816    if (!(node = iks_find_attrib(pak->query, "node"))) {
00817       iks *iq = NULL, *query = NULL, *item = NULL;
00818       iq = iks_new("iq");
00819       query = iks_new("query");
00820       item = iks_new("item");
00821 
00822       if (iq && query && item) {
00823          iks_insert_attrib(iq, "from", client->user);
00824          iks_insert_attrib(iq, "to", pak->from->full);
00825          iks_insert_attrib(iq, "id", pak->id);
00826          iks_insert_attrib(iq, "type", "result");
00827          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
00828          iks_insert_attrib(item, "node", "http://jabber.org/protocol/commands");
00829          iks_insert_attrib(item, "name", "Million Dollar Asterisk Commands");
00830          iks_insert_attrib(item, "jid", client->user);
00831 
00832          iks_insert_node(iq, query);
00833          iks_insert_node(query, item);
00834          iks_send(client->p, iq);
00835       } else {
00836          ast_log(LOG_ERROR, "Out of memory.\n");
00837       }
00838       if (iq)
00839          iks_delete(iq);
00840       if (query)
00841          iks_delete(query);
00842       if (item)
00843          iks_delete(item);
00844 
00845    } else if (!strcasecmp(node, "http://jabber.org/protocol/commands")) {
00846       iks *iq, *query, *confirm;
00847       iq = iks_new("iq");
00848       query = iks_new("query");
00849       confirm = iks_new("item");
00850       if (iq && query && confirm && client) {
00851          iks_insert_attrib(iq, "from", client->user);
00852          iks_insert_attrib(iq, "to", pak->from->full);
00853          iks_insert_attrib(iq, "id", pak->id);
00854          iks_insert_attrib(iq, "type", "result");
00855          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
00856          iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
00857          iks_insert_attrib(confirm, "node", "confirmaccount");
00858          iks_insert_attrib(confirm, "name", "Confirm AIM account");
00859          iks_insert_attrib(confirm, "jid", "blog.astjab.org");
00860 
00861          iks_insert_node(iq, query);
00862          iks_insert_node(query, confirm);
00863          iks_send(client->p, iq);
00864       } else {
00865          ast_log(LOG_ERROR, "Out of memory.\n");
00866       }
00867       if (iq)
00868          iks_delete(iq);
00869       if (query)
00870          iks_delete(query);
00871       if (confirm)
00872          iks_delete(confirm);
00873 
00874    } else if (!strcasecmp(node, "confirmaccount")) {
00875       iks *iq = NULL, *query = NULL, *feature = NULL;
00876 
00877       iq = iks_new("iq");
00878       query = iks_new("query");
00879       feature = iks_new("feature");
00880 
00881       if (iq && query && feature && client) {
00882          iks_insert_attrib(iq, "from", client->user);
00883          iks_insert_attrib(iq, "to", pak->from->full);
00884          iks_insert_attrib(iq, "id", pak->id);
00885          iks_insert_attrib(iq, "type", "result");
00886          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
00887          iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
00888          iks_insert_node(iq, query);
00889          iks_insert_node(query, feature);
00890          iks_send(client->p, iq);
00891       } else {
00892          ast_log(LOG_ERROR, "Out of memory.\n");
00893       }
00894       if (iq)
00895          iks_delete(iq);
00896       if (query)
00897          iks_delete(query);
00898       if (feature)
00899          iks_delete(feature);
00900    }
00901 
00902    ASTOBJ_UNREF(client, aji_client_destroy);
00903    return IKS_FILTER_EAT;
00904 
00905 }
00906 
00907 static int aji_client_info_handler(void *data, ikspak *pak)
00908 {
00909    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00910    struct aji_resource *resource = NULL;
00911    struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
00912 
00913    resource = aji_find_resource(buddy, pak->from->resource);
00914    if (pak->subtype == IKS_TYPE_RESULT) {
00915       if (!resource) {
00916          ast_log(LOG_NOTICE,"JABBER: Received client info from %s when not requested.\n", pak->from->full);
00917          ASTOBJ_UNREF(client, aji_client_destroy);
00918          return IKS_FILTER_EAT;
00919       }
00920       if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
00921          resource->cap->jingle = 1;
00922       } else
00923          resource->cap->jingle = 0;
00924    } else if (pak->subtype == IKS_TYPE_GET) {
00925       iks *iq, *disco, *ident, *google, *query;
00926       iq = iks_new("iq");
00927       query = iks_new("query");
00928       ident = iks_new("identity");
00929       disco = iks_new("feature");
00930       google = iks_new("feature");
00931       if (iq && ident && disco && google) {
00932          iks_insert_attrib(iq, "from", client->jid->full);
00933          iks_insert_attrib(iq, "to", pak->from->full);
00934          iks_insert_attrib(iq, "type", "result");
00935          iks_insert_attrib(iq, "id", pak->id);
00936          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
00937          iks_insert_attrib(ident, "category", "client");
00938          iks_insert_attrib(ident, "type", "pc");
00939          iks_insert_attrib(ident, "name", "asterisk");
00940          iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco#info");
00941          iks_insert_attrib(google, "var", "http://www.google.com/xmpp/protocol/voice/v1");
00942          iks_insert_node(iq, query);
00943          iks_insert_node(query, ident);
00944          iks_insert_node(query, google);
00945          iks_insert_node(query, disco);
00946          iks_send(client->p, iq);
00947       } else
00948          ast_log(LOG_ERROR, "Out of Memory.\n");
00949       if (iq)
00950          iks_delete(iq);
00951       if (query)
00952          iks_delete(query);
00953       if (ident)
00954          iks_delete(ident);
00955       if (google)
00956          iks_delete(google);
00957       if (disco)
00958          iks_delete(disco);
00959    } else if (pak->subtype == IKS_TYPE_ERROR) {
00960       ast_log(LOG_NOTICE, "User %s does not support discovery.\n", pak->from->full);
00961    }
00962    ASTOBJ_UNREF(client, aji_client_destroy);
00963    return IKS_FILTER_EAT;
00964 }
00965 
00966 static int aji_dinfo_handler(void *data, ikspak *pak)
00967 {
00968    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00969    char *node = NULL;
00970    struct aji_resource *resource = NULL;
00971    struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
00972 
00973    resource = aji_find_resource(buddy, pak->from->resource);
00974    if (pak->subtype == IKS_TYPE_ERROR) {
00975       ast_log(LOG_WARNING, "Recieved error from a client, turn on jabber debug!\n");
00976       return IKS_FILTER_EAT;
00977    }
00978    if (pak->subtype == IKS_TYPE_RESULT) {
00979       if (!resource) {
00980          ast_log(LOG_NOTICE,"JABBER: Received client info from %s when not requested.\n", pak->from->full);
00981          ASTOBJ_UNREF(client, aji_client_destroy);
00982          return IKS_FILTER_EAT;
00983       }
00984       if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
00985          resource->cap->jingle = 1;
00986       } else
00987          resource->cap->jingle = 0;
00988    } else if (pak->subtype == IKS_TYPE_GET && !(node = iks_find_attrib(pak->query, "node"))) {
00989       iks *iq, *query, *identity, *disco, *reg, *commands, *gateway, *version, *vcard, *search;
00990 
00991       iq = iks_new("iq");
00992       query = iks_new("query");
00993       identity = iks_new("identity");
00994       disco = iks_new("feature");
00995       reg = iks_new("feature");
00996       commands = iks_new("feature");
00997       gateway = iks_new("feature");
00998       version = iks_new("feature");
00999       vcard = iks_new("feature");
01000       search = iks_new("feature");
01001 
01002       if (iq && query && identity && disco && reg && commands && gateway && version && vcard && search && client) {
01003          iks_insert_attrib(iq, "from", client->user);
01004          iks_insert_attrib(iq, "to", pak->from->full);
01005          iks_insert_attrib(iq, "id", pak->id);
01006          iks_insert_attrib(iq, "type", "result");
01007          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01008          iks_insert_attrib(identity, "category", "gateway");
01009          iks_insert_attrib(identity, "type", "pstn");
01010          iks_insert_attrib(identity, "name", "Asterisk The Open Source PBX");
01011          iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco");
01012          iks_insert_attrib(reg, "var", "jabber:iq:register");
01013          iks_insert_attrib(commands, "var", "http://jabber.org/protocol/commands");
01014          iks_insert_attrib(gateway, "var", "jabber:iq:gateway");
01015          iks_insert_attrib(version, "var", "jabber:iq:version");
01016          iks_insert_attrib(vcard, "var", "vcard-temp");
01017          iks_insert_attrib(search, "var", "jabber:iq:search");
01018 
01019          iks_insert_node(iq, query);
01020          iks_insert_node(query, identity);
01021          iks_insert_node(query, disco);
01022          iks_insert_node(query, reg);
01023          iks_insert_node(query, commands);
01024          iks_insert_node(query, gateway);
01025          iks_insert_node(query, version);
01026          iks_insert_node(query, vcard);
01027          iks_insert_node(query, search);
01028          iks_send(client->p, iq);
01029       } else {
01030          ast_log(LOG_ERROR, "Out of memory.\n");
01031       }
01032 
01033       if (iq)
01034          iks_delete(iq);
01035       if (query)
01036          iks_delete(query);
01037       if (identity)
01038          iks_delete(identity);
01039       if (disco)
01040          iks_delete(disco);
01041       if (reg)
01042          iks_delete(reg);
01043       if (commands)
01044          iks_delete(commands);
01045       if (gateway)
01046          iks_delete(gateway);
01047       if (version)
01048          iks_delete(version);
01049       if (vcard)
01050          iks_delete(vcard);
01051       if (search)
01052          iks_delete(search);
01053 
01054    } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "http://jabber.org/protocol/commands")) {
01055       iks *iq, *query, *confirm;
01056       iq = iks_new("iq");
01057       query = iks_new("query");
01058       confirm = iks_new("item");
01059 
01060       if (iq && query && confirm && client) {
01061          iks_insert_attrib(iq, "from", client->user);
01062          iks_insert_attrib(iq, "to", pak->from->full);
01063          iks_insert_attrib(iq, "id", pak->id);
01064          iks_insert_attrib(iq, "type", "result");
01065          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01066          iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
01067          iks_insert_attrib(confirm, "node", "confirmaccount");
01068          iks_insert_attrib(confirm, "name", "Confirm AIM account");
01069          iks_insert_attrib(confirm, "jid", client->user);
01070          iks_insert_node(iq, query);
01071          iks_insert_node(query, confirm);
01072          iks_send(client->p, iq);
01073       } else {
01074          ast_log(LOG_ERROR, "Out of memory.\n");
01075       }
01076       if (iq)
01077          iks_delete(iq);
01078       if (query)
01079          iks_delete(query);
01080       if (confirm)
01081          iks_delete(confirm);
01082 
01083    } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "confirmaccount")) {
01084       iks *iq, *query, *feature;
01085 
01086       iq = iks_new("iq");
01087       query = iks_new("query");
01088       feature = iks_new("feature");
01089 
01090       if (iq && query && feature && client) {
01091          iks_insert_attrib(iq, "from", client->user);
01092          iks_insert_attrib(iq, "to", pak->from->full);
01093          iks_insert_attrib(iq, "id", pak->id);
01094          iks_insert_attrib(iq, "type", "result");
01095          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01096          iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
01097          iks_insert_node(iq, query);
01098          iks_insert_node(query, feature);
01099          iks_send(client->p, iq);
01100       } else {
01101          ast_log(LOG_ERROR, "Out of memory.\n");
01102       }
01103       if (iq)
01104          iks_delete(iq);
01105       if (query)
01106          iks_delete(query);
01107       if (feature)
01108          iks_delete(feature);
01109    }
01110 
01111    ASTOBJ_UNREF(client, aji_client_destroy);
01112    return IKS_FILTER_EAT;
01113 }
01114 
01115 /*!
01116  * \brief Handles <iq> tags.
01117  * \param client structure and the iq node.
01118  * \return void.
01119  */
01120 static void aji_handle_iq(struct aji_client *client, iks *node)
01121 {
01122    /*Nothing to see here */
01123 }
01124 
01125 /*!
01126  * \brief Handles presence packets.
01127  * \param client structure and the node.
01128  * \return void.
01129  */
01130 static void aji_handle_message(struct aji_client *client, ikspak *pak)
01131 {
01132    struct aji_message *insert, *tmp;
01133    int flag = 0;
01134    
01135    if (!(insert = ast_calloc(1, sizeof(struct aji_message))))
01136       return;
01137    time(&insert->arrived);
01138    if (iks_find_cdata(pak->x, "body"))
01139       insert->message = ast_strdup(iks_find_cdata(pak->x, "body"));
01140    if(pak->id)
01141       ast_copy_string(insert->id, pak->id, sizeof(insert->message));
01142    if (pak->from)
01143       insert->from = ast_strdup(pak->from->full);
01144    AST_LIST_LOCK(&client->messages);
01145    AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, tmp, list) {
01146       if (flag) {
01147          AST_LIST_REMOVE_CURRENT(&client->messages, list);
01148          if (tmp->from)
01149             free(tmp->from);
01150          if (tmp->message)
01151             free(tmp->message);
01152       } else if (difftime(time(NULL), tmp->arrived) >= client->message_timeout) {
01153          flag = 1;
01154          AST_LIST_REMOVE_CURRENT(&client->messages, list);
01155          if (tmp->from)
01156             free(tmp->from);
01157          if (tmp->message)
01158             free(tmp->message);
01159       }
01160    }
01161    AST_LIST_TRAVERSE_SAFE_END;
01162    AST_LIST_INSERT_HEAD(&client->messages, insert, list);
01163    AST_LIST_UNLOCK(&client->messages);
01164 }
01165 
01166 static void aji_handle_presence(struct aji_client *client, ikspak *pak)
01167 {
01168    int status, priority;
01169    struct aji_buddy *buddy;
01170    struct aji_resource *tmp = NULL, *last = NULL, *found = NULL;
01171    char *ver, *node, *descrip, *type;
01172    
01173    if(client->state != AJI_CONNECTED)
01174       aji_create_buddy(pak->from->partial, client);
01175 
01176    buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01177    if (!buddy && pak->from->partial) {
01178       /* allow our jid to be used to log in with another resource */
01179       if (!strcmp((const char *)pak->from->partial, (const char *)client->jid->partial))
01180          aji_create_buddy(pak->from->partial, client);
01181       else
01182          ast_log(LOG_NOTICE, "Got presence packet from %s, someone not in our roster!!!!\n", pak->from->partial);
01183       return;
01184    }
01185    type = iks_find_attrib(pak->x, "type");
01186    if(client->component && type &&!strcasecmp("probe", type)) {
01187       aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), 1, client->statusmessage);
01188       ast_verbose("what i was looking for \n");
01189    }
01190    ASTOBJ_WRLOCK(buddy);
01191    status = (pak->show) ? pak->show : 6;
01192    priority = atoi((iks_find_cdata(pak->x, "priority")) ? iks_find_cdata(pak->x, "priority") : "0");
01193    tmp = buddy->resources;
01194    descrip = ast_strdup(iks_find_cdata(pak->x,"status"));
01195 
01196    while (tmp && pak->from->resource) {
01197       if (!strcasecmp(tmp->resource, pak->from->resource)) {
01198          tmp->status = status;
01199          if (tmp->description) free(tmp->description);
01200          tmp->description = descrip;
01201          found = tmp;
01202          if (status == 6) {   /* Sign off Destroy resource */
01203             if (last && found->next) {
01204                last->next = found->next;
01205             } else if (!last) {
01206                if (found->next)
01207                   buddy->resources = found->next;
01208                else
01209                   buddy->resources = NULL;
01210             } else if (!found->next) {
01211                if (last)
01212                   last->next = NULL;
01213                else
01214                   buddy->resources = NULL;
01215             }
01216             free(found);
01217             found = NULL;
01218             break;
01219          }
01220          /* resource list is sorted by descending priority */
01221          if (tmp->priority != priority) {
01222             found->priority = priority;
01223             if (!last && !found->next)
01224                /* resource was found to be unique,
01225                   leave loop */
01226                break;
01227             /* search for resource in our list
01228                and take it out for the moment */
01229             if (last)
01230                last->next = found->next;
01231             else
01232                buddy->resources = found->next;
01233 
01234             last = NULL;
01235             tmp = buddy->resources;
01236             if (!buddy->resources)
01237                buddy->resources = found;
01238             /* priority processing */
01239             while (tmp) {
01240                /* insert resource back according to 
01241                   its priority value */
01242                if (found->priority > tmp->priority) {
01243                   if (last)
01244                      /* insert within list */
01245                      last->next = found;
01246                   found->next = tmp;
01247                   if (!last)
01248                      /* insert on top */
01249                      buddy->resources = found;
01250                   break;
01251                }
01252                if (!tmp->next) {
01253                   /* insert at the end of the list */
01254                   tmp->next = found;
01255                   found->next = NULL;
01256                   break;
01257                }
01258                last = tmp;
01259                tmp = tmp->next;
01260             }
01261          }
01262          break;
01263       }
01264       last = tmp;
01265       tmp = tmp->next;
01266    }
01267 
01268    /* resource not found in our list, create it */
01269    if (!found && status != 6 && pak->from->resource) {
01270       found = (struct aji_resource *) malloc(sizeof(struct aji_resource));
01271       memset(found, 0, sizeof(struct aji_resource));
01272 
01273       if (!found) {
01274          ast_log(LOG_ERROR, "Out of memory!\n");
01275          return;
01276       }
01277       ast_copy_string(found->resource, pak->from->resource, sizeof(found->resource));
01278       found->status = status;
01279       found->description = descrip;
01280       found->priority = priority;
01281       found->next = NULL;
01282       last = NULL;
01283       tmp = buddy->resources;
01284       while (tmp) {
01285          if (found->priority > tmp->priority) {
01286             if (last)
01287                last->next = found;
01288             found->next = tmp;
01289             if (!last)
01290                buddy->resources = found;
01291             break;
01292          }
01293          if (!tmp->next) {
01294             tmp->next = found;
01295             break;
01296          }
01297          last = tmp;
01298          tmp = tmp->next;
01299       }
01300       if (!tmp)
01301          buddy->resources = found;
01302    }
01303    
01304    ASTOBJ_UNLOCK(buddy);
01305    ASTOBJ_UNREF(buddy, aji_buddy_destroy);
01306 
01307    node = iks_find_attrib(iks_find(pak->x, "c"), "node");
01308    ver = iks_find_attrib(iks_find(pak->x, "c"), "ver");
01309 
01310    /* handle gmail client's special caps:c tag */
01311    if (!node && !ver) {
01312       node = iks_find_attrib(iks_find(pak->x, "caps:c"), "node");
01313       ver = iks_find_attrib(iks_find(pak->x, "caps:c"), "ver");
01314    }
01315 
01316    /* retrieve capabilites of the new resource */
01317    if(status !=6 && found && !found->cap) {
01318       found->cap = aji_find_version(node, ver, pak);
01319       if(gtalk_yuck(pak->x)) /* gtalk should do discover */
01320          found->cap->jingle = 1;
01321       if(found->cap->jingle && option_debug > 4)
01322          ast_log(LOG_DEBUG,"Special case for google till they support discover.\n");
01323       else {
01324          iks *iq, *query;
01325          iq = iks_new("iq");
01326          query = iks_new("query");
01327          if(query && iq)  {
01328             iks_insert_attrib(iq, "type", "get");
01329             iks_insert_attrib(iq, "to", pak->from->full);
01330             iks_insert_attrib(iq,"from", client->jid->full);
01331             iks_insert_attrib(iq, "id", client->mid);
01332             ast_aji_increment_mid(client->mid);
01333             iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01334             iks_insert_node(iq, query);
01335             iks_send(client->p, iq);
01336             
01337          } else
01338             ast_log(LOG_ERROR, "Out of memory.\n");
01339          if(query)
01340             iks_delete(query);
01341          if(iq)
01342             iks_delete(iq);
01343       }
01344    }
01345    if (option_verbose > 4) {
01346       switch (pak->subtype) {
01347       case IKS_TYPE_AVAILABLE:
01348          ast_verbose(VERBOSE_PREFIX_3 "JABBER: I am available ^_* %i\n", pak->subtype);
01349          break;
01350       case IKS_TYPE_UNAVAILABLE:
01351          ast_verbose(VERBOSE_PREFIX_3 "JABBER: I am unavailable ^_* %i\n", pak->subtype);
01352          break;
01353       default:
01354          ast_verbose(VERBOSE_PREFIX_3 "JABBER: Ohh sexy and the wrong type: %i\n", pak->subtype);
01355       }
01356       switch (pak->show) {
01357       case IKS_SHOW_UNAVAILABLE:
01358          ast_verbose(VERBOSE_PREFIX_3 "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01359          break;
01360       case IKS_SHOW_AVAILABLE:
01361          ast_verbose(VERBOSE_PREFIX_3 "JABBER: type is available\n");
01362          break;
01363       case IKS_SHOW_CHAT:
01364          ast_verbose(VERBOSE_PREFIX_3 "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01365          break;
01366       case IKS_SHOW_AWAY:
01367          ast_verbose(VERBOSE_PREFIX_3 "JABBER: type is away\n");
01368          break;
01369       case IKS_SHOW_XA:
01370          ast_verbose(VERBOSE_PREFIX_3 "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01371          break;
01372       case IKS_SHOW_DND:
01373          ast_verbose(VERBOSE_PREFIX_3 "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01374          break;
01375       default:
01376          ast_verbose(VERBOSE_PREFIX_3 "JABBER: Kinky! how did that happen %i\n", pak->show);
01377       }
01378    }
01379 }
01380 
01381 /*!
01382  * \brief handles subscription requests.
01383  * \param aji_client struct and xml packet.
01384  * \return void.
01385  */
01386 static void aji_handle_subscribe(struct aji_client *client, ikspak *pak)
01387 {
01388    iks *presence = NULL, *status = NULL;
01389    struct aji_buddy* buddy = NULL;
01390 
01391    switch (pak->subtype) { 
01392    case IKS_TYPE_SUBSCRIBE:
01393       presence = iks_new("presence");
01394       status = iks_new("status");
01395       if(presence && status) {
01396          iks_insert_attrib(presence, "type", "subscribed");
01397          iks_insert_attrib(presence, "to", pak->from->full);
01398          iks_insert_attrib(presence, "from", client->jid->full);
01399          if(pak->id)
01400             iks_insert_attrib(presence, "id", pak->id);
01401          iks_insert_cdata(status, "Asterisk has approved subscription", 0);
01402          iks_insert_node(presence, status);
01403          iks_send(client->p, presence);
01404       } else
01405          ast_log(LOG_ERROR, "Unable to allocate nodes\n");
01406       if(presence)
01407          iks_delete(presence);
01408       if(status)
01409          iks_delete(status);
01410       if(client->component)
01411          aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), 1, client->statusmessage);
01412    case IKS_TYPE_SUBSCRIBED:
01413       buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01414       if (!buddy && pak->from->partial) {
01415          aji_create_buddy(pak->from->partial, client);
01416       }
01417    default:
01418       if (option_verbose > 4) {
01419          ast_verbose(VERBOSE_PREFIX_3 "JABBER: This is a subcription of type %i\n", pak->subtype);
01420       }
01421    }
01422 }
01423 
01424 /*!
01425  * \brief sends messages.
01426  * \param aji_client struct , reciever, message.
01427  * \return 1.
01428  */
01429 int ast_aji_send(struct aji_client *client, const char *address, const char *message)
01430 {
01431    int res = 0;
01432    iks *message_packet = NULL;
01433    if (client->state == AJI_CONNECTED) {
01434       message_packet = iks_make_msg(IKS_TYPE_CHAT, address, message);
01435       if (message_packet) {
01436          iks_insert_attrib(message_packet, "from", client->jid->full);
01437          res = iks_send(client->p, message_packet);
01438       } else {
01439          ast_log(LOG_ERROR, "Out of memory.\n");
01440       }
01441       if (message_packet)
01442          iks_delete(message_packet);
01443    } else
01444       ast_log(LOG_WARNING, "JABBER: Not connected can't send\n");
01445    return 1;
01446 }
01447 
01448 /*!
01449  * \brief create a chatroom.
01450  * \param aji_client struct , room, server, topic for the room.
01451  * \return 0.
01452  */
01453 int ast_aji_create_chat(struct aji_client *client, char *room, char *server, char *topic)
01454 {
01455    int res = 0;
01456    iks *iq = NULL;
01457    iq = iks_new("iq");
01458 
01459    if (iq && client) {
01460       iks_insert_attrib(iq, "type", "get");
01461       iks_insert_attrib(iq, "to", server);
01462       iks_insert_attrib(iq, "id", client->mid);
01463       ast_aji_increment_mid(client->mid);
01464       iks_send(client->p, iq);
01465    } else 
01466       ast_log(LOG_ERROR, "Out of memory.\n");
01467 
01468    iks_delete(iq);
01469 
01470    return res;
01471 }
01472 
01473 /*!
01474  * \brief join a chatroom.
01475  * \param aji_client struct , room.
01476  * \return res.
01477  */
01478 int ast_aji_join_chat(struct aji_client *client, char *room)
01479 {
01480    int res = 0;
01481    iks *presence = NULL, *priority = NULL;
01482    presence = iks_new("presence");
01483    priority = iks_new("priority");
01484    if (presence && priority && client) {
01485       iks_insert_cdata(priority, "0", 1);
01486       iks_insert_attrib(presence, "to", room);
01487       iks_insert_node(presence, priority);
01488       res = iks_send(client->p, presence);
01489       iks_insert_cdata(priority, "5", 1);
01490       iks_insert_attrib(presence, "to", room);
01491       res = iks_send(client->p, presence);
01492    } else 
01493       ast_log(LOG_ERROR, "Out of memory.\n");
01494    if (presence)
01495       iks_delete(presence);
01496    if (priority)
01497       iks_delete(priority);
01498    return res;
01499 }
01500 
01501 /*!
01502  * \brief invite to a chatroom.
01503  * \param aji_client struct ,user, room, message.
01504  * \return res.
01505  */
01506 int ast_aji_invite_chat(struct aji_client *client, char *user, char *room, char *message)
01507 {
01508    int res = 0;
01509    iks *invite, *body, *namespace;
01510 
01511    invite = iks_new("message");
01512    body = iks_new("body");
01513    namespace = iks_new("x");
01514    if (client && invite && body && namespace) {
01515       iks_insert_attrib(invite, "to", user);
01516       iks_insert_attrib(invite, "id", client->mid);
01517       ast_aji_increment_mid(client->mid);
01518       iks_insert_cdata(body, message, 0);
01519       iks_insert_attrib(namespace, "xmlns", "jabber:x:conference");
01520       iks_insert_attrib(namespace, "jid", room);
01521       iks_insert_node(invite, body);
01522       iks_insert_node(invite, namespace);
01523       res = iks_send(client->p, invite);
01524    } else 
01525       ast_log(LOG_ERROR, "Out of memory.\n");
01526    if (body)
01527       iks_delete(body);
01528    if (namespace)
01529       iks_delete(namespace);
01530    if (invite)
01531       iks_delete(invite);
01532    return res;
01533 }
01534 
01535 
01536 /*!
01537  * \brief receive message loop.
01538  * \param aji_client struct.
01539  * \return void.
01540  */
01541 static void *aji_recv_loop(void *data)
01542 {
01543    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01544    int res = IKS_HOOK;
01545    do {
01546       if (res != IKS_OK) {
01547          while(res != IKS_OK) {
01548             if(option_verbose > 3)
01549                ast_verbose("JABBER: reconnecting.\n");
01550             res = aji_reconnect(client);
01551             sleep(4);
01552          }
01553       }
01554 
01555       res = iks_recv(client->p, 1);
01556 
01557       if (client->state == AJI_DISCONNECTING) {
01558          if (option_debug > 1)
01559             ast_log(LOG_DEBUG, "Ending our Jabber client's thread due to a disconnect\n");
01560          pthread_exit(NULL);
01561       }
01562       client->timeout--;
01563       if (res == IKS_HOOK) 
01564          ast_log(LOG_WARNING, "JABBER: Got hook event.\n");
01565       else if (res == IKS_NET_TLSFAIL)
01566          ast_log(LOG_WARNING, "JABBER:  Failure in TLS.\n");
01567       else if (client->timeout == 0 && client->state == AJI_CONNECTED) {
01568          res = client->keepalive ? iks_send_raw(client->p, " ") : IKS_OK;
01569          if(res == IKS_OK)
01570             client->timeout = 50;
01571          else
01572             ast_log(LOG_WARNING, "JABBER:  Network Timeout\n");
01573       } else if (res == IKS_NET_RWERR)
01574          ast_log(LOG_WARNING, "JABBER: socket read error\n");
01575    } while (client);
01576    ASTOBJ_UNREF(client, aji_client_destroy);
01577    return 0;
01578 }
01579 
01580 /*!
01581  * \brief increments the mid field for messages and other events.
01582  * \param message id.
01583  * \return void.
01584  */
01585 void ast_aji_increment_mid(char *mid)
01586 {
01587    int i = 0;
01588 
01589    for (i = strlen(mid) - 1; i >= 0; i--) {
01590       if (mid[i] != 'z') {
01591          mid[i] = mid[i] + 1;
01592          i = 0;
01593       } else
01594          mid[i] = 'a';
01595    }
01596 }
01597 
01598 
01599 /*!
01600  * \brief attempts to register to a transport.
01601  * \param aji_client struct, and xml packet.
01602  * \return IKS_FILTER_EAT.
01603  */
01604 /*allows for registering to transport , was too sketch and is out for now. */
01605 /*static int aji_register_transport(void *data, ikspak *pak)
01606 {
01607    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01608    int res = 0;
01609    struct aji_buddy *buddy = NULL;
01610    iks *send = iks_make_iq(IKS_TYPE_GET, "jabber:iq:register");
01611 
01612    if (client && send) {
01613       ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
01614          ASTOBJ_RDLOCK(iterator); 
01615          if (iterator->btype == AJI_TRANS) {
01616               buddy = iterator;
01617          }
01618          ASTOBJ_UNLOCK(iterator);
01619       });
01620       iks_filter_remove_hook(client->f, aji_register_transport);
01621       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);
01622       iks_insert_attrib(send, "to", buddy->host);
01623       iks_insert_attrib(send, "id", client->mid);
01624       ast_aji_increment_mid(client->mid);
01625       iks_insert_attrib(send, "from", client->user);
01626       res = iks_send(client->p, send);
01627    } else 
01628       ast_log(LOG_ERROR, "Out of memory.\n");
01629 
01630    if (send)
01631       iks_delete(send);
01632    ASTOBJ_UNREF(client, aji_client_destroy);
01633    return IKS_FILTER_EAT;
01634 
01635 }
01636 */
01637 /*!
01638  * \brief attempts to register to a transport step 2.
01639  * \param aji_client struct, and xml packet.
01640  * \return IKS_FILTER_EAT.
01641  */
01642 /* more of the same blob of code, too wonky for now*/
01643 /* static int aji_register_transport2(void *data, ikspak *pak)
01644 {
01645    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01646    int res = 0;
01647    struct aji_buddy *buddy = NULL;
01648 
01649    iks *regiq = iks_new("iq");
01650    iks *regquery = iks_new("query");
01651    iks *reguser = iks_new("username");
01652    iks *regpass = iks_new("password");
01653 
01654    if (client && regquery && reguser && regpass && regiq) {
01655       ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
01656          ASTOBJ_RDLOCK(iterator);
01657          if (iterator->btype == AJI_TRANS)
01658             buddy = iterator; ASTOBJ_UNLOCK(iterator);
01659       });
01660       iks_filter_remove_hook(client->f, aji_register_transport2);
01661       iks_insert_attrib(regiq, "to", buddy->host);
01662       iks_insert_attrib(regiq, "type", "set");
01663       iks_insert_attrib(regiq, "id", client->mid);
01664       ast_aji_increment_mid(client->mid);
01665       iks_insert_attrib(regiq, "from", client->user);
01666       iks_insert_attrib(regquery, "xmlns", "jabber:iq:register");
01667       iks_insert_cdata(reguser, buddy->user, 0);
01668       iks_insert_cdata(regpass, buddy->pass, 0);
01669       iks_insert_node(regiq, regquery);
01670       iks_insert_node(regquery, reguser);
01671       iks_insert_node(regquery, regpass);
01672       res = iks_send(client->p, regiq);
01673    } else
01674       ast_log(LOG_ERROR, "Out of memory.\n");
01675    if (regiq)
01676       iks_delete(regiq);
01677    if (regquery)
01678       iks_delete(regquery);
01679    if (reguser)
01680       iks_delete(reguser);
01681    if (regpass)
01682       iks_delete(regpass);
01683    ASTOBJ_UNREF(client, aji_client_destroy);
01684    return IKS_FILTER_EAT;
01685 }
01686 */
01687 /*!
01688  * \brief goes through roster and prunes users not needed in list, or adds them accordingly.
01689  * \param aji_client struct.
01690  * \return void.
01691  */
01692 static void aji_pruneregister(struct aji_client *client)
01693 {
01694    int res = 0;
01695    iks *removeiq = iks_new("iq");
01696    iks *removequery = iks_new("query");
01697    iks *removeitem = iks_new("item");
01698    iks *send = iks_make_iq(IKS_TYPE_GET, "http://jabber.org/protocol/disco#items");
01699 
01700    if (client && removeiq && removequery && removeitem && send) {
01701       iks_insert_node(removeiq, removequery);
01702       iks_insert_node(removequery, removeitem);
01703       ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
01704          ASTOBJ_RDLOCK(iterator);
01705          /* For an aji_buddy, both AUTOPRUNE and AUTOREGISTER will never
01706           * be called at the same time */
01707          if (ast_test_flag(iterator, AJI_AUTOPRUNE)) {
01708             res = iks_send(client->p, iks_make_s10n(IKS_TYPE_UNSUBSCRIBE, iterator->name,
01709                   "GoodBye your status is no longer needed by Asterisk the Open Source PBX"
01710                   " so I am no longer subscribing to your presence.\n"));
01711             res = iks_send(client->p, iks_make_s10n(IKS_TYPE_UNSUBSCRIBED, iterator->name,
01712                   "GoodBye you are no longer in the asterisk config file so I am removing"
01713                   " your access to my presence.\n"));
01714             iks_insert_attrib(removeiq, "from", client->jid->full); 
01715             iks_insert_attrib(removeiq, "type", "set"); 
01716             iks_insert_attrib(removequery, "xmlns", "jabber:iq:roster");
01717             iks_insert_attrib(removeitem, "jid", iterator->name);
01718             iks_insert_attrib(removeitem, "subscription", "remove");
01719             res = iks_send(client->p, removeiq);
01720          } else if (ast_test_flag(iterator, AJI_AUTOREGISTER)) {
01721             res = iks_send(client->p, iks_make_s10n(IKS_TYPE_SUBSCRIBE, iterator->name, 
01722                   "Greetings I am the Asterisk Open Source PBX and I want to subscribe to your presence\n"));
01723             ast_clear_flag(iterator, AJI_AUTOREGISTER);
01724          }
01725          ASTOBJ_UNLOCK(iterator);
01726       });
01727    } else
01728       ast_log(LOG_ERROR, "Out of memory.\n");
01729    if (removeiq)
01730       iks_delete(removeiq);
01731    if (removequery)
01732       iks_delete(removequery);
01733    if (removeitem)
01734       iks_delete(removeitem);
01735    if (send)
01736       iks_delete(send);
01737    ASTOBJ_CONTAINER_PRUNE_MARKED(&client->buddies, aji_buddy_destroy);
01738 }
01739 
01740 /*!
01741  * \brief filters the roster packet we get back from server.
01742  * \param aji_client struct, and xml packet.
01743  * \return IKS_FILTER_EAT.
01744  */
01745 static int aji_filter_roster(void *data, ikspak *pak)
01746 {
01747    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01748    int flag = 0;
01749    iks *x = NULL;
01750    struct aji_buddy *buddy;
01751    
01752    client->state = AJI_CONNECTED;
01753    ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
01754       ASTOBJ_RDLOCK(iterator);
01755       x = iks_child(pak->query);
01756       flag = 0;
01757       while (x) {
01758          if (!iks_strcmp(iks_name(x), "item")) {
01759             if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid"))) {
01760                flag = 1;
01761                ast_clear_flag(iterator, AJI_AUTOPRUNE | AJI_AUTOREGISTER);
01762             }
01763          }
01764          x = iks_next(x);
01765       }
01766       if (!flag)
01767          ast_copy_flags(iterator, client, AJI_AUTOREGISTER);
01768       if (x)
01769          iks_delete(x);
01770       ASTOBJ_UNLOCK(iterator);
01771    });
01772 
01773    x = iks_child(pak->query);
01774    while (x) {
01775       flag = 0;
01776       if (iks_strcmp(iks_name(x), "item") == 0) {
01777          ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
01778             ASTOBJ_RDLOCK(iterator);
01779             if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid")))
01780                flag = 1;
01781             ASTOBJ_UNLOCK(iterator);
01782          });
01783 
01784          if (!flag) {
01785             buddy = (struct aji_buddy *) malloc(sizeof(struct aji_buddy));
01786             if (!buddy) {
01787                ast_log(LOG_WARNING, "Out of memory\n");
01788                return 0;
01789             }
01790             memset(buddy, 0, sizeof(struct aji_buddy));
01791             ASTOBJ_INIT(buddy);
01792             ASTOBJ_WRLOCK(buddy);
01793             ast_copy_string(buddy->name, iks_find_attrib(x, "jid"), sizeof(buddy->name));
01794             ast_clear_flag(buddy, AST_FLAGS_ALL);
01795             if(ast_test_flag(client, AJI_AUTOPRUNE)) {
01796                ast_set_flag(buddy, AJI_AUTOPRUNE);
01797                buddy->objflags |= ASTOBJ_FLAG_MARKED;
01798             } else
01799                ast_set_flag(buddy, AJI_AUTOREGISTER);
01800             ASTOBJ_UNLOCK(buddy);
01801             if (buddy) {
01802                ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
01803                ASTOBJ_UNREF(buddy, aji_buddy_destroy);
01804             }
01805          }
01806       }
01807       x = iks_next(x);
01808    }
01809    if (x)
01810       iks_delete(x);
01811    aji_pruneregister(client);
01812 
01813    ASTOBJ_UNREF(client, aji_client_destroy);
01814    return IKS_FILTER_EAT;
01815 }
01816 
01817 static int aji_reconnect(struct aji_client *client)
01818 {
01819    int res = 0;
01820 
01821    if (client->state)
01822       client->state = AJI_DISCONNECTED;
01823    client->timeout=50;
01824    if (client->p)
01825       iks_parser_reset(client->p);
01826    if (client->authorized)
01827       client->authorized = 0;
01828 
01829    if(client->component)
01830       res = aji_component_initialize(client);
01831    else
01832       res = aji_client_initialize(client);
01833 
01834    return res;
01835 }
01836 
01837 static int aji_get_roster(struct aji_client *client)
01838 {
01839    iks *roster = NULL;
01840    roster = iks_make_iq(IKS_TYPE_GET, IKS_NS_ROSTER);
01841    if(roster) {
01842       iks_insert_attrib(roster, "id", "roster");
01843       aji_set_presence(client, NULL, client->jid->full, 1, client->statusmessage);
01844       iks_send(client->p, roster);
01845    }
01846    if (roster)
01847       iks_delete(roster);
01848    return 1;
01849 }
01850 
01851 /*!
01852  * \brief connects as a client to jabber server.
01853  * \param aji_client struct, and xml packet.
01854  * \return res.
01855  */
01856 static int aji_client_connect(void *data, ikspak *pak)
01857 {
01858    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01859    int res = 0;
01860 
01861    if (client) {
01862       if (client->state == AJI_DISCONNECTED) {
01863          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);
01864          client->state = AJI_CONNECTING;
01865          client->jid = (iks_find_cdata(pak->query, "jid")) ? iks_id_new(client->stack, iks_find_cdata(pak->query, "jid")) : client->jid;
01866          iks_filter_remove_hook(client->f, aji_client_connect);
01867          if(!client->component) /*client*/
01868             aji_get_roster(client);
01869       }
01870    } else
01871       ast_log(LOG_ERROR, "Out of memory.\n");
01872 
01873    ASTOBJ_UNREF(client, aji_client_destroy);
01874    return res;
01875 }
01876 
01877 /*!
01878  * \brief prepares client for connect.
01879  * \param aji_client struct.
01880  * \return 1.
01881  */
01882 static int aji_client_initialize(struct aji_client *client)
01883 {
01884    int connected = 0;
01885 
01886    connected = iks_connect_via(client->p, S_OR(client->serverhost, client->jid->server), client->port, client->jid->server);
01887 
01888    if (connected == IKS_NET_NOCONN) {
01889       ast_log(LOG_ERROR, "JABBER ERROR: No Connection\n");
01890       return IKS_HOOK;
01891    } else   if (connected == IKS_NET_NODNS) {
01892       ast_log(LOG_ERROR, "JABBER ERROR: No DNS %s for client to  %s\n", client->name, S_OR(client->serverhost, client->jid->server));
01893       return IKS_HOOK;
01894    } else
01895       iks_recv(client->p, 30);
01896    return IKS_OK;
01897 }
01898 
01899 /*!
01900  * \brief prepares component for connect.
01901  * \param aji_client struct.
01902  * \return 1.
01903  */
01904 static int aji_component_initialize(struct aji_client *client)
01905 {
01906    int connected = 1;
01907 
01908    connected = iks_connect_via(client->p, S_OR(client->serverhost, client->jid->server), client->port, client->user);
01909    if (connected == IKS_NET_NOCONN) {
01910       ast_log(LOG_ERROR, "JABBER ERROR: No Connection\n");
01911       return IKS_HOOK;
01912    } else if (connected == IKS_NET_NODNS) {
01913       ast_log(LOG_ERROR, "JABBER ERROR: No DNS %s for client to  %s\n", client->name, S_OR(client->serverhost, client->jid->server));
01914       return IKS_HOOK;
01915    } else if (!connected) 
01916       iks_recv(client->p, 30);
01917    return IKS_OK;
01918 }
01919 
01920 /*!
01921  * \brief disconnect from jabber server.
01922  * \param aji_client struct.
01923  * \return 1.
01924  */
01925 int ast_aji_disconnect(struct aji_client *client)
01926 {
01927    if (client) {
01928       if (option_verbose > 3)
01929          ast_verbose(VERBOSE_PREFIX_3 "JABBER: Disconnecting\n");
01930       iks_disconnect(client->p);
01931       iks_parser_delete(client->p);
01932       ASTOBJ_UNREF(client, aji_client_destroy);
01933    }
01934 
01935    return 1;
01936 }
01937 
01938 /*!
01939  * \brief set presence of client.
01940  * \param aji_client struct, user to send it to, and from, level, description.
01941  * \return void.
01942  */
01943 static void aji_set_presence(struct aji_client *client, char *to, char *from, int level, char *desc)
01944 {
01945    int res = 0;
01946    iks *presence = iks_make_pres(level, desc);
01947    iks *cnode = iks_new("c");
01948    iks *priority = iks_new("priority");
01949 
01950    iks_insert_cdata(priority, "0", 1);
01951    if (presence && cnode && client) {
01952       if(to)
01953          iks_insert_attrib(presence, "to", to);
01954       if(from)
01955          iks_insert_attrib(presence, "from", from);
01956       iks_insert_attrib(cnode, "node", "http://www.asterisk.org/xmpp/client/caps");
01957       iks_insert_attrib(cnode, "ver", "asterisk-xmpp");
01958       iks_insert_attrib(cnode, "ext", "voice-v1");
01959       iks_insert_attrib(cnode, "xmlns", "http://jabber.org/protocol/caps");
01960       iks_insert_node(presence, cnode);
01961       res = iks_send(client->p, presence);
01962    } else
01963       ast_log(LOG_ERROR, "Out of memory.\n");
01964    if (cnode)
01965       iks_delete(cnode);
01966    if (presence)
01967       iks_delete(presence);
01968 }
01969 
01970 /*!
01971  * \brief turnon console debugging.
01972  * \param fd, number of args, args.
01973  * \return RESULT_SUCCESS.
01974  */
01975 static int aji_do_debug(int fd, int argc, char *argv[])
01976 {
01977    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
01978       ASTOBJ_RDLOCK(iterator); 
01979       iterator->debug = 1;
01980       ASTOBJ_UNLOCK(iterator);
01981    });
01982    ast_cli(fd, "Jabber Debugging Enabled.\n");
01983    return RESULT_SUCCESS;
01984 }
01985 
01986 /*!
01987  * \brief reload jabber module.
01988  * \param fd, number of args, args.
01989  * \return RESULT_SUCCESS.
01990  */
01991 static int aji_do_reload(int fd, int argc, char *argv[])
01992 {
01993    aji_reload();
01994    ast_cli(fd, "Jabber Reloaded.\n");
01995    return RESULT_SUCCESS;
01996 }
01997 
01998 /*!
01999  * \brief turnoff console debugging.
02000  * \param fd, number of args, args.
02001  * \return RESULT_SUCCESS.
02002  */
02003 static int aji_no_debug(int fd, int argc, char *argv[])
02004 {
02005    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02006       ASTOBJ_RDLOCK(iterator);
02007       iterator->debug = 0;
02008       ASTOBJ_UNLOCK(iterator);
02009    });
02010    ast_cli(fd, "Jabber Debugging Disabled.\n");
02011    return RESULT_SUCCESS;
02012 }
02013 
02014 /*!
02015  * \brief show client status.
02016  * \param fd, number of args, args.
02017  * \return RESULT_SUCCESS.
02018  */
02019 static int aji_show_clients(int fd, int argc, char *argv[])
02020 {
02021    char *status;
02022    int count = 0;
02023    ast_cli(fd, "Jabber Users and their status:\n");
02024    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02025       ASTOBJ_RDLOCK(iterator);
02026       count++;
02027       switch (iterator->state) {
02028       case AJI_DISCONNECTED:
02029          status = "Disconnected";
02030          break;
02031       case AJI_CONNECTING:
02032          status = "Connecting";
02033          break;
02034       case AJI_CONNECTED:
02035          status = "Connected";
02036          break;
02037       default:
02038          status = "Unknown";
02039       }
02040       ast_cli(fd, "       User: %s     - %s\n", iterator->user, status);
02041       ASTOBJ_UNLOCK(iterator);
02042    });
02043    ast_cli(fd, "----\n");
02044    ast_cli(fd, "   Number of users: %d\n", count);
02045    return RESULT_SUCCESS;
02046 }
02047 
02048 /*!
02049  * \brief send test message for debugging.
02050  * \param fd, number of args, args.
02051  * \return RESULT_SUCCESS.
02052  */
02053 static int aji_test(int fd, int argc, char *argv[])
02054 {
02055    struct aji_client *client;
02056    struct aji_resource *resource;
02057    const char *name = "asterisk";
02058    struct aji_message *tmp;
02059 
02060    if (argc > 3)
02061       return RESULT_SHOWUSAGE;
02062    else if (argc == 3)
02063       name = argv[2];
02064 
02065    if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
02066       ast_cli(fd, "Unable to find client '%s'!\n", name);
02067       return RESULT_FAILURE;
02068    }
02069 
02070    /* XXX Does Matt really want everyone to use his personal address for tests? */ /* XXX yes he does */
02071    ast_aji_send(client, "mogorman@astjab.org", "blahblah");
02072    ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02073       ASTOBJ_RDLOCK(iterator);
02074       ast_verbose("User: %s\n", iterator->name);
02075       for (resource = iterator->resources; resource; resource = resource->next) {
02076          ast_verbose("Resource: %s\n", resource->resource);
02077          if(resource->cap) {
02078             ast_verbose("   client: %s\n", resource->cap->parent->node);
02079             ast_verbose("   version: %s\n", resource->cap->version);
02080             ast_verbose("   Jingle Capable: %d\n", resource->cap->jingle);
02081          }
02082          ast_verbose("  Priority: %d\n", resource->priority);
02083          ast_verbose("  Status: %d\n", resource->status); 
02084          ast_verbose("  Message: %s\n", S_OR(resource->description,"")); 
02085       }
02086       ASTOBJ_UNLOCK(iterator);
02087    });
02088    ast_verbose("\nOooh a working message stack!\n");
02089    AST_LIST_LOCK(&client->messages);
02090    AST_LIST_TRAVERSE(&client->messages, tmp, list) {
02091       ast_verbose("  Message from: %s with id %s @ %s %s\n",tmp->from, S_OR(tmp->id,""), ctime(&tmp->arrived), S_OR(tmp->message, ""));
02092    }
02093    AST_LIST_UNLOCK(&client->messages);
02094    ASTOBJ_UNREF(client, aji_client_destroy);
02095 
02096    return RESULT_SUCCESS;
02097 }
02098 
02099 /*!
02100  * \brief creates aji_client structure.
02101  * \param label, ast_variable, debug, pruneregister, component/client, aji_client to dump into. 
02102  * \return 0.
02103  */
02104 static int aji_create_client(char *label, struct ast_variable *var, int debug)
02105 {
02106    char *resource;
02107    struct aji_client *client = NULL;
02108    int flag = 0;
02109 
02110    client = ASTOBJ_CONTAINER_FIND(&clients,label);
02111    if (!client) {
02112       flag = 1;
02113       client = (struct aji_client *) malloc(sizeof(struct aji_client));
02114       if (!client) {
02115          ast_log(LOG_ERROR, "Out of memory!\n");
02116          return 0;
02117       }
02118       memset(client, 0, sizeof(struct aji_client));
02119       ASTOBJ_INIT(client);
02120       ASTOBJ_WRLOCK(client);
02121       ASTOBJ_CONTAINER_INIT(&client->buddies);
02122    } else {
02123       ASTOBJ_WRLOCK(client);
02124       ASTOBJ_UNMARK(client);
02125    }
02126    ASTOBJ_CONTAINER_MARKALL(&client->buddies);
02127    ast_copy_string(client->name, label, sizeof(client->name));
02128    ast_copy_string(client->mid, "aaaaa", sizeof(client->mid));
02129 
02130    /* Set default values for the client object */
02131    client->debug = debug;
02132    ast_copy_flags(client, &globalflags, AST_FLAGS_ALL);
02133    client->port = 5222;
02134    client->usetls = 1;
02135    client->usesasl = 1;
02136    client->forcessl = 0;
02137    client->keepalive = 1;
02138    client->timeout = 50;
02139    client->message_timeout = 100;
02140    AST_LIST_HEAD_INIT(&client->messages);
02141    client->component = 0;
02142    ast_copy_string(client->statusmessage, "Online and Available", sizeof(client->statusmessage));
02143 
02144    if (flag) {
02145       client->authorized = 0;
02146       client->state = AJI_DISCONNECTED;
02147    }
02148    while (var) {
02149       if (!strcasecmp(var->name, "username"))
02150          ast_copy_string(client->user, var->value, sizeof(client->user));
02151       else if (!strcasecmp(var->name, "serverhost"))
02152          ast_copy_string(client->serverhost, var->value, sizeof(client->serverhost));
02153       else if (!strcasecmp(var->name, "secret"))
02154          ast_copy_string(client->password, var->value, sizeof(client->password));
02155       else if (!strcasecmp(var->name, "statusmessage"))
02156          ast_copy_string(client->statusmessage, var->value, sizeof(client->statusmessage));
02157       else if (!strcasecmp(var->name, "port"))
02158          client->port = atoi(var->value);
02159       else if (!strcasecmp(var->name, "timeout"))
02160          client->message_timeout = atoi(var->value);
02161       else if (!strcasecmp(var->name, "debug"))
02162          client->debug = (ast_false(var->value)) ? 0 : 1;
02163       else if (!strcasecmp(var->name, "type")) {
02164          if (!strcasecmp(var->value, "component"))
02165             client->component = 1;
02166       } else if (!strcasecmp(var->name, "usetls")) {
02167          client->usetls = (ast_false(var->value)) ? 0 : 1;
02168       } else if (!strcasecmp(var->name, "usesasl")) {
02169          client->usesasl = (ast_false(var->value)) ? 0 : 1;
02170       } else if (!strcasecmp(var->name, "forceoldssl"))
02171          client->forcessl = (ast_false(var->value)) ? 0 : 1;
02172       else if (!strcasecmp(var->name, "keepalive"))
02173          client->keepalive = (ast_false(var->value)) ? 0 : 1;
02174       else if (!strcasecmp(var->name, "autoprune"))
02175          ast_set2_flag(client, ast_true(var->value), AJI_AUTOPRUNE);
02176       else if (!strcasecmp(var->name, "autoregister"))
02177          ast_set2_flag(client, ast_true(var->value), AJI_AUTOREGISTER);
02178       else if (!strcasecmp(var->name, "buddy"))
02179             aji_create_buddy(var->value, client);
02180    /* no transport support in this version */
02181    /* else if (!strcasecmp(var->name, "transport"))
02182             aji_create_transport(var->value, client);
02183    */
02184       var = var->next;
02185    }
02186    if (!flag) {
02187       ASTOBJ_UNLOCK(client);
02188       ASTOBJ_UNREF(client, aji_client_destroy);
02189       return 1;
02190    }
02191    client->p = iks_stream_new(((client->component) ? "jabber:component:accept" : "jabber:client"), client, aji_act_hook);
02192    if (!client->p) {
02193       ast_log(LOG_ERROR, "Failed to create stream for client '%s'!\n", client->name);
02194       return 0;
02195    }
02196    client->stack = iks_stack_new(8192, 8192);
02197    if (!client->stack) {
02198       ast_log(LOG_ERROR, "Failed to allocate stack for client '%s'\n", client->name);
02199       return 0;
02200    }
02201    client->f = iks_filter_new();
02202    if (!client->f) {
02203       ast_log(LOG_ERROR, "Failed to create filter for client '%s'\n", client->name);
02204       return 0;
02205    }
02206    if (!strchr(client->user, '/') && !client->component) { /*client */
02207       resource = NULL;
02208       asprintf(&resource, "%s/asterisk", client->user);
02209       if (resource) {
02210          client->jid = iks_id_new(client->stack, resource);
02211          free(resource);
02212       }
02213    } else
02214       client->jid = iks_id_new(client->stack, client->user);
02215    if (client->component) {
02216       iks_filter_add_rule(client->f, aji_dinfo_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
02217       iks_filter_add_rule(client->f, aji_ditems_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#items", IKS_RULE_DONE);
02218       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);
02219       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);
02220    } else {
02221       iks_filter_add_rule(client->f, aji_client_info_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
02222    }
02223    if (!strchr(client->user, '/') && !client->component) { /*client */
02224       resource = NULL;
02225       asprintf(&resource, "%s/asterisk", client->user);
02226       if (resource) {
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 = 1;
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       if (!ast_strlen_zero(id))
02432          astman_append(s, "ActionID: %s\r\n",id);
02433       astman_append(s, "Response: Success\r\n");
02434       return 0;
02435    }
02436    if (!ast_strlen_zero(id))
02437       astman_append(s, "ActionID: %s\r\n",id);
02438    astman_append(s, "Response: Failure\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 Mon Jul 14 17:25:00 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.1