Sat Nov 1 06:28:36 2008

Asterisk developer's documentation


res_jabber.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2006, Digium, Inc.
00005  *
00006  * Matt O'Gorman <mogorman@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  * \brief A resource for interfacing asterisk directly as a client
00021  * or a component to a jabber compliant server.
00022  *
00023  * \todo If you unload this module, chan_gtalk/jingle will be dead. How do we handle that?
00024  * \todo If you have TLS, you can't unload this module. See bug #9738. This needs to be fixed,
00025  *       but the bug is in the unmantained Iksemel library
00026  *
00027  */
00028 
00029 /*** MODULEINFO
00030    <depend>iksemel</depend>
00031    <use>gnutls</use>
00032  ***/
00033 
00034 #include "asterisk.h"
00035 
00036 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 120675 $")
00037 
00038 #include <stdlib.h>
00039 #include <stdio.h>
00040 #include <iksemel.h>
00041 
00042 #include "asterisk/channel.h"
00043 #include "asterisk/jabber.h"
00044 #include "asterisk/file.h"
00045 #include "asterisk/config.h"
00046 #include "asterisk/callerid.h"
00047 #include "asterisk/lock.h"
00048 #include "asterisk/logger.h"
00049 #include "asterisk/options.h"
00050 #include "asterisk/cli.h"
00051 #include "asterisk/app.h"
00052 #include "asterisk/pbx.h"
00053 #include "asterisk/md5.h"
00054 #include "asterisk/acl.h"
00055 #include "asterisk/utils.h"
00056 #include "asterisk/module.h"
00057 #include "asterisk/astobj.h"
00058 #include "asterisk/astdb.h"
00059 #include "asterisk/manager.h"
00060 
00061 #define JABBER_CONFIG "jabber.conf"
00062 
00063 #ifndef FALSE
00064 #define FALSE 0
00065 #endif
00066 
00067 #ifndef TRUE
00068 #define TRUE 1
00069 #endif
00070 
00071 /*-- Forward declarations */
00072 static int aji_highest_bit(int number);
00073 static void aji_buddy_destroy(struct aji_buddy *obj);
00074 static void aji_client_destroy(struct aji_client *obj);
00075 static int aji_send_exec(struct ast_channel *chan, void *data);
00076 static int aji_status_exec(struct ast_channel *chan, void *data);
00077 static void aji_log_hook(void *data, const char *xmpp, size_t size, int is_incoming);
00078 static int aji_act_hook(void *data, int type, iks *node);
00079 static void aji_handle_iq(struct aji_client *client, iks *node);
00080 static void aji_handle_message(struct aji_client *client, ikspak *pak);
00081 static void aji_handle_presence(struct aji_client *client, ikspak *pak);
00082 static void aji_handle_subscribe(struct aji_client *client, ikspak *pak);
00083 static void *aji_recv_loop(void *data);
00084 static int aji_component_initialize(struct aji_client *client);
00085 static int aji_client_initialize(struct aji_client *client);
00086 static int aji_client_connect(void *data, ikspak *pak);
00087 static void aji_set_presence(struct aji_client *client, char *to, char *from, int level, char *desc);
00088 static int aji_do_debug(int fd, int argc, char *argv[]);
00089 static int aji_do_reload(int fd, int argc, char *argv[]);
00090 static int aji_no_debug(int fd, int argc, char *argv[]);
00091 static int aji_test(int fd, int argc, char *argv[]);
00092 static int aji_show_clients(int fd, int argc, char *argv[]);
00093 static int aji_create_client(char *label, struct ast_variable *var, int debug);
00094 static int aji_create_buddy(char *label, struct aji_client *client);
00095 static int aji_reload(void);
00096 static int aji_load_config(void);
00097 static void aji_pruneregister(struct aji_client *client);
00098 static int aji_filter_roster(void *data, ikspak *pak);
00099 static int aji_get_roster(struct aji_client *client);
00100 static int aji_client_info_handler(void *data, ikspak *pak);
00101 static int aji_dinfo_handler(void *data, ikspak *pak);
00102 static int aji_ditems_handler(void *data, ikspak *pak);
00103 static int aji_register_query_handler(void *data, ikspak *pak);
00104 static int aji_register_approve_handler(void *data, ikspak *pak);
00105 static int aji_reconnect(struct aji_client *client);
00106 static iks *jabber_make_auth(iksid * id, const char *pass, const char *sid);
00107 /* No transports in this version */
00108 /*
00109 static int aji_create_transport(char *label, struct aji_client *client);
00110 static int aji_register_transport(void *data, ikspak *pak);
00111 static int aji_register_transport2(void *data, ikspak *pak);
00112 */
00113 
00114 static char debug_usage[] = 
00115 "Usage: jabber debug\n" 
00116 "       Enables dumping of Jabber packets for debugging purposes.\n";
00117 
00118 static char no_debug_usage[] = 
00119 "Usage: jabber debug off\n" 
00120 "       Disables dumping of Jabber packets for debugging purposes.\n";
00121 
00122 static char reload_usage[] = 
00123 "Usage: jabber reload\n" 
00124 "       Enables reloading of Jabber module.\n";
00125 
00126 static char test_usage[] = 
00127 "Usage: jabber test [client]\n" 
00128 "       Sends test message for debugging purposes.  A specific client\n"
00129 "       as configured in jabber.conf can be optionally specified.\n";
00130 
00131 static struct ast_cli_entry aji_cli[] = {
00132    { { "jabber", "debug", NULL},
00133    aji_do_debug, "Enable Jabber debugging",
00134    debug_usage },
00135 
00136    { { "jabber", "reload", NULL},
00137    aji_do_reload, "Reload Jabber configuration",
00138    reload_usage },
00139 
00140    { { "jabber", "show", "connected", NULL},
00141    aji_show_clients, "Show state of clients and components",
00142    debug_usage },
00143 
00144    { { "jabber", "debug", "off", NULL},
00145    aji_no_debug, "Disable Jabber debug",
00146    no_debug_usage },
00147 
00148    { { "jabber", "test", NULL},
00149    aji_test, "Shows roster, but is generally used for mog's debugging.",
00150    test_usage },
00151 };
00152 
00153 static char *app_ajisend = "JabberSend";
00154 
00155 static char *ajisend_synopsis = "JabberSend(jabber,screenname,message)";
00156 
00157 static char *ajisend_descrip =
00158 "JabberSend(Jabber,ScreenName,Message)\n"
00159 "  Jabber - Client or transport Asterisk uses to connect to Jabber\n" 
00160 "  ScreenName - User Name to message.\n" 
00161 "  Message - Message to be sent to the buddy\n";
00162 
00163 static char *app_ajistatus = "JabberStatus";
00164 
00165 static char *ajistatus_synopsis = "JabberStatus(Jabber,ScreenName,Variable)";
00166 
00167 static char *ajistatus_descrip =
00168 "JabberStatus(Jabber,ScreenName,Variable)\n"
00169 "  Jabber - Client or transport Asterisk uses to connect to Jabber\n"
00170 "  ScreenName - User Name to retrieve status from.\n"
00171 "  Variable - Variable to store presence in will be 1-6.\n" 
00172 "             In order, Online, Chatty, Away, XAway, DND, Offline\n" 
00173 "             If not in roster variable will = 7\n";
00174 
00175 struct aji_client_container clients;
00176 struct aji_capabilities *capabilities = NULL;
00177 
00178 /*! \brief Global flags, initialized to default values */
00179 static struct ast_flags globalflags = { AJI_AUTOPRUNE | AJI_AUTOREGISTER };
00180 static int tls_initialized = FALSE;
00181 
00182 /*!
00183  * \brief Deletes the aji_client data structure.
00184  * \param obj is the structure we will delete.
00185  * \return void.
00186  */
00187 static void aji_client_destroy(struct aji_client *obj)
00188 {
00189    struct aji_message *tmp;
00190    ASTOBJ_CONTAINER_DESTROYALL(&obj->buddies, aji_buddy_destroy);
00191    ASTOBJ_CONTAINER_DESTROY(&obj->buddies);
00192    iks_filter_delete(obj->f);
00193    iks_parser_delete(obj->p);
00194    iks_stack_delete(obj->stack);
00195    AST_LIST_LOCK(&obj->messages);
00196    while ((tmp = AST_LIST_REMOVE_HEAD(&obj->messages, list))) {
00197       if (tmp->from)
00198          free(tmp->from);
00199       if (tmp->message)
00200          free(tmp->message);
00201    }
00202    AST_LIST_HEAD_DESTROY(&obj->messages);
00203    free(obj);
00204 }
00205 
00206 /*!
00207  * \brief Deletes the aji_buddy data structure.
00208  * \param obj is the structure we will delete.
00209  * \return void.
00210  */
00211 static void aji_buddy_destroy(struct aji_buddy *obj)
00212 {
00213    struct aji_resource *tmp;
00214 
00215    while ((tmp = obj->resources)) {
00216       obj->resources = obj->resources->next;
00217       free(tmp->description);
00218       free(tmp);
00219    }
00220 
00221    free(obj);
00222 }
00223 
00224 /*!
00225  * \brief Find version in XML stream and populate our capabilities list
00226  * \param node the node attribute in the caps element we'll look for or add to 
00227  * our list
00228  * \param version the version attribute in the caps element we'll look for or 
00229  * add to our list
00230  * \param pak the XML stanza we're processing
00231  * \return a pointer to the added or found aji_version structure
00232  */ 
00233 static struct aji_version *aji_find_version(char *node, char *version, ikspak *pak)
00234 {
00235    struct aji_capabilities *list = NULL;
00236    struct aji_version *res = NULL;
00237 
00238    list = capabilities;
00239 
00240    if(!node)
00241       node = pak->from->full;
00242    if(!version)
00243       version = "none supplied.";
00244    while(list) {
00245       if(!strcasecmp(list->node, node)) {
00246          res = list->versions;
00247          while(res) {
00248              if(!strcasecmp(res->version, version))
00249                 return res;
00250              res = res->next;
00251          }
00252          /* Specified version not found. Let's add it to 
00253             this node in our capabilities list */
00254          if(!res) {
00255             res = (struct aji_version *)malloc(sizeof(struct aji_version));
00256             if(!res) {
00257                ast_log(LOG_ERROR, "Out of memory!\n");
00258                return NULL;
00259             }
00260             res->jingle = 0;
00261             res->parent = list;
00262             ast_copy_string(res->version, version, sizeof(res->version));
00263             res->next = list->versions;
00264             list->versions = res;
00265             return res;
00266          }
00267       }
00268       list = list->next;
00269    }
00270    /* Specified node not found. Let's add it our capabilities list */
00271    if(!list) {
00272       list = (struct aji_capabilities *)malloc(sizeof(struct aji_capabilities));
00273       if(!list) {
00274          ast_log(LOG_ERROR, "Out of memory!\n");
00275          return NULL;
00276       }
00277       res = (struct aji_version *)malloc(sizeof(struct aji_version));
00278       if(!res) {
00279          ast_log(LOG_ERROR, "Out of memory!\n");
00280          ast_free(list);
00281          return NULL;
00282       }
00283       ast_copy_string(list->node, node, sizeof(list->node));
00284       ast_copy_string(res->version, version, sizeof(res->version));
00285       res->jingle = 0;
00286       res->parent = list;
00287       res->next = NULL;
00288       list->versions = res;
00289       list->next = capabilities;
00290       capabilities = list;
00291    }
00292    return res;
00293 }
00294 
00295 static struct aji_resource *aji_find_resource(struct aji_buddy *buddy, char *name)
00296 {
00297    struct aji_resource *res = NULL;
00298    if (!buddy || !name)
00299       return res;
00300    res = buddy->resources;
00301    while (res) {
00302       if (!strcasecmp(res->resource, name)) {
00303          break;
00304       }
00305       res = res->next;
00306    }
00307    return res;
00308 }
00309 
00310 static int gtalk_yuck(iks *node)
00311 {
00312    if (iks_find_with_attrib(node, "c", "node", "http://www.google.com/xmpp/client/caps"))
00313       return 1;
00314    return 0;
00315 }
00316 
00317 /*!
00318  * \brief Detects the highest bit in a number.
00319  * \param Number you want to have evaluated.
00320  * \return the highest power of 2 that can go into the number.
00321  */
00322 static int aji_highest_bit(int number)
00323 {
00324    int x = sizeof(number) * 8 - 1;
00325    if (!number)
00326       return 0;
00327    for (; x > 0; x--) {
00328       if (number & (1 << x))
00329          break;
00330    }
00331    return (1 << x);
00332 }
00333 
00334 static iks *jabber_make_auth(iksid * id, const char *pass, const char *sid)
00335 {
00336    iks *x, *y;
00337    x = iks_new("iq");
00338    iks_insert_attrib(x, "type", "set");
00339    y = iks_insert(x, "query");
00340    iks_insert_attrib(y, "xmlns", IKS_NS_AUTH);
00341    iks_insert_cdata(iks_insert(y, "username"), id->user, 0);
00342    iks_insert_cdata(iks_insert(y, "resource"), id->resource, 0);
00343    if (sid) {
00344       char buf[41];
00345       char sidpass[100];
00346       snprintf(sidpass, sizeof(sidpass), "%s%s", sid, pass);
00347       ast_sha1_hash(buf, sidpass);
00348       iks_insert_cdata(iks_insert(y, "digest"), buf, 0);
00349    } else {
00350       iks_insert_cdata(iks_insert(y, "password"), pass, 0);
00351    }
00352    return x;
00353 }
00354 
00355 /*!
00356  * \brief Dial plan function status(). puts the status of watched user 
00357    into a channel variable.
00358  * \param channel, and username,watched user, status var
00359  * \return 0.
00360  */
00361 static int aji_status_exec(struct ast_channel *chan, void *data)
00362 {
00363    struct aji_client *client = NULL;
00364    struct aji_buddy *buddy = NULL;
00365    struct aji_resource *r = NULL;
00366    char *s = NULL, *sender = NULL, *jid = NULL, *screenname = NULL, *resource = NULL, *variable = NULL;
00367    int stat = 7;
00368    char status[2];
00369 
00370    if (!data) {
00371       ast_log(LOG_ERROR, "This application requires arguments.\n");
00372       return 0;
00373    }
00374    s = ast_strdupa(data);
00375    if (s) {
00376       sender = strsep(&s, "|");
00377       if (sender && (sender[0] != '\0')) {
00378          jid = strsep(&s, "|");
00379          if (jid && (jid[0] != '\0')) {
00380             variable = s;
00381          } else {
00382             ast_log(LOG_ERROR, "Bad arguments\n");
00383             return -1;
00384          }
00385       }
00386    }
00387 
00388    if(!strchr(jid, '/')) {
00389       resource = NULL;
00390    } else {
00391       screenname = strsep(&jid, "/");
00392       resource = jid;
00393    }
00394    client = ast_aji_get_client(sender);
00395    if (!client) {
00396       ast_log(LOG_WARNING, "Could not find sender connection: %s\n", sender);
00397       return -1;
00398    }
00399    if(!&client->buddies) {
00400       ast_log(LOG_WARNING, "No buddies for connection : %s\n", sender);
00401       return -1;
00402    }
00403    buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, resource ? screenname: jid);
00404    if (!buddy) {
00405       ast_log(LOG_WARNING, "Could not find buddy in list : %s\n", resource ? screenname : jid);
00406       return -1;
00407    }
00408    r = aji_find_resource(buddy, resource);
00409    if(!r && buddy->resources) 
00410       r = buddy->resources;
00411    if(!r)
00412       ast_log(LOG_NOTICE, "Resource %s of buddy %s not found \n", resource, screenname);
00413    else
00414       stat = r->status;
00415    sprintf(status, "%d", stat);
00416    pbx_builtin_setvar_helper(chan, variable, status);
00417    return 0;
00418 }
00419 
00420 /*!
00421  * \brief Dial plan function to send a message.
00422  * \param channel, and data, data is sender, reciever, message.
00423  * \return 0.
00424  */
00425 static int aji_send_exec(struct ast_channel *chan, void *data)
00426 {
00427    struct aji_client *client = NULL;
00428 
00429    char *s = NULL, *sender = NULL, *recipient = NULL, *message = NULL;
00430 
00431    if (!data) {
00432       ast_log(LOG_ERROR, "This application requires arguments.\n");
00433       return 0;
00434    }
00435    s = ast_strdupa(data);
00436    if (s) {
00437       sender = strsep(&s, "|");
00438       if (sender && (sender[0] != '\0')) {
00439          recipient = strsep(&s, "|");
00440          if (recipient && (recipient[0] != '\0')) {
00441             message = s;
00442          } else {
00443             ast_log(LOG_ERROR, "Bad arguments: %s\n", (char *) data);
00444             return -1;
00445          }
00446       }
00447    }
00448    if (!(client = ast_aji_get_client(sender))) {
00449       ast_log(LOG_WARNING, "Could not find sender connection: %s\n", sender);
00450       return -1;
00451    }
00452    if (strchr(recipient, '@') && message)
00453       ast_aji_send(client, recipient, message);
00454    return 0;
00455 }
00456 
00457 /*!
00458  * \brief the debug loop.
00459  * \param aji_client structure, xml data as string, size of string, direction of packet, 1 for inbound 0 for outbound.
00460  */
00461 static void aji_log_hook(void *data, const char *xmpp, size_t size, int is_incoming)
00462 {
00463    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00464    manager_event(EVENT_FLAG_USER, "JabberEvent", "Account: %s\r\nPacket: %s\r\n", client->name, xmpp);
00465 
00466    if (client->debug) {
00467       if (is_incoming)
00468          ast_verbose("\nJABBER: %s INCOMING: %s\n", client->name, xmpp);
00469       else {
00470          if( strlen(xmpp) == 1) {
00471             if(option_debug > 2  && xmpp[0] == ' ')
00472             ast_verbose("\nJABBER: Keep alive packet\n");
00473          } else
00474             ast_verbose("\nJABBER: %s OUTGOING: %s\n", client->name, xmpp);
00475       }
00476 
00477    }
00478    ASTOBJ_UNREF(client, aji_client_destroy);
00479 }
00480 
00481 /*!
00482  * \brief The action hook parses the inbound packets, constantly running.
00483  * \param data aji client structure 
00484  * \param type type of packet 
00485  * \param node the actual packet.
00486  * \return IKS_OK or IKS_HOOK .
00487  */
00488 static int aji_act_hook(void *data, int type, iks *node)
00489 {
00490    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00491    ikspak *pak = NULL;
00492    iks *auth = NULL;
00493 
00494    if(!node) {
00495       ast_log(LOG_ERROR, "aji_act_hook was called with out a packet\n"); /* most likely cause type is IKS_NODE_ERROR lost connection */
00496       ASTOBJ_UNREF(client, aji_client_destroy);
00497       return IKS_HOOK;
00498    }
00499 
00500    if (client->state == AJI_DISCONNECTING) {
00501       ASTOBJ_UNREF(client, aji_client_destroy);
00502       return IKS_HOOK;
00503    }
00504 
00505    pak = iks_packet(node);
00506 
00507    if (!client->component) { /*client */
00508       switch (type) {
00509       case IKS_NODE_START:
00510          if (client->usetls && !iks_is_secure(client->p)) {
00511             if (iks_has_tls()) {
00512                iks_start_tls(client->p);
00513                tls_initialized = TRUE;
00514             } else
00515                ast_log(LOG_ERROR, "gnuTLS not installed. You need to recompile the Iksemel library with gnuTLS support\n");
00516             break;
00517          }
00518          if (!client->usesasl) {
00519             iks_filter_add_rule(client->f, aji_client_connect, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->mid, IKS_RULE_DONE);
00520             auth = jabber_make_auth(client->jid, client->password, iks_find_attrib(node, "id"));
00521             if (auth) {
00522                iks_insert_attrib(auth, "id", client->mid);
00523                iks_insert_attrib(auth, "to", client->jid->server);
00524                ast_aji_increment_mid(client->mid);
00525                iks_send(client->p, auth);
00526                iks_delete(auth);
00527             } else
00528                ast_log(LOG_ERROR, "Out of memory.\n");
00529          }
00530          break;
00531 
00532       case IKS_NODE_NORMAL:
00533          if (!strcmp("stream:features", iks_name(node))) {
00534             int features = 0;
00535             features = iks_stream_features(node);
00536             if (client->usesasl) {
00537                if (client->usetls && !iks_is_secure(client->p))
00538                   break;
00539                if (client->authorized) {
00540                   if (features & IKS_STREAM_BIND) {
00541                      iks_filter_add_rule (client->f, aji_client_connect, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_DONE);
00542                      auth = iks_make_resource_bind(client->jid);
00543                      if (auth) {
00544                         iks_insert_attrib(auth, "id", client->mid);
00545                         ast_aji_increment_mid(client->mid);
00546                         iks_send(client->p, auth);
00547                         iks_delete(auth);
00548                      } else {
00549                         ast_log(LOG_ERROR, "Out of memory.\n");
00550                         break;
00551                      }
00552                   }
00553                   if (features & IKS_STREAM_SESSION) {
00554                      iks_filter_add_rule (client->f, aji_client_connect, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, "auth", IKS_RULE_DONE);
00555                      auth = iks_make_session();
00556                      if (auth) {
00557                         iks_insert_attrib(auth, "id", "auth");
00558                         ast_aji_increment_mid(client->mid);
00559                         iks_send(client->p, auth);
00560                         iks_delete(auth);
00561                      } else {
00562                         ast_log(LOG_ERROR, "Out of memory.\n");
00563                      }
00564                   }
00565                } else {
00566                   if (!client->jid->user) {
00567                      ast_log(LOG_ERROR, "Malformed Jabber ID : %s (domain missing?)\n", client->jid->full);
00568                      break;
00569                   }
00570                   features = aji_highest_bit(features);
00571                   if (features == IKS_STREAM_SASL_MD5)
00572                      iks_start_sasl(client->p, IKS_SASL_DIGEST_MD5, client->jid->user, client->password);
00573                   else {
00574                      if (features == IKS_STREAM_SASL_PLAIN) {
00575                         iks *x = NULL;
00576                         x = iks_new("auth");
00577                         if (x) {
00578                            int len = strlen(client->jid->user) + strlen(client->password) + 3;
00579                            /* XXX Check return values XXX */
00580                            char *s = ast_malloc(80 + len);
00581                            char *base64 = ast_malloc(80 + len * 2);
00582                            iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_SASL);
00583                            iks_insert_attrib(x, "mechanism", "PLAIN");
00584                            sprintf(s, "%c%s%c%s", 0, client->jid->user, 0, client->password);
00585                               
00586                            /* exclude the NULL training byte from the base64 encoding operation
00587                               as some XMPP servers will refuse it.
00588                               The format for authentication is [authzid]\0authcid\0password
00589                               not [authzid]\0authcid\0password\0 */
00590                            ast_base64encode(base64, (const unsigned char *) s, len - 1, len * 2);
00591                            iks_insert_cdata(x, base64, 0);
00592                            iks_send(client->p, x);
00593                            iks_delete(x);
00594                            if (base64)
00595                               free(base64);
00596                            if (s)
00597                               free(s);
00598                         } else {
00599                            ast_log(LOG_ERROR, "Out of memory.\n");
00600                         }
00601                      }
00602                   }
00603                }
00604             }
00605          } else if (!strcmp("failure", iks_name(node))) {
00606             ast_log(LOG_ERROR, "JABBER: encryption failure. possible bad password.\n");
00607          } else if (!strcmp("success", iks_name(node))) {
00608             client->authorized = 1;
00609             iks_send_header(client->p, client->jid->server);
00610          }
00611          break;
00612       case IKS_NODE_ERROR: 
00613             ast_log(LOG_ERROR, "JABBER: Node Error\n");
00614             ASTOBJ_UNREF(client, aji_client_destroy);
00615             return IKS_HOOK;
00616             break;
00617       case IKS_NODE_STOP: 
00618             ast_log(LOG_WARNING, "JABBER: Disconnected\n");
00619             ASTOBJ_UNREF(client, aji_client_destroy);
00620             return IKS_HOOK;
00621             break;
00622       }
00623    } else if (client->state != AJI_CONNECTED && client->component) {
00624       switch (type) {
00625       case IKS_NODE_START:
00626          if (client->state == AJI_DISCONNECTED) {
00627             char secret[160], shasum[320], *handshake;
00628 
00629             sprintf(secret, "%s%s", pak->id, client->password);
00630             ast_sha1_hash(shasum, secret);
00631             handshake = NULL;
00632             asprintf(&handshake, "<handshake>%s</handshake>", shasum);
00633             if (handshake) {
00634                iks_send_raw(client->p, handshake);
00635                free(handshake);
00636                handshake = NULL;
00637             }
00638             client->state = AJI_CONNECTING;
00639             if(iks_recv(client->p,1) == 2) /*XXX proper result for iksemel library on iks_recv of <handshake/> XXX*/
00640                client->state = AJI_CONNECTED;
00641             else
00642                ast_log(LOG_WARNING,"Jabber didn't seem to handshake, failed to authenicate.\n");
00643             break;
00644          }
00645          break;
00646 
00647       case IKS_NODE_NORMAL:
00648          break;
00649 
00650       case IKS_NODE_ERROR:
00651          ast_log(LOG_ERROR, "JABBER: Node Error\n");
00652          ASTOBJ_UNREF(client, aji_client_destroy);
00653          return IKS_HOOK;
00654 
00655       case IKS_NODE_STOP:
00656          ast_log(LOG_WARNING, "JABBER: Disconnected\n");
00657          ASTOBJ_UNREF(client, aji_client_destroy);
00658          return IKS_HOOK;
00659       }
00660    }
00661 
00662    switch (pak->type) {
00663    case IKS_PAK_NONE:
00664       if (option_debug)
00665          ast_log(LOG_DEBUG, "JABBER: I Don't know what to do with you NONE\n");
00666       break;
00667    case IKS_PAK_MESSAGE:
00668       aji_handle_message(client, pak);
00669       if (option_debug)
00670          ast_log(LOG_DEBUG, "JABBER: I Don't know what to do with you MESSAGE\n");
00671       break;
00672    case IKS_PAK_PRESENCE:
00673       aji_handle_presence(client, pak);
00674       if (option_debug)
00675          ast_log(LOG_DEBUG, "JABBER: I Do know how to handle presence!!\n");
00676       break;
00677    case IKS_PAK_S10N:
00678       aji_handle_subscribe(client, pak);
00679       if (option_debug)
00680          ast_log(LOG_DEBUG, "JABBER: I Dont know S10N subscribe!!\n");
00681       break;
00682    case IKS_PAK_IQ:
00683       if (option_debug)
00684          ast_log(LOG_DEBUG, "JABBER: I Dont have an IQ!!!\n");
00685       aji_handle_iq(client, node);
00686       break;
00687    default:
00688       if (option_debug)
00689          ast_log(LOG_DEBUG, "JABBER: I Dont know %i\n", pak->type);
00690       break;
00691    }
00692    
00693    iks_filter_packet(client->f, pak);
00694 
00695    if (node)
00696       iks_delete(node);
00697 
00698    ASTOBJ_UNREF(client, aji_client_destroy);
00699    return IKS_OK;
00700 }
00701 
00702 static int aji_register_approve_handler(void *data, ikspak *pak)
00703 {
00704    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00705    iks *iq = NULL, *presence = NULL, *x = NULL;
00706 
00707    iq = iks_new("iq");
00708    presence = iks_new("presence");
00709    x = iks_new("x");
00710    if (client && iq && presence && x) {
00711       if (!iks_find(pak->query, "remove")) {
00712          iks_insert_attrib(iq, "from", client->jid->full);
00713          iks_insert_attrib(iq, "to", pak->from->full);
00714          iks_insert_attrib(iq, "id", pak->id);
00715          iks_insert_attrib(iq, "type", "result");
00716          iks_send(client->p, iq);
00717 
00718          iks_insert_attrib(presence, "from", client->jid->full);
00719          iks_insert_attrib(presence, "to", pak->from->partial);
00720          iks_insert_attrib(presence, "id", client->mid);
00721          ast_aji_increment_mid(client->mid);
00722          iks_insert_attrib(presence, "type", "subscribe");
00723          iks_insert_attrib(x, "xmlns", "vcard-temp:x:update");
00724          iks_insert_node(presence, x);
00725          iks_send(client->p, presence); 
00726       }
00727    } else {
00728       ast_log(LOG_ERROR, "Out of memory.\n");
00729    }
00730 
00731    if (iq)
00732       iks_delete(iq);
00733    if(presence)
00734       iks_delete(presence);
00735    if (x)
00736       iks_delete(x);
00737    ASTOBJ_UNREF(client, aji_client_destroy);
00738    return IKS_FILTER_EAT;
00739 }
00740 
00741 static int aji_register_query_handler(void *data, ikspak *pak)
00742 {
00743    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00744    struct aji_buddy *buddy = NULL; 
00745    char *node = NULL;
00746 
00747    client = (struct aji_client *) data;
00748 
00749    buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
00750    if (!buddy) {
00751       iks *iq = NULL, *query = NULL, *error = NULL, *notacceptable = NULL;
00752       ast_verbose("Someone.... %s tried to register but they aren't allowed\n", pak->from->partial);
00753       iq = iks_new("iq");
00754       query = iks_new("query");
00755       error = iks_new("error");
00756       notacceptable = iks_new("not-acceptable");
00757       if(iq && query && error && notacceptable) {
00758          iks_insert_attrib(iq, "type", "error");
00759          iks_insert_attrib(iq, "from", client->user);
00760          iks_insert_attrib(iq, "to", pak->from->full);
00761          iks_insert_attrib(iq, "id", pak->id);
00762          iks_insert_attrib(query, "xmlns", "jabber:iq:register");
00763          iks_insert_attrib(error, "code" , "406");
00764          iks_insert_attrib(error, "type", "modify");
00765          iks_insert_attrib(notacceptable, "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas");
00766          iks_insert_node(iq, query);
00767          iks_insert_node(iq, error);
00768          iks_insert_node(error, notacceptable);
00769          iks_send(client->p, iq);
00770       } else {
00771          ast_log(LOG_ERROR, "Out of memory.\n");
00772       }
00773       if (iq)
00774          iks_delete(iq);
00775       if (query)
00776          iks_delete(query);
00777       if (error)
00778          iks_delete(error);
00779       if (notacceptable)
00780          iks_delete(notacceptable);
00781    } else   if (!(node = iks_find_attrib(pak->query, "node"))) {
00782       iks *iq = NULL, *query = NULL, *instructions = NULL;
00783       char *explain = "Welcome to Asterisk - the Open Source PBX.\n";
00784       iq = iks_new("iq");
00785       query = iks_new("query");
00786       instructions = iks_new("instructions");
00787       if (iq && query && instructions && client) {
00788          iks_insert_attrib(iq, "from", client->user);
00789          iks_insert_attrib(iq, "to", pak->from->full);
00790          iks_insert_attrib(iq, "id", pak->id);
00791          iks_insert_attrib(iq, "type", "result");
00792          iks_insert_attrib(query, "xmlns", "jabber:iq:register");
00793          iks_insert_cdata(instructions, explain, 0);
00794          iks_insert_node(iq, query);
00795          iks_insert_node(query, instructions);
00796          iks_send(client->p, iq);
00797       } else {
00798          ast_log(LOG_ERROR, "Out of memory.\n");
00799       }
00800       if (iq)
00801          iks_delete(iq);
00802       if (query)
00803          iks_delete(query);
00804       if (instructions)
00805          iks_delete(instructions);
00806    }
00807    ASTOBJ_UNREF(client, aji_client_destroy);
00808    return IKS_FILTER_EAT;
00809 }
00810 
00811 static int aji_ditems_handler(void *data, ikspak *pak)
00812 {
00813    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00814    char *node = NULL;
00815 
00816    if (!(node = iks_find_attrib(pak->query, "node"))) {
00817       iks *iq = NULL, *query = NULL, *item = NULL;
00818       iq = iks_new("iq");
00819       query = iks_new("query");
00820       item = iks_new("item");
00821 
00822       if (iq && query && item) {
00823          iks_insert_attrib(iq, "from", client->user);
00824          iks_insert_attrib(iq, "to", pak->from->full);
00825          iks_insert_attrib(iq, "id", pak->id);
00826          iks_insert_attrib(iq, "type", "result");
00827          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
00828          iks_insert_attrib(item, "node", "http://jabber.org/protocol/commands");
00829          iks_insert_attrib(item, "name", "Million Dollar Asterisk Commands");
00830          iks_insert_attrib(item, "jid", client->user);
00831 
00832          iks_insert_node(iq, query);
00833          iks_insert_node(query, item);
00834          iks_send(client->p, iq);
00835       } else {
00836          ast_log(LOG_ERROR, "Out of memory.\n");
00837       }
00838       if (iq)
00839          iks_delete(iq);
00840       if (query)
00841          iks_delete(query);
00842       if (item)
00843          iks_delete(item);
00844 
00845    } else if (!strcasecmp(node, "http://jabber.org/protocol/commands")) {
00846       iks *iq, *query, *confirm;
00847       iq = iks_new("iq");
00848       query = iks_new("query");
00849       confirm = iks_new("item");
00850       if (iq && query && confirm && client) {
00851          iks_insert_attrib(iq, "from", client->user);
00852          iks_insert_attrib(iq, "to", pak->from->full);
00853          iks_insert_attrib(iq, "id", pak->id);
00854          iks_insert_attrib(iq, "type", "result");
00855          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
00856          iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
00857          iks_insert_attrib(confirm, "node", "confirmaccount");
00858          iks_insert_attrib(confirm, "name", "Confirm AIM account");
00859          iks_insert_attrib(confirm, "jid", "blog.astjab.org");
00860 
00861          iks_insert_node(iq, query);
00862          iks_insert_node(query, confirm);
00863          iks_send(client->p, iq);
00864       } else {
00865          ast_log(LOG_ERROR, "Out of memory.\n");
00866       }
00867       if (iq)
00868          iks_delete(iq);
00869       if (query)
00870          iks_delete(query);
00871       if (confirm)
00872          iks_delete(confirm);
00873 
00874    } else if (!strcasecmp(node, "confirmaccount")) {
00875       iks *iq = NULL, *query = NULL, *feature = NULL;
00876 
00877       iq = iks_new("iq");
00878       query = iks_new("query");
00879       feature = iks_new("feature");
00880 
00881       if (iq && query && feature && client) {
00882          iks_insert_attrib(iq, "from", client->user);
00883          iks_insert_attrib(iq, "to", pak->from->full);
00884          iks_insert_attrib(iq, "id", pak->id);
00885          iks_insert_attrib(iq, "type", "result");
00886          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
00887          iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
00888          iks_insert_node(iq, query);
00889          iks_insert_node(query, feature);
00890          iks_send(client->p, iq);
00891       } else {
00892          ast_log(LOG_ERROR, "Out of memory.\n");
00893       }
00894       if (iq)
00895          iks_delete(iq);
00896       if (query)
00897          iks_delete(query);
00898       if (feature)
00899          iks_delete(feature);
00900    }
00901 
00902    ASTOBJ_UNREF(client, aji_client_destroy);
00903    return IKS_FILTER_EAT;
00904 
00905 }
00906 
00907 static int aji_client_info_handler(void *data, ikspak *pak)
00908 {
00909    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00910    struct aji_resource *resource = NULL;
00911    struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
00912 
00913    resource = aji_find_resource(buddy, pak->from->resource);
00914    if (pak->subtype == IKS_TYPE_RESULT) {
00915       if (!resource) {
00916          ast_log(LOG_NOTICE,"JABBER: Received client info from %s when not requested.\n", pak->from->full);
00917          ASTOBJ_UNREF(client, aji_client_destroy);
00918          return IKS_FILTER_EAT;
00919       }
00920       if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
00921          resource->cap->jingle = 1;
00922       } else
00923          resource->cap->jingle = 0;
00924    } else if (pak->subtype == IKS_TYPE_GET) {
00925       iks *iq, *disco, *ident, *google, *query;
00926       iq = iks_new("iq");
00927       query = iks_new("query");
00928       ident = iks_new("identity");
00929       disco = iks_new("feature");
00930       google = iks_new("feature");
00931       if (iq && ident && disco && google) {
00932          iks_insert_attrib(iq, "from", client->jid->full);
00933          iks_insert_attrib(iq, "to", pak->from->full);
00934          iks_insert_attrib(iq, "type", "result");
00935          iks_insert_attrib(iq, "id", pak->id);
00936          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
00937          iks_insert_attrib(ident, "category", "client");
00938          iks_insert_attrib(ident, "type", "pc");
00939          iks_insert_attrib(ident, "name", "asterisk");
00940          iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco#info");
00941          iks_insert_attrib(google, "var", "http://www.google.com/xmpp/protocol/voice/v1");
00942          iks_insert_node(iq, query);
00943          iks_insert_node(query, ident);
00944          iks_insert_node(query, google);
00945          iks_insert_node(query, disco);
00946          iks_send(client->p, iq);
00947       } else
00948          ast_log(LOG_ERROR, "Out of Memory.\n");
00949       if (iq)
00950          iks_delete(iq);
00951       if (query)
00952          iks_delete(query);
00953       if (ident)
00954          iks_delete(ident);
00955       if (google)
00956          iks_delete(google);
00957       if (disco)
00958          iks_delete(disco);
00959    } else if (pak->subtype == IKS_TYPE_ERROR) {
00960       ast_log(LOG_NOTICE, "User %s does not support discovery.\n", pak->from->full);
00961    }
00962    ASTOBJ_UNREF(client, aji_client_destroy);
00963    return IKS_FILTER_EAT;
00964 }
00965 
00966 static int aji_dinfo_handler(void *data, ikspak *pak)
00967 {
00968    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00969    char *node = NULL;
00970    struct aji_resource *resource = NULL;
00971    struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
00972 
00973    resource = aji_find_resource(buddy, pak->from->resource);
00974    if (pak->subtype == IKS_TYPE_ERROR) {
00975       ast_log(LOG_WARNING, "Recieved error from a client, turn on jabber debug!\n");
00976       return IKS_FILTER_EAT;
00977    }
00978    if (pak->subtype == IKS_TYPE_RESULT) {
00979       if (!resource) {
00980          ast_log(LOG_NOTICE,"JABBER: Received client info from %s when not requested.\n", pak->from->full);
00981