Sat Apr 12 07:12:27 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: 89088 $")
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          {
00534             int features = 0;
00535             if (!strcmp("stream:features", iks_name(node))) {
00536                features = iks_stream_features(node);
00537                if (client->usesasl) {
00538                   if (client->usetls && !iks_is_secure(client->p))
00539                      break;
00540                   if (client->authorized) {
00541                      if (features & IKS_STREAM_BIND) {
00542                         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);
00543                         auth = iks_make_resource_bind(client->jid);
00544                         if (auth) {
00545                            iks_insert_attrib(auth, "id", client->mid);
00546                            ast_aji_increment_mid(client->mid);
00547                            iks_send(client->p, auth);
00548                            iks_delete(auth);
00549                         } else {
00550                            ast_log(LOG_ERROR, "Out of memory.\n");
00551                            break;
00552                         }
00553                      }
00554                      if (features & IKS_STREAM_SESSION) {
00555                         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);
00556                         auth = iks_make_session();
00557                         if (auth) {
00558                            iks_insert_attrib(auth, "id", "auth");
00559                            ast_aji_increment_mid(client->mid);
00560                            iks_send(client->p, auth);
00561                            iks_delete(auth);
00562                         } else {
00563                            ast_log(LOG_ERROR, "Out of memory.\n");
00564                         }
00565                      }
00566                   } else {
00567                      if (!client->jid->user) {
00568                         ast_log(LOG_ERROR, "Malformed Jabber ID : %s (domain missing?)\n", client->jid->full);
00569                         break;
00570                      }
00571                      features = aji_highest_bit(features);
00572                      if (features == IKS_STREAM_SASL_MD5)
00573                         iks_start_sasl(client->p, IKS_SASL_DIGEST_MD5, client->jid->user, client->password);
00574                      else {
00575                         if (features == IKS_STREAM_SASL_PLAIN) {
00576                            iks *x = NULL;
00577                            x = iks_new("auth");
00578                            if (x) {
00579                               int len = strlen(client->jid->user) + strlen(client->password) + 3;
00580                               /* XXX Check return values XXX */
00581                               char *s = ast_malloc(80 + len);
00582                               char *base64 = ast_malloc(80 + len * 2);
00583                               iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_SASL);
00584                               iks_insert_attrib(x, "mechanism", "PLAIN");
00585                               sprintf(s, "%c%s%c%s", 0, client->jid->user, 0, client->password);
00586                               ast_base64encode(base64, (const unsigned char *) s, len, len * 2);
00587                               iks_insert_cdata(x, base64, 0);
00588                               iks_send(client->p, x);
00589                               iks_delete(x);
00590                               if (base64)
00591                                  free(base64);
00592                               if (s)
00593                                  free(s);
00594                            } else {
00595                               ast_log(LOG_ERROR, "Out of memory.\n");
00596                            }
00597                         }
00598                      }
00599                   }
00600                }
00601             } else if (!strcmp("failure", iks_name(node))) {
00602                ast_log(LOG_ERROR, "JABBER: encryption failure. possible bad password.\n");
00603             } else if (!strcmp("success", iks_name(node))) {
00604                client->authorized = 1;
00605                iks_send_header(client->p, client->jid->server);
00606             }
00607             break;
00608          }
00609       case IKS_NODE_ERROR: 
00610             ast_log(LOG_ERROR, "JABBER: Node Error\n");
00611             ASTOBJ_UNREF(client, aji_client_destroy);
00612             return IKS_HOOK;
00613             break;
00614       case IKS_NODE_STOP: 
00615             ast_log(LOG_WARNING, "JABBER: Disconnected\n");
00616             ASTOBJ_UNREF(client, aji_client_destroy);
00617             return IKS_HOOK;
00618             break;
00619       }
00620    } else if (client->state != AJI_CONNECTED && client->component) {
00621       switch (type) {
00622       case IKS_NODE_START:
00623          if (client->state == AJI_DISCONNECTED) {
00624             char secret[160], shasum[320], *handshake;
00625 
00626             sprintf(secret, "%s%s", pak->id, client->password);
00627             ast_sha1_hash(shasum, secret);
00628             handshake = NULL;
00629             asprintf(&handshake, "<handshake>%s</handshake>", shasum);
00630             if (handshake) {
00631                iks_send_raw(client->p, handshake);
00632                free(handshake);
00633                handshake = NULL;
00634             }
00635             client->state = AJI_CONNECTING;
00636             if(iks_recv(client->p,1) == 2) /*XXX proper result for iksemel library on iks_recv of <handshake/> XXX*/
00637                client->state = AJI_CONNECTED;
00638             else
00639                ast_log(LOG_WARNING,"Jabber didn't seem to handshake, failed to authenicate.\n");
00640             break;
00641          }
00642          break;
00643 
00644       case IKS_NODE_NORMAL:
00645          break;
00646 
00647       case IKS_NODE_ERROR:
00648          ast_log(LOG_ERROR, "JABBER: Node Error\n");
00649          ASTOBJ_UNREF(client, aji_client_destroy);
00650          return IKS_HOOK;
00651 
00652       case IKS_NODE_STOP:
00653          ast_log(LOG_WARNING, "JABBER: Disconnected\n");
00654          ASTOBJ_UNREF(client, aji_client_destroy);
00655          return IKS_HOOK;
00656       }
00657    }
00658 
00659    switch (pak->type) {
00660    case IKS_PAK_NONE:
00661       if (option_debug)
00662          ast_log(LOG_DEBUG, "JABBER: I Don't know what to do with you NONE\n");
00663       break;
00664    case IKS_PAK_MESSAGE:
00665       aji_handle_message(client, pak);
00666       if (option_debug)
00667          ast_log(LOG_DEBUG, "JABBER: I Don't know what to do with you MESSAGE\n");
00668       break;
00669    case IKS_PAK_PRESENCE:
00670       aji_handle_presence(client, pak);
00671       if (option_debug)
00672          ast_log(LOG_DEBUG, "JABBER: I Do know how to handle presence!!\n");
00673       break;
00674    case IKS_PAK_S10N:
00675       aji_handle_subscribe(client, pak);
00676       if (option_debug)
00677          ast_log(LOG_DEBUG, "JABBER: I Dont know S10N subscribe!!\n");
00678       break;
00679    case IKS_PAK_IQ:
00680       if (option_debug)
00681          ast_log(LOG_DEBUG, "JABBER: I Dont have an IQ!!!\n");
00682       aji_handle_iq(client, node);
00683       break;
00684    default:
00685       if (option_debug)
00686          ast_log(LOG_DEBUG, "JABBER: I Dont know %i\n", pak->type);
00687       break;
00688    }
00689    
00690    iks_filter_packet(client->f, pak);
00691 
00692    if (node)
00693       iks_delete(node);
00694 
00695    ASTOBJ_UNREF(client, aji_client_destroy);
00696    return IKS_OK;
00697 }
00698 
00699 static int aji_register_approve_handler(void *data, ikspak *pak)
00700 {
00701    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00702    iks *iq = NULL, *presence = NULL, *x = NULL;
00703 
00704    iq = iks_new("iq");
00705    presence = iks_new("presence");
00706    x = iks_new("x");
00707    if (client && iq && presence && x) {
00708       if (!iks_find(pak->query, "remove")) {
00709          iks_insert_attrib(iq, "from", client->jid->full);
00710          iks_insert_attrib(iq, "to", pak->from->full);
00711          iks_insert_attrib(iq, "id", pak->id);
00712          iks_insert_attrib(iq, "type", "result");
00713          iks_send(client->p, iq);
00714 
00715          iks_insert_attrib(presence, "from", client->jid->full);
00716          iks_insert_attrib(presence, "to", pak->from->partial);
00717          iks_insert_attrib(presence, "id", client->mid);
00718          ast_aji_increment_mid(client->mid);
00719          iks_insert_attrib(presence, "type", "subscribe");
00720          iks_insert_attrib(x, "xmlns", "vcard-temp:x:update");
00721          iks_insert_node(presence, x);
00722          iks_send(client->p, presence); 
00723       }
00724    } else {
00725       ast_log(LOG_ERROR, "Out of memory.\n");
00726    }
00727 
00728    if (iq)
00729       iks_delete(iq);
00730    if(presence)
00731       iks_delete(presence);
00732    if (x)
00733       iks_delete(x);
00734    ASTOBJ_UNREF(client, aji_client_destroy);
00735    return IKS_FILTER_EAT;
00736 }
00737 
00738 static int aji_register_query_handler(void *data, ikspak *pak)
00739 {
00740    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00741    struct aji_buddy *buddy = NULL; 
00742    char *node = NULL;
00743 
00744    client = (struct aji_client *) data;
00745 
00746    buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
00747    if (!buddy) {
00748       iks *iq = NULL, *query = NULL, *error = NULL, *notacceptable = NULL;
00749       ast_verbose("Someone.... %s tried to register but they aren't allowed\n", pak->from->partial);
00750       iq = iks_new("iq");
00751       query = iks_new("query");
00752       error = iks_new("error");
00753       notacceptable = iks_new("not-acceptable");
00754       if(iq && query && error && notacceptable) {
00755          iks_insert_attrib(iq, "type", "error");
00756          iks_insert_attrib(iq, "from", client->user);
00757          iks_insert_attrib(iq, "to", pak->from->full);
00758          iks_insert_attrib(iq, "id", pak->id);
00759          iks_insert_attrib(query, "xmlns", "jabber:iq:register");
00760          iks_insert_attrib(error, "code" , "406");
00761          iks_insert_attrib(error, "type", "modify");
00762          iks_insert_attrib(notacceptable, "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas");
00763          iks_insert_node(iq, query);
00764          iks_insert_node(iq, error);
00765          iks_insert_node(error, notacceptable);
00766          iks_send(client->p, iq);
00767       } else {
00768          ast_log(LOG_ERROR, "Out of memory.\n");
00769       }
00770       if (iq)
00771          iks_delete(iq);
00772       if (query)
00773          iks_delete(query);
00774       if (error)
00775          iks_delete(error);
00776       if (notacceptable)
00777          iks_delete(notacceptable);
00778    } else   if (!(node = iks_find_attrib(pak->query, "node"))) {
00779       iks *iq = NULL, *query = NULL, *instructions = NULL;
00780       char *explain = "Welcome to Asterisk - the Open Source PBX.\n";
00781       iq = iks_new("iq");
00782       query = iks_new("query");
00783       instructions = iks_new("instructions");
00784       if (iq && query && instructions && client) {
00785          iks_insert_attrib(iq, "from", client->user);
00786          iks_insert_attrib(iq, "to", pak->from->full);
00787          iks_insert_attrib(iq, "id", pak->id);
00788          iks_insert_attrib(iq, "type", "result");
00789          iks_insert_attrib(query, "xmlns", "jabber:iq:register");
00790          iks_insert_cdata(instructions, explain, 0);
00791          iks_insert_node(iq, query);
00792          iks_insert_node(query, instructions);
00793          iks_send(client->p, iq);
00794       } else {
00795          ast_log(LOG_ERROR, "Out of memory.\n");
00796       }
00797       if (iq)
00798          iks_delete(iq);
00799       if (query)
00800          iks_delete(query);
00801       if (instructions)
00802          iks_delete(instructions);
00803    }
00804    ASTOBJ_UNREF(client, aji_client_destroy);
00805    return IKS_FILTER_EAT;
00806 }
00807 
00808 static int aji_ditems_handler(void *data, ikspak *pak)
00809 {
00810    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00811    char *node = NULL;
00812 
00813    if (!(node = iks_find_attrib(pak->query, "node"))) {
00814       iks *iq = NULL, *query = NULL, *item = NULL;
00815       iq = iks_new("iq");
00816       query = iks_new("query");
00817       item = iks_new("item");
00818 
00819       if (iq && query && item) {
00820          iks_insert_attrib(iq, "from", client->user);
00821          iks_insert_attrib(iq, "to", pak->from->full);
00822          iks_insert_attrib(iq, "id", pak->id);
00823          iks_insert_attrib(iq, "type", "result");
00824          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
00825          iks_insert_attrib(item, "node", "http://jabber.org/protocol/commands");
00826          iks_insert_attrib(item, "name", "Million Dollar Asterisk Commands");
00827          iks_insert_attrib(item, "jid", client->user);
00828 
00829          iks_insert_node(iq, query);
00830          iks_insert_node(query, item);
00831          iks_send(client->p, iq);
00832       } else {
00833          ast_log(LOG_ERROR, "Out of memory.\n");
00834       }
00835       if (iq)
00836          iks_delete(iq);
00837       if (query)
00838          iks_delete(query);
00839       if (item)
00840          iks_delete(item);
00841 
00842    } else if (!strcasecmp(node, "http://jabber.org/protocol/commands")) {
00843       iks *iq, *query, *confirm;
00844       iq = iks_new("iq");
00845       query = iks_new("query");
00846       confirm = iks_new("item");
00847       if (iq && query && confirm && client) {
00848          iks_insert_attrib(iq, "from", client->user);
00849          iks_insert_attrib(iq, "to", pak->from->full);
00850          iks_insert_attrib(iq, "id", pak->id);
00851          iks_insert_attrib(iq, "type", "result");
00852          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
00853          iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
00854          iks_insert_attrib(confirm, "node", "confirmaccount");
00855          iks_insert_attrib(confirm, "name", "Confirm AIM account");
00856          iks_insert_attrib(confirm, "jid", "blog.astjab.org");
00857 
00858          iks_insert_node(iq, query);
00859          iks_insert_node(query, confirm);
00860          iks_send(client->p, iq);
00861       } else {
00862          ast_log(LOG_ERROR, "Out of memory.\n");
00863       }
00864       if (iq)
00865          iks_delete(iq);
00866       if (query)
00867          iks_delete(query);
00868       if (confirm)
00869          iks_delete(confirm);
00870 
00871    } else if (!strcasecmp(node, "confirmaccount")) {
00872       iks *iq = NULL, *query = NULL, *feature = NULL;
00873 
00874       iq = iks_new("iq");
00875       query = iks_new("query");
00876       feature = iks_new("feature");
00877 
00878       if (iq && query && feature && client) {
00879          iks_insert_attrib(iq, "from", client->user);
00880          iks_insert_attrib(iq, "to", pak->from->full);
00881          iks_insert_attrib(iq, "id", pak->id);
00882          iks_insert_attrib(iq, "type", "result");
00883          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
00884          iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
00885          iks_insert_node(iq, query);
00886          iks_insert_node(query, feature);
00887          iks_send(client->p, iq);
00888       } else {
00889          ast_log(LOG_ERROR, "Out of memory.\n");
00890       }
00891       if (iq)
00892          iks_delete(iq);
00893       if (query)
00894          iks_delete(query);
00895       if (feature)
00896          iks_delete(feature);
00897    }
00898 
00899    ASTOBJ_UNREF(client, aji_client_destroy);
00900    return IKS_FILTER_EAT;
00901 
00902 }
00903 
00904 static int aji_client_info_handler(void *data, ikspak *pak)
00905 {
00906    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00907    struct aji_resource *resource = NULL;
00908    struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
00909 
00910    resource = aji_find_resource(buddy, pak->from->resource);
00911    if (pak->subtype == IKS_TYPE_RESULT) {
00912       if (!resource) {
00913          ast_log(LOG_NOTICE,"JABBER: Received client info from %s when not requested.\n", pak->from->full);
00914          ASTOBJ_UNREF(client, aji_client_destroy);
00915          return IKS_FILTER_EAT;
00916       }
00917       if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
00918          resource->cap->jingle = 1;
00919       } else
00920          resource->cap->jingle = 0;
00921    } else if (pak->subtype == IKS_TYPE_GET) {
00922       iks *iq, *disco, *ident, *google, *query;
00923       iq = iks_new("iq");
00924       query = iks_new("query");
00925       ident = iks_new("identity");
00926       disco = iks_new("feature");
00927       google = iks_new("feature");
00928       if (iq && ident && disco && google) {
00929          iks_insert_attrib(iq, "from", client->jid->full);
00930          iks_insert_attrib(iq, "to", pak->from->full);
00931          iks_insert_attrib(iq, "type", "result");
00932          iks_insert_attrib(iq, "id", pak->id);
00933          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
00934          iks_insert_attrib(ident, "category", "client");
00935          iks_insert_attrib(ident, "type", "pc");
00936          iks_insert_attrib(ident, "name", "asterisk");
00937          iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco#info");
00938          iks_insert_attrib(google, "var", "http://www.google.com/xmpp/protocol/voice/v1");
00939          iks_insert_node(iq, query);
00940          iks_insert_node(query, ident);
00941          iks_insert_node(query, google);
00942          iks_insert_node(query, disco);
00943          iks_send(client->p, iq);
00944       } else
00945          ast_log(LOG_ERROR, "Out of Memory.\n");
00946       if (iq)
00947          iks_delete(iq);
00948       if (query)
00949          iks_delete(query);
00950       if (ident)
00951          iks_delete(ident);
00952       if (google)
00953          iks_delete(google);
00954       if (disco)
00955          iks_delete(disco);
00956    } else if (pak->subtype == IKS_TYPE_ERROR) {
00957       ast_log(LOG_NOTICE, "User %s does not support discovery.\n", pak->from->full);
00958    }
00959    ASTOBJ_UNREF(client, aji_client_destroy);
00960    return IKS_FILTER_EAT;
00961 }
00962 
00963 static int aji_dinfo_handler(void *data, ikspak *pak)
00964 {
00965    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00966    char *node = NULL;
00967    struct aji_resource *resource = NULL;
00968    struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
00969 
00970    resource = aji_find_resource(buddy, pak->from->resource);
00971    if (pak->subtype == IKS_TYPE_ERROR) {
00972       ast_log(LOG_WARNING, "Recieved error from a client, turn on jabber debug!\n");
00973       return IKS_FILTER_EAT;
00974    }
00975    if (pak->subtype == IKS_TYPE_RESULT) {
00976       if (!resource) {
00977          ast_log(LOG_NOTICE,"JABBER: Received client info from %s when not requested.\n", pak->from->full);
00978          ASTOBJ_UNREF(client, aji_client_destroy);
00979          return IKS_FILTER_EAT;
00980       }
00981       if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
00982          resource->cap->jingle = 1;
00983       } else
00984          resource->cap->jingle = 0;
00985    } else if (pak->subtype == IKS_TYPE_GET && !(node = iks_find_attrib(pak->query, "node"))) {
00986       iks *iq, *query, *identity, *disco, *reg, *commands, *gateway, *version, *vcard, *search;
00987 
00988       iq = iks_new("iq");
00989       query = iks_new("query");
00990       identity = iks_new("identity");
00991       disco = iks_new("feature");
00992       reg = iks_new("feature");
00993       commands = iks_new("feature");
00994       gateway = iks_new("feature");
00995       version = iks_new("feature");
00996       vcard = iks_new("feature");
00997       search = iks_new("feature");
00998 
00999       if (iq && query && identity && disco && reg && commands && gateway && version && vcard && search && client) {
01000          iks_insert_attrib(iq, "from", client->user);
01001          iks_insert_attrib(iq, "to", pak->from->full);
01002          iks_insert_attrib(iq, "id", pak->id);
01003          iks_insert_attrib(iq, "type", "result");
01004          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01005          iks_insert_attrib(identity, "category", "gateway");
01006          iks_insert_attrib(identity, "type", "pstn");
01007          iks_insert_attrib(identity, "name", "Asterisk The Open Source PBX");
01008          iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco");
01009          iks_insert_attrib(reg, "var", "jabber:iq:register");
01010          iks_insert_attrib(commands, "var", "http://jabber.org/protocol/commands");
01011          iks_insert_attrib(gateway, "var", "jabber:iq:gateway");
01012          iks_insert_attrib(version, "var", "jabber:iq:version");
01013          iks_insert_attrib(vcard, "var", "vcard-temp");
01014          iks_insert_attrib(search, "var", "jabber:iq:search");
01015 
01016          iks_insert_node(iq, query);
01017          iks_insert_node(query, identity);
01018          iks_insert_node(query, disco);
01019          iks_insert_node(query, reg);
01020          iks_insert_node(query, commands);
01021          iks_insert_node(query, gateway);
01022          iks_insert_node(query, version);
01023          iks_insert_node(query, vcard);
01024          iks_insert_node(query, search);
01025          iks_send(client->p, iq);
01026       } else {
01027          ast_log(LOG_ERROR, "Out of memory.\n");
01028       }
01029 
01030       if (iq)
01031          iks_delete(iq);
01032       if (query)
01033          iks_delete(query);
01034       if (identity)
01035          iks_delete(identity);
01036       if (disco)
01037          iks_delete(disco);
01038       if (reg)
01039          iks_delete(reg);
01040       if (commands)
01041          iks_delete(commands);
01042       if (gateway)
01043          iks_delete(gateway);
01044       if (version)
01045          iks_delete(version);
01046       if (vcard)
01047          iks_delete(vcard);
01048       if (search)
01049          iks_delete(search);
01050 
01051    } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "http://jabber.org/protocol/commands")) {
01052       iks *iq, *query, *confirm;
01053       iq = iks_new("iq");
01054       query = iks_new("query");
01055       confirm = iks_new("item");
01056 
01057       if (iq && query && confirm && client) {
01058          iks_insert_attrib(iq, "from", client->user);
01059          iks_insert_attrib(iq, "to", pak->from->full);
01060          iks_insert_attrib(iq, "id", pak->id);
01061          iks_insert_attrib(iq, "type", "result");
01062          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01063          iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
01064          iks_insert_attrib(confirm, "node", "confirmaccount");
01065          iks_insert_attrib(confirm, "name", "Confirm AIM account");
01066          iks_insert_attrib(confirm, "jid", client->user);
01067          iks_insert_node(iq, query);
01068          iks_insert_node(query, confirm);
01069          iks_send(client->p, iq);
01070       } else {
01071          ast_log(LOG_ERROR, "Out of memory.\n");
01072       }
01073       if (iq)
01074          iks_delete(iq);
01075       if (query)
01076          iks_delete(query);
01077       if (confirm)
01078          iks_delete(confirm);
01079 
01080    } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "confirmaccount")) {
01081       iks *iq, *query, *feature;
01082 
01083       iq = iks_new("iq");
01084       query = iks_new("query");
01085       feature = iks_new("feature");
01086 
01087       if (iq && query && feature && client) {
01088          iks_insert_attrib(iq, "from", client->user);
01089          iks_insert_attrib(iq, "to", pak->from->full);
01090          iks_insert_attrib(iq, "id", pak->id);
01091          iks_insert_attrib(iq, "type", "result");
01092          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01093          iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
01094          iks_insert_node(iq, query);
01095          iks_insert_node(query, feature);
01096          iks_send(client->p, iq);
01097       } else {
01098          ast_log(LOG_ERROR, "Out of memory.\n");
01099       }
01100       if (iq)
01101          iks_delete(iq);
01102       if (query)
01103          iks_delete(query);
01104       if (feature)
01105          iks_delete(feature);
01106    }
01107 
01108    ASTOBJ_UNREF(client, aji_client_destroy);
01109    return IKS_FILTER_EAT;
01110 }
01111 
01112 /*!
01113  * \brief Handles <iq> tags.
01114  * \param client structure and the iq node.
01115  * \return void.
01116  */
01117 static void aji_handle_iq(struct aji_client *client, iks *node)
01118 {
01119    /*Nothing to see here */
01120 }
01121 
01122 /*!
01123  * \brief Handles presence packets.
01124  * \param client structure and the node.
01125  * \return void.
01126  */
01127 static void aji_handle_message(struct aji_client *client, ikspak *pak)
01128 {
01129    struct aji_message *insert, *tmp;
01130    int flag = 0;
01131    
01132    if (!(insert = ast_calloc(1, sizeof(struct aji_message))))
01133       return;
01134    time(&insert->arrived);
01135    if (iks_find_cdata(pak->x, "body"))
01136       insert->message = ast_strdup(iks_find_cdata(pak->x, "body"));
01137    if(pak->id)
01138       ast_copy_string(insert->id, pak->id, sizeof(insert->message));
01139    if (pak->from)
01140       insert->from = ast_strdup(pak->from->full);
01141    AST_LIST_LOCK(&client->messages);
01142    AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, tmp, list) {
01143       if (flag) {
01144          AST_LIST_REMOVE_CURRENT(&client->messages, list);
01145          if (tmp->from)
01146             free(tmp->from);
01147          if (tmp->message)
01148             free(tmp->message);
01149       } else if (difftime(time(NULL), tmp->arrived) >= client->message_timeout) {
01150          flag = 1;
01151          AST_LIST_REMOVE_CURRENT(&client->messages, list);
01152          if (tmp->from)
01153             free(tmp->from);
01154          if (tmp->message)
01155             free(tmp->message);
01156       }
01157    }
01158    AST_LIST_TRAVERSE_SAFE_END;
01159    AST_LIST_INSERT_HEAD(&client->messages, insert, list);
01160    AST_LIST_UNLOCK(&client->messages);
01161 }
01162 
01163 static void aji_handle_presence(struct aji_client *client, ikspak *pak)
01164 {
01165    int status, priority;
01166    struct aji_buddy *buddy;
01167    struct aji_resource *tmp = NULL, *last = NULL, *found = NULL;
01168    char *ver, *node, *descrip, *type;
01169    
01170    if(client->state != AJI_CONNECTED)
01171       aji_create_buddy(pak->from->partial, client);
01172 
01173    buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01174    if (!buddy && pak->from->partial) {
01175       /* allow our jid to be used to log in with another resource */
01176       if (!strcmp((const char *)pak->from->partial, (const char *)client->jid->partial))
01177          aji_create_buddy(pak->from->partial, client);
01178       else
01179          ast_log(LOG_NOTICE, "Got presence packet from %s, someone not in our roster!!!!\n", pak->from->partial);
01180       return;
01181    }
01182    type = iks_find_attrib(pak->x, "type");
01183    if(client->component && type &&!strcasecmp("probe", type)) {
01184       aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), 1, client->statusmessage);
01185       ast_verbose("what i was looking for \n");
01186    }
01187    ASTOBJ_WRLOCK(buddy);
01188    status = (pak->show) ? pak->show : 6;
01189    priority = atoi((iks_find_cdata(pak->x, "priority")) ? iks_find_cdata(pak->x, "priority") : "0");
01190    tmp = buddy->resources;
01191    descrip = ast_strdup(iks_find_cdata(pak->x,"status"));
01192 
01193    while (tmp && pak->from->resource) {
01194       if (!strcasecmp(tmp->resource, pak->from->resource)) {
01195          tmp->status = status;
01196          if (tmp->description) free(tmp->description);
01197          tmp->description = descrip;
01198          found = tmp;
01199          if (status == 6) {   /* Sign off Destroy resource */
01200             if (last && found->next) {
01201                last->next = found->next;
01202             } else if (!last) {
01203                if (found->next)
01204                   buddy->resources = found->next;
01205                else
01206                   buddy->resources = NULL;
01207             } else if (!found->next) {
01208                if (last)
01209                   last->next = NULL;
01210                else
01211                   buddy->resources = NULL;
01212             }
01213             free(found);
01214             found = NULL;
01215             break;
01216          }
01217          /* resource list is sorted by descending priority */
01218          if (tmp->priority != priority) {
01219             found->priority = priority;
01220             if (!last && !found->next)
01221                /* resource was found to be unique,
01222                   leave loop */
01223                break;
01224             /* search for resource in our list
01225                and take it out for the moment */
01226             if (last)
01227                last->next = found->next;
01228             else
01229                buddy->resources = found->next;
01230 
01231             last = NULL;
01232             tmp = buddy->resources;
01233             if (!buddy->resources)
01234                buddy->resources = found;
01235             /* priority processing */
01236             while (tmp) {
01237                /* insert resource back according to 
01238                   its priority value */
01239                if (found->priority > tmp->priority) {
01240                   if (last)
01241                      /* insert within list */
01242                      last->next = found;
01243                   found->next = tmp;
01244                   if (!last)
01245                      /* insert on top */
01246                      buddy->resources = found;
01247                   break;
01248                }
01249                if (!tmp->next) {
01250                   /* insert at the end of the list */
01251                   tmp->next = found;
01252                   found->next = NULL;
01253                   break;
01254                }
01255                last = tmp;
01256                tmp = tmp->next;
01257             }
01258          }
01259          break;
01260       }
01261       last = tmp;
01262       tmp = tmp->next;
01263    }
01264 
01265    /* resource not found in our list, create it */
01266    if (!found && status != 6 && pak->from->resource) {
01267       found = (struct aji_resource *) malloc(sizeof(struct aji_resource));
01268       memset(found, 0, sizeof(struct aji_resource));
01269 
01270       if (!found) {
01271          ast_log(LOG_ERROR, "Out of memory!\n");
01272          return;
01273       }
01274       ast_copy_string(found->resource, pak->from->resource, sizeof(found->resource));
01275       found->status = status;
01276       found->description = descrip;
01277       found->priority = priority;
01278       found->next = NULL;
01279       last = NULL;
01280       tmp = buddy->resources;
01281       while (tmp) {
01282          if (found->priority > tmp->priority) {
01283             if (last)
01284                last->next = found;
01285             found->next = tmp;
01286             if (!last)
01287                buddy->resources = found;
01288             break;
01289          }
01290          if (!tmp->next) {
01291             tmp->next = found;
01292             break;
01293          }
01294          last = tmp;
01295          tmp = tmp->next;
01296       }
01297       if (!tmp)
01298          buddy->resources = found;
01299    }
01300    
01301    ASTOBJ_UNLOCK(buddy);
01302    ASTOBJ_UNREF(buddy, aji_buddy_destroy);
01303 
01304    node = iks_find_attrib(iks_find(pak->x, "c"), "node");
01305    ver = iks_find_attrib(iks_find(pak->x, "c"), "ver");
01306 
01307    /* handle gmail client's special caps:c tag */
01308    if (!node && !ver) {
01309       node = iks_find_attrib(iks_find(pak->x, "caps:c"), "node");
01310       ver = iks_find_attrib(iks_find(pak->x, "caps:c"), "ver");
01311    }
01312 
01313    /* retrieve capabilites of the new resource */
01314    if(status !=6 && found && !found->cap) {
01315       found->cap = aji_find_version(node, ver, pak);
01316       if(gtalk_yuck(pak->x)) /* gtalk should do discover */
01317          found->cap->jingle = 1;
01318       if(found->cap->jingle && option_debug > 4)
01319          ast_log(LOG_DEBUG,"Special case for google till they support discover.\n");
01320       else {
01321          iks *iq, *query;
01322          iq = iks_new("iq");
01323          query = iks_new("query");
01324          if(query && iq)  {
01325             iks_insert_attrib(iq, "type", "get");
01326             iks_insert_attrib(iq, "to", pak->from->full);
01327             iks_insert_attrib(iq,"from", client->jid->full);
01328             iks_insert_attrib(iq, "id", client->mid);
01329             ast_aji_increment_mid(client->mid);
01330             iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01331             iks_insert_node(iq, query);
01332             iks_send(client->p, iq);
01333             
01334          } else
01335             ast_log(LOG_ERROR, "Out of memory.\n");
01336          if(query)
01337             iks_delete(query);
01338          if(iq)
01339             iks_delete(iq);
01340       }
01341    }
01342    if (option_verbose > 4) {
01343       switch (pak->subtype) {
01344       case IKS_TYPE_AVAILABLE:
01345          ast_verbose(VERBOSE_PREFIX_3 "JABBER: I am available ^_* %i\n", pak->subtype);
01346          break;
01347       case IKS_TYPE_UNAVAILABLE:
01348          ast_verbose(VERBOSE_PREFIX_3 "JABBER: I am unavailable ^_* %i\n", pak->subtype);
01349          break;
01350       default:
01351          ast_verbose(VERBOSE_PREFIX_3 "JABBER: Ohh sexy and the wrong type: %i\n", pak->subtype);
01352       }
01353       switch (pak->show) {
01354       case IKS_SHOW_UNAVAILABLE:
01355          ast_verbose(VERBOSE_PREFIX_3 "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01356          break;
01357       case IKS_SHOW_AVAILABLE:
01358          ast_verbose(VERBOSE_PREFIX_3 "JABBER: type is available\n");
01359          break;
01360       case IKS_SHOW_CHAT:
01361          ast_verbose(VERBOSE_PREFIX_3 "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01362          break;
01363       case IKS_SHOW_AWAY:
01364          ast_verbose(VERBOSE_PREFIX_3 "JABBER: type is away\n");
01365          break;
01366       case IKS_SHOW_XA:
01367          ast_verbose(VERBOSE_PREFIX_3 "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01368          break;
01369       case IKS_SHOW_DND:
01370          ast_verbose(VERBOSE_PREFIX_3 "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01371          break;
01372       default:
01373          ast_verbose(VERBOSE_PREFIX_3 "JABBER: Kinky! how did that happen %i\n", pak->show);
01374       }
01375    }
01376 }
01377 
01378 /*!
01379  * \brief handles subscription requests.
01380  * \param aji_client struct and xml packet.
01381  * \return void.
01382  */
01383 static void aji_handle_subscribe(struct aji_client *client, ikspak *pak)
01384 {
01385    if(pak->subtype == IKS_TYPE_SUBSCRIBE) { 
01386       iks *presence = NULL, *status = NULL;
01387       presence = iks_new("presence");
01388       status = iks_new("status");
01389       if(presence && status) {
01390          iks_insert_attrib(presence, "type", "subscribed");
01391          iks_insert_attrib(presence, "to", pak->from->full);
01392          iks_insert_attrib(presence, "from", client->jid->full);
01393          if(pak->id)
01394             iks_insert_attrib(presence, "id", pak->id);
01395          iks_insert_cdata(status, "Asterisk has approved subscription", 0);
01396          iks_insert_node(presence, status);
01397          iks_send(client->p, presence);
01398       } else
01399          ast_log(LOG_ERROR, "Unable to allocate nodes\n");
01400       if(presence)
01401          iks_delete(presence);
01402       if(status)
01403          iks_delete(status);
01404       if(client->component)
01405          aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), 1, client->statusmessage);
01406    }
01407    if (option_verbose > 4) {
01408       switch (pak->subtype) {
01409       case IKS_TYPE_SUBSCRIBE:
01410          ast_verbose(VERBOSE_PREFIX_3 "JABBER: This is a subcription of type %i\n", pak->subtype);
01411          break;
01412       case IKS_TYPE_SUBSCRIBED:
01413          ast_verbose(VERBOSE_PREFIX_3 "JABBER: This is a subcription of type %i\n", pak->subtype);
01414          break;
01415       case IKS_TYPE_UNSUBSCRIBE:
01416          ast_verbose(VERBOSE_PREFIX_3 "JABBER: This is a subcription of type %i\n", pak->subtype);
01417          break;
01418       case IKS_TYPE_UNSUBSCRIBED:
01419          ast_verbose(VERBOSE_PREFIX_3 "JABBER: This is a subcription of type %i\n", pak->subtype);
01420          break;
01421       default:          /*IKS_TYPE_ERROR: */
01422          ast_verbose(VERBOSE_PREFIX_3 "JABBER: This is a subcription of type %i\n", pak->subtype);
01423          break;
01424       }
01425    }
01426 }
01427 
01428 /*!
01429  * \brief sends messages.
01430  * \param aji_client struct , reciever, message.
01431  * \return 1.
01432  */
01433 int ast_aji_send(struct aji_client *client, const char *address, const char *message)
01434 {
01435    int res = 0;
01436    iks *message_packet = NULL;
01437    if (client->state == AJI_CONNECTED) {
01438       message_packet = iks_make_msg(IKS_TYPE_CHAT, address, message);
01439       if (message_packet) {
01440          iks_insert_attrib(message_packet, "from", client->jid->full);
01441          res = iks_send(client->p, message_packet);
01442       } else {
01443          ast_log(LOG_ERROR, "Out of memory.\n");
01444       }
01445       if (message_packet)
01446          iks_delete(message_packet);
01447    } else
01448       ast_log(LOG_WARNING, "JABBER: Not connected can't send\n");
01449    return 1;
01450 }
01451 
01452 /*!
01453  * \brief create a chatroom.
01454  * \param aji_client struct , room, server, topic for the room.
01455  * \return 0.
01456  */
01457 int ast_aji_create_chat(struct aji_client *client, char *room, char *server, char *topic)
01458 {
01459    int res = 0;
01460    iks *iq = NULL;
01461    iq = iks_new("iq");
01462    if (iq && client) {
01463       iks_insert_attrib(iq, "type", "get");
01464       iks_insert_attrib(iq, "to", server);
01465       iks_insert_attrib(iq, "id", client->mid);
01466       ast_aji_increment_mid(client->mid);
01467       iks_send(client->p, iq);
01468    } else 
01469       ast_log(LOG_ERROR, "Out of memory.\n");
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 = iks_send_raw(client->p, " ");
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.
02363  * \param void. 
02364  * \return 1.
02365  */
02366 struct aji_client *ast_aji_get_client(const char *name)
02367 {
02368    struct aji_client *client = NULL;
02369 
02370    client = ASTOBJ_CONTAINER_FIND(&clients, name);
02371    if (!client && !strchr(name, '@'))
02372       client = ASTOBJ_CONTAINER_FIND_FULL(&clients, name, user,,, strcasecmp);
02373    return client;
02374 }
02375 
02376 struct aji_client_container *ast_aji_get_clients(void)
02377 {
02378    return &clients;
02379 }
02380 
02381 static char mandescr_jabber_send[] =
02382 "Description: Sends a message to a Jabber Client.\n"
02383 "Variables: \n"
02384 "  Jabber:  Client or transport Asterisk uses to connect to JABBER.\n"
02385 "  ScreenName: User Name to message.\n"
02386 "  Message: Message to be sent to the buddy\n";
02387 
02388 /*! \brief  Send a Jabber Message via call from the Manager */
02389 static int manager_jabber_send(struct mansession *s, const struct message *m)
02390 {
02391    struct aji_client *client = NULL;
02392    const char *id = astman_get_header(m,"ActionID");
02393    const char *jabber = astman_get_header(m,"Jabber");
02394    const char *screenname = astman_get_header(m,"ScreenName");
02395    const char *message = astman_get_header(m,"Message");
02396 
02397    if (ast_strlen_zero(jabber)) {
02398       astman_send_error(s, m, "No transport specified");
02399       return 0;
02400    }
02401    if (ast_strlen_zero(screenname)) {
02402       astman_send_error(s, m, "No ScreenName specified");
02403       return 0;
02404    }
02405    if (ast_strlen_zero(message)) {
02406       astman_send_error(s, m, "No Message specified");
02407       return 0;
02408    }
02409 
02410    astman_send_ack(s, m, "Attempting to send Jabber Message");
02411    client = ast_aji_get_client(jabber);
02412    if (!client) {
02413       astman_send_error(s, m, "Could not find Sender");
02414       return 0;
02415    }  
02416    if (strchr(screenname, '@') && message){
02417       ast_aji_send(client, screenname, message);   
02418       if (!ast_strlen_zero(id))
02419          astman_append(s, "ActionID: %s\r\n",id);
02420       astman_append(s, "Response: Success\r\n");
02421       return 0;
02422    }
02423    if (!ast_strlen_zero(id))
02424       astman_append(s, "ActionID: %s\r\n",id);
02425    astman_append(s, "Response: Failure\r\n");
02426    return 0;
02427 }
02428 
02429 
02430 static int aji_reload()
02431 {
02432    ASTOBJ_CONTAINER_MARKALL(&clients);
02433    if (!aji_load_config()) {
02434       ast_log(LOG_ERROR, "JABBER: Failed to load config.\n");
02435       return 0;
02436    }
02437    ASTOBJ_CONTAINER_PRUNE_MARKED(&clients, aji_client_destroy);
02438    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02439       ASTOBJ_RDLOCK(iterator);
02440       if(iterator->state == AJI_DISCONNECTED) {
02441          if (!iterator->thread)
02442             ast_pthread_create_background(&iterator->thread, NULL, aji_recv_loop, iterator);
02443       } else if (iterator->state == AJI_CONNECTING)
02444          aji_get_roster(iterator);
02445       ASTOBJ_UNLOCK(iterator);
02446    });
02447    
02448    return 1;
02449 }
02450 
02451 static int unload_module(void)
02452 {
02453 
02454    /* Check if TLS is initialized. If that's the case, we can't unload this
02455       module due to a bug in the iksemel library that will cause a crash or
02456       a deadlock. We're trying to find a way to handle this, but in the meantime
02457       we will simply refuse to die... 
02458     */
02459    if (tls_initialized) {
02460       ast_log(LOG_ERROR, "Module can't be unloaded due to a bug in the Iksemel library when using TLS.\n");
02461       return 1;   /* You need a forced unload to get rid of this module */
02462    }
02463 
02464    ast_cli_unregister_multiple(aji_cli, sizeof(aji_cli) / sizeof(struct ast_cli_entry));
02465    ast_unregister_application(app_ajisend);
02466    ast_unregister_application(app_ajistatus);
02467    ast_manager_unregister("JabberSend");
02468    
02469    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02470       ASTOBJ_RDLOCK(iterator);
02471       if (option_debug > 2)
02472          ast_log(LOG_DEBUG, "JABBER: Releasing and disconneing client: %s\n", iterator->name);
02473       iterator->state = AJI_DISCONNECTING;
02474       ast_aji_disconnect(iterator);
02475       pthread_join(iterator->thread, NULL);
02476       ASTOBJ_UNLOCK(iterator);
02477    });
02478 
02479    ASTOBJ_CONTAINER_DESTROYALL(&clients, aji_client_destroy);
02480    ASTOBJ_CONTAINER_DESTROY(&clients);
02481    return 0;
02482 }
02483 
02484 static int load_module(void)
02485 {
02486    ASTOBJ_CONTAINER_INIT(&clients);
02487    if(!aji_reload())
02488       return AST_MODULE_LOAD_DECLINE;
02489    ast_manager_register2("JabberSend", EVENT_FLAG_SYSTEM, manager_jabber_send,
02490          "Sends a message to a Jabber Client", mandescr_jabber_send);
02491    ast_register_application(app_ajisend, aji_send_exec, ajisend_synopsis, ajisend_descrip);
02492    ast_register_application(app_ajistatus, aji_status_exec, ajistatus_synopsis, ajistatus_descrip);
02493    ast_cli_register_multiple(aji_cli, sizeof(aji_cli) / sizeof(struct ast_cli_entry));
02494 
02495    return 0;
02496 }
02497 
02498 static int reload(void)
02499 {
02500    aji_reload();
02501    return 0;
02502 }
02503 
02504 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "AJI - Asterisk Jabber Interface",
02505       .load = load_module,
02506       .unload = unload_module,
02507       .reload = reload,
02508           );

Generated on Sat Apr 12 07:12:27 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.5