Tue Apr 28 22:50:45 2009

Asterisk developer's documentation


res_jabber.c File Reference

A resource for interfacing asterisk directly as a client or a component to a jabber compliant server. More...

#include "asterisk.h"
#include <stdlib.h>
#include <stdio.h>
#include <iksemel.h>
#include "asterisk/channel.h"
#include "asterisk/jabber.h"
#include "asterisk/file.h"
#include "asterisk/config.h"
#include "asterisk/callerid.h"
#include "asterisk/lock.h"
#include "asterisk/logger.h"
#include "asterisk/options.h"
#include "asterisk/cli.h"
#include "asterisk/app.h"
#include "asterisk/pbx.h"
#include "asterisk/md5.h"
#include "asterisk/acl.h"
#include "asterisk/utils.h"
#include "asterisk/module.h"
#include "asterisk/astobj.h"
#include "asterisk/astdb.h"
#include "asterisk/manager.h"

Go to the source code of this file.

Defines

#define FALSE   0
#define JABBER_CONFIG   "jabber.conf"
#define TRUE   1

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int aji_act_hook (void *data, int type, iks *node)
 The action hook parses the inbound packets, constantly running.
static void aji_buddy_destroy (struct aji_buddy *obj)
 Deletes the aji_buddy data structure.
static int aji_client_connect (void *data, ikspak *pak)
 connects as a client to jabber server.
static void aji_client_destroy (struct aji_client *obj)
 Deletes the aji_client data structure.
static int aji_client_info_handler (void *data, ikspak *pak)
static int aji_client_initialize (struct aji_client *client)
 prepares client for connect.
static int aji_component_initialize (struct aji_client *client)
 prepares component for connect.
static int aji_create_buddy (char *label, struct aji_client *client)
 creates transport. creates buddy.
static int aji_create_client (char *label, struct ast_variable *var, int debug)
 creates aji_client structure.
static int aji_dinfo_handler (void *data, ikspak *pak)
static int aji_ditems_handler (void *data, ikspak *pak)
static int aji_do_debug (int fd, int argc, char *argv[])
 turnon console debugging.
static int aji_do_reload (int fd, int argc, char *argv[])
 reload jabber module.
static int aji_filter_roster (void *data, ikspak *pak)
 filters the roster packet we get back from server.
static struct aji_resourceaji_find_resource (struct aji_buddy *buddy, char *name)
static struct aji_versionaji_find_version (char *node, char *version, ikspak *pak)
 Find version in XML stream and populate our capabilities list.
static int aji_get_roster (struct aji_client *client)
static void aji_handle_iq (struct aji_client *client, iks *node)
 Handles <iq> tags.
static void aji_handle_message (struct aji_client *client, ikspak *pak)
 Handles presence packets.
static void aji_handle_presence (struct aji_client *client, ikspak *pak)
static void aji_handle_subscribe (struct aji_client *client, ikspak *pak)
 handles subscription requests.
static int aji_highest_bit (int number)
 Detects the highest bit in a number.
static int aji_load_config (void)
 load config file.
static void aji_log_hook (void *data, const char *xmpp, size_t size, int is_incoming)
 the debug loop.
static int aji_no_debug (int fd, int argc, char *argv[])
 turnoff console debugging.
static void aji_pruneregister (struct aji_client *client)
 attempts to register to a transport. attempts to register to a transport step 2. goes through roster and prunes users not needed in list, or adds them accordingly.
static int aji_reconnect (struct aji_client *client)
static void * aji_recv_loop (void *data)
 receive message loop.
static int aji_register_approve_handler (void *data, ikspak *pak)
static int aji_register_query_handler (void *data, ikspak *pak)
static int aji_reload (void)
static int aji_send_exec (struct ast_channel *chan, void *data)
 Dial plan function to send a message.
static void aji_set_presence (struct aji_client *client, char *to, char *from, int level, char *desc)
 set presence of client.
static int aji_show_clients (int fd, int argc, char *argv[])
 show client status.
static int aji_status_exec (struct ast_channel *chan, void *data)
 Dial plan function status(). puts the status of watched user into a channel variable.
static int aji_test (int fd, int argc, char *argv[])
 send test message for debugging.
int ast_aji_create_chat (struct aji_client *client, char *room, char *server, char *topic)
 create a chatroom.
int ast_aji_disconnect (struct aji_client *client)
 disconnect from jabber server.
aji_clientast_aji_get_client (const char *name)
 grab a aji_client structure by label name or JID (without the resource string)
aji_client_containerast_aji_get_clients (void)
void ast_aji_increment_mid (char *mid)
 increments the mid field for messages and other events.
int ast_aji_invite_chat (struct aji_client *client, char *user, char *room, char *message)
 invite to a chatroom.
int ast_aji_join_chat (struct aji_client *client, char *room)
 join a chatroom.
int ast_aji_send (struct aji_client *client, const char *address, const char *message)
 sends messages.
static int gtalk_yuck (iks *node)
static iks * jabber_make_auth (iksid *id, const char *pass, const char *sid)
static int load_module (void)
static int manager_jabber_send (struct mansession *s, const struct message *m)
 Send a Jabber Message via call from the Manager.
static int reload (void)
static int unload_module (void)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_BUILDSUM, .description = "AJI - Asterisk Jabber Interface" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "f450f61f60e761b3aa089ebed76ca8a5" , .load = load_module, .unload = unload_module, .reload = reload, }
static struct ast_cli_entry aji_cli []
static char * ajisend_descrip
static char * ajisend_synopsis = "JabberSend(jabber,screenname,message)"
static char * ajistatus_descrip
static char * ajistatus_synopsis = "JabberStatus(Jabber,ScreenName,Variable)"
static char * app_ajisend = "JabberSend"
static char * app_ajistatus = "JabberStatus"
static const struct ast_module_infoast_module_info = &__mod_info
aji_capabilitiescapabilities = NULL
aji_client_container clients
static char debug_usage []
static struct ast_flags globalflags = { AJI_AUTOPRUNE | AJI_AUTOREGISTER }
 Global flags, initialized to default values.
static char mandescr_jabber_send []
static char no_debug_usage []
static char reload_usage []
static char test_usage []
static int tls_initialized = FALSE


Detailed Description

A resource for interfacing asterisk directly as a client or a component to a jabber compliant server.

Todo:
If you unload this module, chan_gtalk/jingle will be dead. How do we handle that?

If you have TLS, you can't unload this module. See bug #9738. This needs to be fixed, but the bug is in the unmantained Iksemel library

Definition in file res_jabber.c.


Define Documentation

#define FALSE   0

Definition at line 64 of file res_jabber.c.

#define JABBER_CONFIG   "jabber.conf"

Definition at line 61 of file res_jabber.c.

Referenced by aji_load_config().

#define TRUE   1

Definition at line 68 of file res_jabber.c.


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 2518 of file res_jabber.c.

static void __unreg_module ( void   )  [static]

Definition at line 2518 of file res_jabber.c.

static int aji_act_hook ( void *  data,
int  type,
iks *  node 
) [static]

The action hook parses the inbound packets, constantly running.

Parameters:
data aji client structure
type type of packet
node the actual packet.
Returns:
IKS_OK or IKS_HOOK .

Definition at line 488 of file res_jabber.c.

References aji_client_connect(), aji_client_destroy(), AJI_CONNECTED, AJI_CONNECTING, AJI_DISCONNECTED, AJI_DISCONNECTING, aji_handle_iq(), aji_handle_message(), aji_handle_presence(), aji_handle_subscribe(), aji_highest_bit(), asprintf, ast_aji_increment_mid(), ast_base64encode(), ast_log(), ast_malloc, ast_sha1_hash(), ASTOBJ_REF, ASTOBJ_UNREF, aji_client::authorized, base64, aji_client::component, aji_client::f, free, jabber_make_auth(), aji_client::jid, len(), LOG_DEBUG, LOG_ERROR, LOG_WARNING, aji_client::mid, option_debug, aji_client::p, aji_client::password, s, secret, aji_client::state, TRUE, aji_client::usesasl, and aji_client::usetls.

Referenced by aji_create_client().

00489 {
00490    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00491    ikspak *pak = NULL;
00492    iks *auth = NULL;
00493 
00494    if(!node) {
00495       ast_log(LOG_ERROR, "aji_act_hook was called with out a packet\n"); /* most likely cause type is IKS_NODE_ERROR lost connection */
00496       ASTOBJ_UNREF(client, aji_client_destroy);
00497       return IKS_HOOK;
00498    }
00499 
00500    if (client->state == AJI_DISCONNECTING) {
00501       ASTOBJ_UNREF(client, aji_client_destroy);
00502       return IKS_HOOK;
00503    }
00504 
00505    pak = iks_packet(node);
00506 
00507    if (!client->component) { /*client */
00508       switch (type) {
00509       case IKS_NODE_START:
00510          if (client->usetls && !iks_is_secure(client->p)) {
00511             if (iks_has_tls()) {
00512                iks_start_tls(client->p);
00513                tls_initialized = TRUE;
00514             } else
00515                ast_log(LOG_ERROR, "gnuTLS not installed. You need to recompile the Iksemel library with gnuTLS support\n");
00516             break;
00517          }
00518          if (!client->usesasl) {
00519             iks_filter_add_rule(client->f, aji_client_connect, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->mid, IKS_RULE_DONE);
00520             auth = jabber_make_auth(client->jid, client->password, iks_find_attrib(node, "id"));
00521             if (auth) {
00522                iks_insert_attrib(auth, "id", client->mid);
00523                iks_insert_attrib(auth, "to", client->jid->server);
00524                ast_aji_increment_mid(client->mid);
00525                iks_send(client->p, auth);
00526                iks_delete(auth);
00527             } else
00528                ast_log(LOG_ERROR, "Out of memory.\n");
00529          }
00530          break;
00531 
00532       case IKS_NODE_NORMAL:
00533          if (!strcmp("stream:features", iks_name(node))) {
00534             int features = 0;
00535             features = iks_stream_features(node);
00536             if (client->usesasl) {
00537                if (client->usetls && !iks_is_secure(client->p))
00538                   break;
00539                if (client->authorized) {
00540                   if (features & IKS_STREAM_BIND) {
00541                      iks_filter_add_rule (client->f, aji_client_connect, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_DONE);
00542                      auth = iks_make_resource_bind(client->jid);
00543                      if (auth) {
00544                         iks_insert_attrib(auth, "id", client->mid);
00545                         ast_aji_increment_mid(client->mid);
00546                         iks_send(client->p, auth);
00547                         iks_delete(auth);
00548                      } else {
00549                         ast_log(LOG_ERROR, "Out of memory.\n");
00550                         break;
00551                      }
00552                   }
00553                   if (features & IKS_STREAM_SESSION) {
00554                      iks_filter_add_rule (client->f, aji_client_connect, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, "auth", IKS_RULE_DONE);
00555                      auth = iks_make_session();
00556                      if (auth) {
00557                         iks_insert_attrib(auth, "id", "auth");
00558                         ast_aji_increment_mid(client->mid);
00559                         iks_send(client->p, auth);
00560                         iks_delete(auth);
00561                      } else {
00562                         ast_log(LOG_ERROR, "Out of memory.\n");
00563                      }
00564                   }
00565                } else {
00566                   if (!client->jid->user) {
00567                      ast_log(LOG_ERROR, "Malformed Jabber ID : %s (domain missing?)\n", client->jid->full);
00568                      break;
00569                   }
00570                   features = aji_highest_bit(features);
00571                   if (features == IKS_STREAM_SASL_MD5)
00572                      iks_start_sasl(client->p, IKS_SASL_DIGEST_MD5, client->jid->user, client->password);
00573                   else {
00574                      if (features == IKS_STREAM_SASL_PLAIN) {
00575                         iks *x = NULL;
00576                         x = iks_new("auth");
00577                         if (x) {
00578                            int len = strlen(client->jid->user) + strlen(client->password) + 3;
00579                            /* XXX Check return values XXX */
00580                            char *s = ast_malloc(80 + len);
00581                            char *base64 = ast_malloc(80 + len * 2);
00582                            iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_SASL);
00583                            iks_insert_attrib(x, "mechanism", "PLAIN");
00584                            sprintf(s, "%c%s%c%s", 0, client->jid->user, 0, client->password);
00585                               
00586                            /* exclude the NULL training byte from the base64 encoding operation
00587                               as some XMPP servers will refuse it.
00588                               The format for authentication is [authzid]\0authcid\0password
00589                               not [authzid]\0authcid\0password\0 */
00590                            ast_base64encode(base64, (const unsigned char *) s, len - 1, len * 2);
00591                            iks_insert_cdata(x, base64, 0);
00592                            iks_send(client->p, x);
00593                            iks_delete(x);
00594                            if (base64)
00595                               free(base64);
00596                            if (s)
00597                               free(s);
00598                         } else {
00599                            ast_log(LOG_ERROR, "Out of memory.\n");
00600                         }
00601                      }
00602                   }
00603                }
00604             }
00605          } else if (!strcmp("failure", iks_name(node))) {
00606             ast_log(LOG_ERROR, "JABBER: encryption failure. possible bad password.\n");
00607          } else if (!strcmp("success", iks_name(node))) {
00608             client->authorized = 1;
00609             iks_send_header(client->p, client->jid->server);
00610          }
00611          break;
00612       case IKS_NODE_ERROR: 
00613             ast_log(LOG_ERROR, "JABBER: Node Error\n");
00614             ASTOBJ_UNREF(client, aji_client_destroy);
00615             return IKS_HOOK;
00616             break;
00617       case IKS_NODE_STOP: 
00618             ast_log(LOG_WARNING, "JABBER: Disconnected\n");
00619             ASTOBJ_UNREF(client, aji_client_destroy);
00620             return IKS_HOOK;
00621             break;
00622       }
00623    } else if (client->state != AJI_CONNECTED && client->component) {
00624       switch (type) {
00625       case IKS_NODE_START:
00626          if (client->state == AJI_DISCONNECTED) {
00627             char secret[160], shasum[320], *handshake;
00628 
00629             sprintf(secret, "%s%s", pak->id, client->password);
00630             ast_sha1_hash(shasum, secret);
00631             handshake = NULL;
00632             if (asprintf(&handshake, "<handshake>%s</handshake>", shasum) > 0) {
00633                iks_send_raw(client->p, handshake);
00634                free(handshake);
00635                handshake = NULL;
00636             }
00637             client->state = AJI_CONNECTING;
00638             if(iks_recv(client->p,1) == 2) /*XXX proper result for iksemel library on iks_recv of <handshake/> XXX*/
00639                client->state = AJI_CONNECTED;
00640             else
00641                ast_log(LOG_WARNING,"Jabber didn't seem to handshake, failed to authenicate.\n");
00642             break;
00643          }
00644          break;
00645 
00646       case IKS_NODE_NORMAL:
00647          break;
00648 
00649       case IKS_NODE_ERROR:
00650          ast_log(LOG_ERROR, "JABBER: Node Error\n");
00651          ASTOBJ_UNREF(client, aji_client_destroy);
00652          return IKS_HOOK;
00653 
00654       case IKS_NODE_STOP:
00655          ast_log(LOG_WARNING, "JABBER: Disconnected\n");
00656          ASTOBJ_UNREF(client, aji_client_destroy);
00657          return IKS_HOOK;
00658       }
00659    }
00660 
00661    switch (pak->type) {
00662    case IKS_PAK_NONE:
00663       if (option_debug)
00664          ast_log(LOG_DEBUG, "JABBER: I Don't know what to do with you NONE\n");
00665       break;
00666    case IKS_PAK_MESSAGE:
00667       aji_handle_message(client, pak);
00668       if (option_debug)
00669          ast_log(LOG_DEBUG, "JABBER: I Don't know what to do with you MESSAGE\n");
00670       break;
00671    case IKS_PAK_PRESENCE:
00672       aji_handle_presence(client, pak);
00673       if (option_debug)
00674          ast_log(LOG_DEBUG, "JABBER: I Do know how to handle presence!!\n");
00675       break;
00676    case IKS_PAK_S10N:
00677       aji_handle_subscribe(client, pak);
00678       if (option_debug)
00679          ast_log(LOG_DEBUG, "JABBER: I Dont know S10N subscribe!!\n");
00680       break;
00681    case IKS_PAK_IQ:
00682       if (option_debug)
00683          ast_log(LOG_DEBUG, "JABBER: I Dont have an IQ!!!\n");
00684       aji_handle_iq(client, node);
00685       break;
00686    default:
00687       if (option_debug)
00688          ast_log(LOG_DEBUG, "JABBER: I Dont know %i\n", pak->type);
00689       break;
00690    }
00691    
00692    iks_filter_packet(client->f, pak);
00693 
00694    if (node)
00695       iks_delete(node);
00696 
00697    ASTOBJ_UNREF(client, aji_client_destroy);
00698    return IKS_OK;
00699 }

static void aji_buddy_destroy ( struct aji_buddy obj  )  [static]

Deletes the aji_buddy data structure.

Parameters:
obj is the structure we will delete.
Returns:
void.

Definition at line 211 of file res_jabber.c.

References aji_resource::description, free, aji_resource::next, and aji_buddy::resources.

Referenced by aji_client_destroy(), aji_create_buddy(), and aji_handle_presence().

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 }

static int aji_client_connect ( void *  data,
ikspak *  pak 
) [static]

connects as a client to jabber server.

Parameters:
aji_client struct, and xml packet.
Returns:
res.

Definition at line 1855 of file res_jabber.c.

References aji_client_destroy(), AJI_CONNECTING, AJI_DISCONNECTED, aji_filter_roster(), aji_get_roster(), ast_log(), ASTOBJ_REF, ASTOBJ_UNREF, aji_client::component, aji_client::f, aji_client::jid, LOG_ERROR, aji_client::stack, and aji_client::state.

Referenced by aji_act_hook().

01856 {
01857    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01858    int res = 0;
01859 
01860    if (client) {
01861       if (client->state == AJI_DISCONNECTED) {
01862          iks_filter_add_rule(client->f, aji_filter_roster, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, "roster", IKS_RULE_DONE);
01863          client->state = AJI_CONNECTING;
01864          client->jid = (iks_find_cdata(pak->query, "jid")) ? iks_id_new(client->stack, iks_find_cdata(pak->query, "jid")) : client->jid;
01865          iks_filter_remove_hook(client->f, aji_client_connect);
01866          if(!client->component) /*client*/
01867             aji_get_roster(client);
01868       }
01869    } else
01870       ast_log(LOG_ERROR, "Out of memory.\n");
01871 
01872    ASTOBJ_UNREF(client, aji_client_destroy);
01873    return res;
01874 }

static void aji_client_destroy ( struct aji_client obj  )  [static]

Deletes the aji_client data structure.

Parameters:
obj is the structure we will delete.
Returns:
void.

Definition at line 187 of file res_jabber.c.

References aji_buddy_destroy(), AST_LIST_HEAD_DESTROY, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, ASTOBJ_CONTAINER_DESTROY, ASTOBJ_CONTAINER_DESTROYALL, aji_client::buddies, aji_client::f, free, aji_message::from, aji_message::list, aji_message::message, aji_client::messages, aji_client::p, and aji_client::stack.

Referenced by aji_act_hook(), aji_client_connect(), aji_client_info_handler(), aji_create_client(), aji_dinfo_handler(), aji_ditems_handler(), aji_log_hook(), aji_recv_loop(), aji_register_approve_handler(), aji_register_query_handler(), aji_reload(), ast_aji_disconnect(), and unload_module().

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 }

static int aji_client_info_handler ( void *  data,
ikspak *  pak 
) [static]

Definition at line 906 of file res_jabber.c.

References aji_client_destroy(), aji_find_resource(), ast_log(), ASTOBJ_CONTAINER_FIND, ASTOBJ_REF, ASTOBJ_UNREF, aji_client::buddies, aji_resource::cap, aji_client::jid, aji_version::jingle, LOG_ERROR, LOG_NOTICE, aji_client::p, and aji_resource::resource.

Referenced by aji_create_client().

00907 {
00908    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00909    struct aji_resource *resource = NULL;
00910    struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
00911 
00912    resource = aji_find_resource(buddy, pak->from->resource);
00913    if (pak->subtype == IKS_TYPE_RESULT) {
00914       if (!resource) {
00915          ast_log(LOG_NOTICE,"JABBER: Received client info from %s when not requested.\n", pak->from->full);
00916          ASTOBJ_UNREF(client, aji_client_destroy);
00917          return IKS_FILTER_EAT;
00918       }
00919       if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
00920          resource->cap->jingle = 1;
00921       } else
00922          resource->cap->jingle = 0;
00923    } else if (pak->subtype == IKS_TYPE_GET) {
00924       iks *iq, *disco, *ident, *google, *query;
00925       iq = iks_new("iq");
00926       query = iks_new("query");
00927       ident = iks_new("identity");
00928       disco = iks_new("feature");
00929       google = iks_new("feature");
00930       if (iq && ident && disco && google) {
00931          iks_insert_attrib(iq, "from", client->jid->full);
00932          iks_insert_attrib(iq, "to", pak->from->full);
00933          iks_insert_attrib(iq, "type", "result");
00934          iks_insert_attrib(iq, "id", pak->id);
00935          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
00936          iks_insert_attrib(ident, "category", "client");
00937          iks_insert_attrib(ident, "type", "pc");
00938          iks_insert_attrib(ident, "name", "asterisk");
00939          iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco#info");
00940          iks_insert_attrib(google, "var", "http://www.google.com/xmpp/protocol/voice/v1");
00941          iks_insert_node(iq, query);
00942          iks_insert_node(query, ident);
00943          iks_insert_node(query, google);
00944          iks_insert_node(query, disco);
00945          iks_send(client->p, iq);
00946       } else
00947          ast_log(LOG_ERROR, "Out of Memory.\n");
00948       if (iq)
00949          iks_delete(iq);
00950       if (query)
00951          iks_delete(query);
00952       if (ident)
00953          iks_delete(ident);
00954       if (google)
00955          iks_delete(google);
00956       if (disco)
00957          iks_delete(disco);
00958    } else if (pak->subtype == IKS_TYPE_ERROR) {
00959       ast_log(LOG_NOTICE, "User %s does not support discovery.\n", pak->from->full);
00960    }
00961    ASTOBJ_UNREF(client, aji_client_destroy);
00962    return IKS_FILTER_EAT;
00963 }

static int aji_client_initialize ( struct aji_client client  )  [static]

prepares client for connect.

Parameters:
aji_client struct.
Returns:
1.

Definition at line 1881 of file res_jabber.c.

References ast_log(), connected, aji_client::jid, LOG_ERROR, aji_client::name, aji_client::p, aji_client::port, S_OR, and aji_client::serverhost.

Referenced by aji_reconnect().

01882 {
01883    int connected = 0;
01884 
01885    connected = iks_connect_via(client->p, S_OR(client->serverhost, client->jid->server), client->port, client->jid->server);
01886 
01887    if (connected == IKS_NET_NOCONN) {
01888       ast_log(LOG_ERROR, "JABBER ERROR: No Connection\n");
01889       return IKS_HOOK;
01890    } else   if (connected == IKS_NET_NODNS) {
01891       ast_log(LOG_ERROR, "JABBER ERROR: No DNS %s for client to  %s\n", client->name, S_OR(client->serverhost, client->jid->server));
01892       return IKS_HOOK;
01893    } else
01894       iks_recv(client->p, 30);
01895    return IKS_OK;
01896 }

static int aji_component_initialize ( struct aji_client client  )  [static]

prepares component for connect.

Parameters:
aji_client struct.
Returns:
1.

Definition at line 1903 of file res_jabber.c.

References ast_log(), connected, aji_client::jid, LOG_ERROR, aji_client::name, aji_client::p, aji_client::port, S_OR, aji_client::serverhost, and aji_client::user.

Referenced by aji_reconnect().

01904 {
01905    int connected = 1;
01906 
01907    connected = iks_connect_via(client->p, S_OR(client->serverhost, client->jid->server), client->port, client->user);
01908    if (connected == IKS_NET_NOCONN) {
01909       ast_log(LOG_ERROR, "JABBER ERROR: No Connection\n");
01910       return IKS_HOOK;
01911    } else if (connected == IKS_NET_NODNS) {
01912       ast_log(LOG_ERROR, "JABBER ERROR: No DNS %s for client to  %s\n", client->name, S_OR(client->serverhost, client->jid->server));
01913       return IKS_HOOK;
01914    } else if (!connected) 
01915       iks_recv(client->p, 30);
01916    return IKS_OK;
01917 }

static int aji_create_buddy ( char *  label,
struct aji_client client 
) [static]

creates transport. creates buddy.

Parameters:
label,buddy to dump it into.
Returns:
0.

Definition at line 2292 of file res_jabber.c.

References aji_buddy_destroy(), ast_copy_string(), ast_log(), ASTOBJ_CONTAINER_FIND, ASTOBJ_CONTAINER_LINK, ASTOBJ_INIT, ASTOBJ_UNLOCK, ASTOBJ_UNMARK, ASTOBJ_UNREF, ASTOBJ_WRLOCK, aji_client::buddies, LOG_WARNING, malloc, and aji_buddy::name.

Referenced by aji_create_client(), aji_handle_presence(), and aji_handle_subscribe().

02293 {
02294    struct aji_buddy *buddy = NULL;
02295    int flag = 0;
02296    buddy = ASTOBJ_CONTAINER_FIND(&client->buddies,label);
02297    if (!buddy) {
02298       flag = 1;
02299       buddy = malloc(sizeof(struct aji_buddy));
02300       if(!buddy) {
02301          ast_log(LOG_WARNING, "Out of memory\n");
02302          return 0;
02303       }
02304       memset(buddy, 0, sizeof(struct aji_buddy));
02305       ASTOBJ_INIT(buddy);
02306    }
02307    ASTOBJ_WRLOCK(buddy);
02308    ast_copy_string(buddy->name, label, sizeof(buddy->name));
02309    ASTOBJ_UNLOCK(buddy);
02310    if(flag)
02311       ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
02312    else {
02313       ASTOBJ_UNMARK(buddy);
02314       ASTOBJ_UNREF(buddy, aji_buddy_destroy);
02315    }
02316    return 1;
02317 }

static int aji_create_client ( char *  label,
struct ast_variable var,
int  debug 
) [static]

creates aji_client structure.

Parameters:
label,ast_variable,debug,pruneregister,component/client,aji_client to dump into.
Returns:
0.

Definition at line 2103 of file res_jabber.c.

References aji_act_hook(), AJI_AUTOPRUNE, AJI_AUTOREGISTER, aji_client_destroy(), aji_client_info_handler(), aji_create_buddy(), aji_dinfo_handler(), AJI_DISCONNECTED, aji_ditems_handler(), aji_log_hook(), aji_register_approve_handler(), aji_register_query_handler(), asprintf, ast_copy_flags, ast_copy_string(), ast_false(), AST_FLAGS_ALL, AST_LIST_HEAD_INIT, ast_log(), ast_set2_flag, ast_true(), ASTOBJ_CONTAINER_FIND, ASTOBJ_CONTAINER_INIT, ASTOBJ_CONTAINER_LINK, ASTOBJ_CONTAINER_MARKALL, ASTOBJ_INIT, ASTOBJ_UNLOCK, ASTOBJ_UNMARK, ASTOBJ_UNREF, ASTOBJ_WRLOCK, aji_client::authorized, aji_client::buddies, clients, aji_client::component, aji_client::debug, aji_client::f, aji_client::forcessl, free, globalflags, aji_client::jid, aji_client::keepalive, LOG_ERROR, malloc, aji_client::message_timeout, aji_client::messages, aji_client::mid, aji_client::name, aji_client::p, aji_client::password, aji_client::port, aji_client::serverhost, aji_client::stack, aji_client::state, aji_client::statusmessage, aji_client::timeout, aji_client::user, aji_client::usesasl, aji_client::usetls, and var.

Referenced by aji_load_config().

02104 {
02105    char *resource;
02106    struct aji_client *client = NULL;
02107    int flag = 0;
02108 
02109    client = ASTOBJ_CONTAINER_FIND(&clients,label);
02110    if (!client) {
02111       flag = 1;
02112       client = (struct aji_client *) malloc(sizeof(struct aji_client));
02113       if (!client) {
02114          ast_log(LOG_ERROR, "Out of memory!\n");
02115          return 0;
02116       }
02117       memset(client, 0, sizeof(struct aji_client));
02118       ASTOBJ_INIT(client);
02119       ASTOBJ_WRLOCK(client);
02120       ASTOBJ_CONTAINER_INIT(&client->buddies);
02121    } else {
02122       ASTOBJ_WRLOCK(client);
02123       ASTOBJ_UNMARK(client);
02124    }
02125    ASTOBJ_CONTAINER_MARKALL(&client->buddies);
02126    ast_copy_string(client->name, label, sizeof(client->name));
02127    ast_copy_string(client->mid, "aaaaa", sizeof(client->mid));
02128 
02129    /* Set default values for the client object */
02130    client->debug = debug;
02131    ast_copy_flags(client, &globalflags, AST_FLAGS_ALL);
02132    client->port = 5222;
02133    client->usetls = 1;
02134    client->usesasl = 1;
02135    client->forcessl = 0;
02136    client->keepalive = 1;
02137    client->timeout = 50;
02138    client->message_timeout = 100;
02139    AST_LIST_HEAD_INIT(&client->messages);
02140    client->component = 0;
02141    ast_copy_string(client->statusmessage, "Online and Available", sizeof(client->statusmessage));
02142 
02143    if (flag) {
02144       client->authorized = 0;
02145       client->state = AJI_DISCONNECTED;
02146    }
02147    while (var) {
02148       if (!strcasecmp(var->name, "username"))
02149          ast_copy_string(client->user, var->value, sizeof(client->user));
02150       else if (!strcasecmp(var->name, "serverhost"))
02151          ast_copy_string(client->serverhost, var->value, sizeof(client->serverhost));
02152       else if (!strcasecmp(var->name, "secret"))
02153          ast_copy_string(client->password, var->value, sizeof(client->password));
02154       else if (!strcasecmp(var->name, "statusmessage"))
02155          ast_copy_string(client->statusmessage, var->value, sizeof(client->statusmessage));
02156       else if (!strcasecmp(var->name, "port"))
02157          client->port = atoi(var->value);
02158       else if (!strcasecmp(var->name, "timeout"))
02159          client->message_timeout = atoi(var->value);
02160       else if (!strcasecmp(var->name, "debug"))
02161          client->debug = (ast_false(var->value)) ? 0 : 1;
02162       else if (!strcasecmp(var->name, "type")) {
02163          if (!strcasecmp(var->value, "component"))
02164             client->component = 1;
02165       } else if (!strcasecmp(var->name, "usetls")) {
02166          client->usetls = (ast_false(var->value)) ? 0 : 1;
02167       } else if (!strcasecmp(var->name, "usesasl")) {
02168          client->usesasl = (ast_false(var->value)) ? 0 : 1;
02169       } else if (!strcasecmp(var->name, "forceoldssl"))
02170          client->forcessl = (ast_false(var->value)) ? 0 : 1;
02171       else if (!strcasecmp(var->name, "keepalive"))
02172          client->keepalive = (ast_false(var->value)) ? 0 : 1;
02173       else if (!strcasecmp(var->name, "autoprune"))
02174          ast_set2_flag(client, ast_true(var->value), AJI_AUTOPRUNE);
02175       else if (!strcasecmp(var->name, "autoregister"))
02176          ast_set2_flag(client, ast_true(var->value), AJI_AUTOREGISTER);
02177       else if (!strcasecmp(var->name, "buddy"))
02178             aji_create_buddy(var->value, client);
02179    /* no transport support in this version */
02180    /* else if (!strcasecmp(var->name, "transport"))
02181             aji_create_transport(var->value, client);
02182    */
02183       var = var->next;
02184    }
02185    if (!flag) {
02186       ASTOBJ_UNLOCK(client);
02187       ASTOBJ_UNREF(client, aji_client_destroy);
02188       return 1;
02189    }
02190    client->p = iks_stream_new(((client->component) ? "jabber:component:accept" : "jabber:client"), client, aji_act_hook);
02191    if (!client->p) {
02192       ast_log(LOG_ERROR, "Failed to create stream for client '%s'!\n", client->name);
02193       return 0;
02194    }
02195    client->stack = iks_stack_new(8192, 8192);
02196    if (!client->stack) {
02197       ast_log(LOG_ERROR, "Failed to allocate stack for client '%s'\n", client->name);
02198       return 0;
02199    }
02200    client->f = iks_filter_new();
02201    if (!client->f) {
02202       ast_log(LOG_ERROR, "Failed to create filter for client '%s'\n", client->name);
02203       return 0;
02204    }
02205    if (!strchr(client->user, '/') && !client->component) { /*client */
02206       resource = NULL;
02207       if (asprintf(&resource, "%s/asterisk", client->user) > 0) {
02208          client->jid = iks_id_new(client->stack, resource);
02209          free(resource);
02210       }
02211    } else
02212       client->jid = iks_id_new(client->stack, client->user);
02213    if (client->component) {
02214       iks_filter_add_rule(client->f, aji_dinfo_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
02215       iks_filter_add_rule(client->f, aji_ditems_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#items", IKS_RULE_DONE);
02216       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);
02217       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);
02218    } else {
02219       iks_filter_add_rule(client->f, aji_client_info_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
02220    }
02221    if (!strchr(client->user, '/') && !client->component) { /*client */
02222       resource = NULL;
02223       if (asprintf(&resource, "%s/asterisk", client->user) > 0) {
02224          client->jid = iks_id_new(client->stack, resource);
02225          free(resource);
02226       }
02227    } else
02228       client->jid = iks_id_new(client->stack, client->user);
02229    iks_set_log_hook(client->p, aji_log_hook);
02230    ASTOBJ_UNLOCK(client);
02231    ASTOBJ_CONTAINER_LINK(&clients,client);
02232    return 1;
02233 }

static int aji_dinfo_handler ( void *  data,
ikspak *  pak 
) [static]

Definition at line 965 of file res_jabber.c.

References aji_client_destroy(), aji_find_resource(), ast_log(), ASTOBJ_CONTAINER_FIND, ASTOBJ_REF, ASTOBJ_UNREF, aji_client::buddies, aji_resource::cap, commands, aji_version::jingle, LOG_ERROR, LOG_NOTICE, LOG_WARNING, aji_client::p, aji_resource::resource, and aji_client::user.

Referenced by aji_create_client().

00966 {
00967    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00968    char *node = NULL;
00969    struct aji_resource *resource = NULL;
00970    struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
00971 
00972    resource = aji_find_resource(buddy, pak->from->resource);
00973    if (pak->subtype == IKS_TYPE_ERROR) {
00974       ast_log(LOG_WARNING, "Recieved error from a client, turn on jabber debug!\n");
00975       return IKS_FILTER_EAT;
00976    }
00977    if (pak->subtype == IKS_TYPE_RESULT) {
00978       if (!resource) {
00979          ast_log(LOG_NOTICE,"JABBER: Received client info from %s when not requested.\n", pak->from->full);
00980          ASTOBJ_UNREF(client, aji_client_destroy);
00981          return IKS_FILTER_EAT;
00982       }
00983       if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
00984          resource->cap->jingle = 1;
00985       } else
00986          resource->cap->jingle = 0;
00987    } else if (pak->subtype == IKS_TYPE_GET && !(node = iks_find_attrib(pak->query, "node"))) {
00988       iks *iq, *query, *identity, *disco, *reg, *commands, *gateway, *version, *vcard, *search;
00989 
00990       iq = iks_new("iq");
00991       query = iks_new("query");
00992       identity = iks_new("identity");
00993       disco = iks_new("feature");
00994       reg = iks_new("feature");
00995       commands = iks_new("feature");
00996       gateway = iks_new("feature");
00997       version = iks_new("feature");
00998       vcard = iks_new("feature");
00999       search = iks_new("feature");
01000 
01001       if (iq && query && identity && disco && reg && commands && gateway && version && vcard && search && client) {
01002          iks_insert_attrib(iq, "from", client->user);
01003          iks_insert_attrib(iq, "to", pak->from->full);
01004          iks_insert_attrib(iq, "id", pak->id);
01005          iks_insert_attrib(iq, "type", "result");
01006          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01007          iks_insert_attrib(identity, "category", "gateway");
01008          iks_insert_attrib(identity, "type", "pstn");
01009          iks_insert_attrib(identity, "name", "Asterisk The Open Source PBX");
01010          iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco");
01011          iks_insert_attrib(reg, "var", "jabber:iq:register");
01012          iks_insert_attrib(commands, "var", "http://jabber.org/protocol/commands");
01013          iks_insert_attrib(gateway, "var", "jabber:iq:gateway");
01014          iks_insert_attrib(version, "var", "jabber:iq:version");
01015          iks_insert_attrib(vcard, "var", "vcard-temp");
01016          iks_insert_attrib(search, "var", "jabber:iq:search");
01017 
01018          iks_insert_node(iq, query);
01019          iks_insert_node(query, identity);
01020          iks_insert_node(query, disco);
01021          iks_insert_node(query, reg);
01022          iks_insert_node(query, commands);
01023          iks_insert_node(query, gateway);
01024          iks_insert_node(query, version);
01025          iks_insert_node(query, vcard);
01026          iks_insert_node(query, search);
01027          iks_send(client->p, iq);
01028       } else {
01029          ast_log(LOG_ERROR, "Out of memory.\n");
01030       }
01031 
01032       if (iq)
01033          iks_delete(iq);
01034       if (query)
01035          iks_delete(query);
01036       if (identity)
01037          iks_delete(identity);
01038       if (disco)
01039          iks_delete(disco);
01040       if (reg)
01041          iks_delete(reg);
01042       if (commands)
01043          iks_delete(commands);
01044       if (gateway)
01045          iks_delete(gateway);
01046       if (version)
01047          iks_delete(version);
01048       if (vcard)
01049          iks_delete(vcard);
01050       if (search)
01051          iks_delete(search);
01052 
01053    } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "http://jabber.org/protocol/commands")) {
01054       iks *iq, *query, *confirm;
01055       iq = iks_new("iq");
01056       query = iks_new("query");
01057       confirm = iks_new("item");
01058 
01059       if (iq && query && confirm && client) {
01060          iks_insert_attrib(iq, "from", client->user);
01061          iks_insert_attrib(iq, "to", pak->from->full);
01062          iks_insert_attrib(iq, "id", pak->id);
01063          iks_insert_attrib(iq, "type", "result");
01064          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01065          iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
01066          iks_insert_attrib(confirm, "node", "confirmaccount");
01067          iks_insert_attrib(confirm, "name", "Confirm AIM account");
01068          iks_insert_attrib(confirm, "jid", client->user);
01069          iks_insert_node(iq, query);
01070          iks_insert_node(query, confirm);
01071          iks_send(client->p, iq);
01072       } else {
01073          ast_log(LOG_ERROR, "Out of memory.\n");
01074       }
01075       if (iq)
01076          iks_delete(iq);
01077       if (query)
01078          iks_delete(query);
01079       if (confirm)
01080          iks_delete(confirm);
01081 
01082    } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "confirmaccount")) {
01083       iks *iq, *query, *feature;
01084 
01085       iq = iks_new("iq");
01086       query = iks_new("query");
01087       feature = iks_new("feature");
01088 
01089       if (iq && query && feature && client) {
01090          iks_insert_attrib(iq, "from", client->user);
01091          iks_insert_attrib(iq, "to", pak->from->full);
01092          iks_insert_attrib(iq, "id", pak->id);
01093          iks_insert_attrib(iq, "type", "result");
01094          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01095          iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
01096          iks_insert_node(iq, query);
01097          iks_insert_node(query, feature);
01098          iks_send(client->p, iq);
01099       } else {
01100          ast_log(LOG_ERROR, "Out of memory.\n");
01101       }
01102       if (iq)
01103          iks_delete(iq);
01104       if (query)
01105          iks_delete(query);
01106       if (feature)
01107          iks_delete(feature);
01108    }
01109 
01110    ASTOBJ_UNREF(client, aji_client_destroy);
01111    return IKS_FILTER_EAT;
01112 }

static int aji_ditems_handler ( void *  data,
ikspak *  pak 
) [static]

Definition at line 810 of file res_jabber.c.

References aji_client_destroy(), ast_log(), ASTOBJ_REF, ASTOBJ_UNREF, LOG_ERROR, aji_client::p, and aji_client::user.

Referenced by aji_create_client().

00811 {
00812    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00813    char *node = NULL;
00814 
00815    if (!(node = iks_find_attrib(pak->query, "node"))) {
00816       iks *iq = NULL, *query = NULL, *item = NULL;
00817       iq = iks_new("iq");
00818       query = iks_new("query");
00819       item = iks_new("item");
00820 
00821       if (iq && query && item) {
00822          iks_insert_attrib(iq, "from", client->user);
00823          iks_insert_attrib(iq, "to", pak->from->full);
00824          iks_insert_attrib(iq, "id", pak->id);
00825          iks_insert_attrib(iq, "type", "result");
00826          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
00827          iks_insert_attrib(item, "node", "http://jabber.org/protocol/commands");
00828          iks_insert_attrib(item, "name", "Million Dollar Asterisk Commands");
00829          iks_insert_attrib(item, "jid", client->user);
00830 
00831          iks_insert_node(iq, query);
00832          iks_insert_node(query, item);
00833          iks_send(client->p, iq);
00834       } else {
00835          ast_log(LOG_ERROR, "Out of memory.\n");
00836       }
00837       if (iq)
00838          iks_delete(iq);
00839       if (query)
00840          iks_delete(query);
00841       if (item)
00842          iks_delete(item);
00843 
00844    } else if (!strcasecmp(node, "http://jabber.org/protocol/commands")) {
00845       iks *iq, *query, *confirm;
00846       iq = iks_new("iq");
00847       query = iks_new("query");
00848       confirm = iks_new("item");
00849       if (iq && query && confirm && client) {
00850          iks_insert_attrib(iq, "from", client->user);
00851          iks_insert_attrib(iq, "to", pak->from->full);
00852          iks_insert_attrib(iq, "id", pak->id);
00853          iks_insert_attrib(iq, "type", "result");
00854          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
00855          iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
00856          iks_insert_attrib(confirm, "node", "confirmaccount");
00857          iks_insert_attrib(confirm, "name", "Confirm AIM account");
00858          iks_insert_attrib(confirm, "jid", "blog.astjab.org");
00859 
00860          iks_insert_node(iq, query);
00861          iks_insert_node(query, confirm);
00862          iks_send(client->p, iq);
00863       } else {
00864          ast_log(LOG_ERROR, "Out of memory.\n");
00865       }
00866       if (iq)
00867          iks_delete(iq);
00868       if (query)
00869          iks_delete(query);
00870       if (confirm)
00871          iks_delete(confirm);
00872 
00873    } else if (!strcasecmp(node, "confirmaccount")) {
00874       iks *iq = NULL, *query = NULL, *feature = NULL;
00875 
00876       iq = iks_new("iq");
00877       query = iks_new("query");
00878       feature = iks_new("feature");
00879 
00880       if (iq && query && feature && client) {
00881          iks_insert_attrib(iq, "from", client->user);
00882          iks_insert_attrib(iq, "to", pak->from->full);
00883          iks_insert_attrib(iq, "id", pak->id);
00884          iks_insert_attrib(iq, "type", "result");
00885          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
00886          iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
00887          iks_insert_node(iq, query);
00888          iks_insert_node(query, feature);
00889          iks_send(client->p, iq);
00890       } else {
00891          ast_log(LOG_ERROR, "Out of memory.\n");
00892       }
00893       if (iq)
00894          iks_delete(iq);
00895       if (query)
00896          iks_delete(query);
00897       if (feature)
00898          iks_delete(feature);
00899    }
00900 
00901    ASTOBJ_UNREF(client, aji_client_destroy);
00902    return IKS_FILTER_EAT;
00903 
00904 }

static int aji_do_debug ( int  fd,
int  argc,
char *  argv[] 
) [static]

turnon console debugging.

Parameters:
fd,number of args, args.
Returns:
RESULT_SUCCESS.

Definition at line 1974 of file res_jabber.c.

References ast_cli(), ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_RDLOCK, ASTOBJ_UNLOCK, clients, and RESULT_SUCCESS.

01975 {
01976    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
01977       ASTOBJ_RDLOCK(iterator); 
01978       iterator->debug = 1;
01979       ASTOBJ_UNLOCK(iterator);
01980    });
01981    ast_cli(fd, "Jabber Debugging Enabled.\n");
01982    return RESULT_SUCCESS;
01983 }

static int aji_do_reload ( int  fd,
int  argc,
char *  argv[] 
) [static]

reload jabber module.

Parameters:
fd,number of args, args.
Returns:
RESULT_SUCCESS.

Definition at line 1990 of file res_jabber.c.

References aji_reload(), ast_cli(), and RESULT_SUCCESS.

01991 {
01992    aji_reload();
01993    ast_cli(fd, "Jabber Reloaded.\n");
01994    return RESULT_SUCCESS;
01995 }

static int aji_filter_roster ( void *  data,
ikspak *  pak 
) [static]

filters the roster packet we get back from server.

Parameters:
aji_client struct, and xml packet.
Returns:
IKS_FILTER_EAT.

Definition at line 1744 of file res_jabber.c.

References AJI_AUTOPRUNE, AJI_AUTOREGISTER, AJI_CONNECTED, ast_clear_flag, ast_copy_flags, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_RDLOCK, ASTOBJ_REF, ASTOBJ_UNLOCK, aji_client::buddies, and aji_client::state.

Referenced by aji_client_connect().

01745 {
01746    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01747    int flag = 0;
01748    iks *x = NULL;
01749    struct aji_buddy *buddy;
01750    
01751    client->state = AJI_CONNECTED;
01752    ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
01753       ASTOBJ_RDLOCK(iterator);
01754       x = iks_child(pak->query);
01755       flag = 0;
01756       while (x) {
01757          if (!iks_strcmp(iks_name(x), "item")) {
01758             if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid"))) {
01759                flag = 1;
01760                ast_clear_flag(iterator, AJI_AUTOPRUNE | AJI_AUTOREGISTER);
01761             }
01762          }
01763          x = iks_next(x);
01764       }
01765       if (!flag)
01766          ast_copy_flags(iterator, client, AJI_AUTOREGISTER);
01767       if (x)
01768          iks_delete(x);
01769       ASTOBJ_UNLOCK(iterator);
01770    });
01771 
01772    x = iks_child(pak->query);
01773    while (x) {
01774       flag = 0;
01775       if (iks_strcmp(iks_name(x), "item") == 0) {
01776          ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
01777             ASTOBJ_RDLOCK(iterator);
01778             if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid")))
01779                flag = 1;
01780             ASTOBJ_UNLOCK(iterator);
01781          });
01782 
01783          if (!flag) {
01784             buddy = (struct aji_buddy *) malloc(sizeof(struct aji_buddy));
01785             if (!buddy) {
01786                ast_log(LOG_WARNING, "Out of memory\n");
01787                return 0;
01788             }
01789             memset(buddy, 0, sizeof(struct aji_buddy));
01790             ASTOBJ_INIT(buddy);
01791             ASTOBJ_WRLOCK(buddy);
01792             ast_copy_string(buddy->name, iks_find_attrib(x, "jid"), sizeof(buddy->name));
01793             ast_clear_flag(buddy, AST_FLAGS_ALL);
01794             if(ast_test_flag(client, AJI_AUTOPRUNE)) {
01795                ast_set_flag(buddy, AJI_AUTOPRUNE);
01796                buddy->objflags |= ASTOBJ_FLAG_MARKED;
01797             } else
01798                ast_set_flag(buddy, AJI_AUTOREGISTER);
01799             ASTOBJ_UNLOCK(buddy);
01800             if (buddy) {
01801                ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
01802                ASTOBJ_UNREF(buddy, aji_buddy_destroy);
01803             }
01804          }
01805       }
01806       x = iks_next(x);
01807    }
01808    if (x)
01809       iks_delete(x);
01810    aji_pruneregister(client);
01811 
01812    ASTOBJ_UNREF(client, aji_client_destroy);
01813    return IKS_FILTER_EAT;
01814 }

static struct aji_resource* aji_find_resource ( struct aji_buddy buddy,
char *  name 
) [static]

Definition at line 295 of file res_jabber.c.

References aji_resource::next, aji_resource::resource, and aji_buddy::resources.

Referenced by aji_client_info_handler(), aji_dinfo_handler(), and aji_status_exec().

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 }

static struct aji_version* aji_find_version ( char *  node,
char *  version,
ikspak *  pak 
) [static]

Find version in XML stream and populate our capabilities list.

Parameters:
node the node attribute in the caps element we'll look for or add to our list
version the version attribute in the caps element we'll look for or add to our list
pak the XML stanza we're processing
Returns:
a pointer to the added or found aji_version structure

Definition at line 233 of file res_jabber.c.

References ast_copy_string(), ast_free, ast_log(), capabilities, aji_version::jingle, LOG_ERROR, malloc, aji_capabilities::next, aji_version::next, aji_capabilities::node, aji_version::parent, aji_version::version, and aji_capabilities::versions.

Referenced by aji_handle_presence().

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 }

static int aji_get_roster ( struct aji_client client  )  [static]

Definition at line 1836 of file res_jabber.c.

References aji_set_presence(), aji_client::jid, aji_client::p, and aji_client::statusmessage.

Referenced by aji_client_connect(), and aji_reload().

01837 {
01838    iks *roster = NULL;
01839    roster = iks_make_iq(IKS_TYPE_GET, IKS_NS_ROSTER);
01840    if(roster) {
01841       iks_insert_attrib(roster, "id", "roster");
01842       aji_set_presence(client, NULL, client->jid->full, 1, client->statusmessage);
01843       iks_send(client->p, roster);
01844    }
01845    if (roster)
01846       iks_delete(roster);
01847    return 1;
01848 }

static void aji_handle_iq ( struct aji_client client,
iks *  node 
) [static]

Handles <iq> tags.

Parameters:
client structure and the iq node.
Returns:
void.

Definition at line 1119 of file res_jabber.c.

Referenced by aji_act_hook().

01120 {
01121    /*Nothing to see here */
01122 }

static void aji_handle_message ( struct aji_client client,
ikspak *  pak 
) [static]

Handles presence packets.

Parameters:
client structure and the node.
Returns:
void.

Definition at line 1129 of file res_jabber.c.

References aji_message::arrived, ast_calloc, ast_copy_string(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_strdup, free, aji_message::from, aji_message::id, aji_message::list, aji_message::message, aji_client::message_timeout, and aji_client::messages.

Referenced by aji_act_hook().

01130 {
01131    struct aji_message *insert, *tmp;
01132    int flag = 0;
01133    
01134    if (!(insert = ast_calloc(1, sizeof(struct aji_message))))
01135       return;
01136    time(&insert->arrived);
01137    if (iks_find_cdata(pak->x, "body"))
01138       insert->message = ast_strdup(iks_find_cdata(pak->x, "body"));
01139    if(pak->id)
01140       ast_copy_string(insert->id, pak->id, sizeof(insert->message));
01141    if (pak->from)
01142       insert->from = ast_strdup(pak->from->full);
01143    AST_LIST_LOCK(&client->messages);
01144    AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, tmp, list) {
01145       if (flag) {
01146          AST_LIST_REMOVE_CURRENT(&client->messages, list);
01147          if (tmp->from)
01148             free(tmp->from);
01149          if (tmp->message)
01150             free(tmp->message);
01151       } else if (difftime(time(NULL), tmp->arrived) >= client->message_timeout) {
01152          flag = 1;
01153          AST_LIST_REMOVE_CURRENT(&client->messages, list);
01154          if (tmp->from)
01155             free(tmp->from);
01156          if (tmp->message)
01157             free(tmp->message);
01158       }
01159    }
01160    AST_LIST_TRAVERSE_SAFE_END;
01161    AST_LIST_INSERT_HEAD(&client->messages, insert, list);
01162    AST_LIST_UNLOCK(&client->messages);
01163 }

static void aji_handle_presence ( struct aji_client client,
ikspak *  pak 
) [static]

Definition at line 1165 of file res_jabber.c.

References aji_buddy_destroy(), AJI_CONNECTED, aji_create_buddy(), aji_find_version(), aji_set_presence(), ast_aji_increment_mid(), ast_copy_string(), ast_log(), ast_strdup, ast_verbose(), ASTOBJ_CONTAINER_FIND, ASTOBJ_UNLOCK, ASTOBJ_UNREF, ASTOBJ_WRLOCK, aji_client::buddies, aji_client::component, descrip, aji_resource::description, free, gtalk_yuck(), aji_client::jid, last, LOG_DEBUG, LOG_ERROR, LOG_NOTICE, malloc, aji_client::mid, aji_resource::next, option_debug, option_verbose, aji_client::p, aji_resource::priority, aji_resource::resource, aji_buddy::resources, aji_client::state, aji_resource::status, aji_client::statusmessage, type, and VERBOSE_PREFIX_3.

Referenced by aji_act_hook().

01166 {
01167    int status, priority;
01168    struct aji_buddy *buddy;
01169    struct aji_resource *tmp = NULL, *last = NULL, *found = NULL;
01170    char *ver, *node, *descrip, *type;
01171    
01172    if(client->state != AJI_CONNECTED)
01173       aji_create_buddy(pak->from->partial, client);
01174 
01175    buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01176    if (!buddy && pak->from->partial) {
01177       /* allow our jid to be used to log in with another resource */
01178       if (!strcmp((const char *)pak->from->partial, (const char *)client->jid->partial))
01179          aji_create_buddy(pak->from->partial, client);
01180       else
01181          ast_log(LOG_NOTICE, "Got presence packet from %s, someone not in our roster!!!!\n", pak->from->partial);
01182       return;
01183    }
01184    type = iks_find_attrib(pak->x, "type");
01185    if(client->component && type &&!strcasecmp("probe", type)) {
01186       aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), 1, client->statusmessage);
01187       ast_verbose("what i was looking for \n");
01188    }
01189    ASTOBJ_WRLOCK(buddy);
01190    status = (pak->show) ? pak->show : 6;
01191    priority = atoi((iks_find_cdata(pak->x, "priority")) ? iks_find_cdata(pak->x, "priority") : "0");
01192    tmp = buddy->resources;
01193    descrip = ast_strdup(iks_find_cdata(pak->x,"status"));
01194 
01195    while (tmp && pak->from->resource) {
01196       if (!strcasecmp(tmp->resource, pak->from->resource)) {
01197          tmp->status = status;
01198          if (tmp->description) free(tmp->description);
01199          tmp->description = descrip;
01200          found = tmp;
01201          if (status == 6) {   /* Sign off Destroy resource */
01202             if (last && found->next) {
01203                last->next = found->next;
01204             } else if (!last) {
01205                if (found->next)
01206                   buddy->resources = found->next;
01207                else
01208                   buddy->resources = NULL;
01209             } else if (!found->next) {
01210                if (last)
01211                   last->next = NULL;
01212                else
01213                   buddy->resources = NULL;
01214             }
01215             free(found);
01216             found = NULL;
01217             break;
01218          }
01219          /* resource list is sorted by descending priority */
01220          if (tmp->priority != priority) {
01221             found->priority = priority;
01222             if (!last && !found->next)
01223                /* resource was found to be unique,
01224                   leave loop */
01225                break;
01226             /* search for resource in our list
01227                and take it out for the moment */
01228             if (last)
01229                last->next = found->next;
01230             else
01231                buddy->resources = found->next;
01232 
01233             last = NULL;
01234             tmp = buddy->resources;
01235             if (!buddy->resources)
01236                buddy->resources = found;
01237             /* priority processing */
01238             while (tmp) {
01239                /* insert resource back according to 
01240                   its priority value */
01241                if (found->priority > tmp->priority) {
01242                   if (last)
01243                      /* insert within list */
01244                      last->next = found;
01245                   found->next = tmp;
01246                   if (!last)
01247                      /* insert on top */
01248                      buddy->resources = found;
01249                   break;
01250                }
01251                if (!tmp->next) {
01252                   /* insert at the end of the list */
01253                   tmp->next = found;
01254                   found->next = NULL;
01255                   break;
01256                }
01257                last = tmp;
01258                tmp = tmp->next;
01259             }
01260          }
01261          break;
01262       }
01263       last = tmp;
01264       tmp = tmp->next;
01265    }
01266 
01267    /* resource not found in our list, create it */
01268    if (!found && status != 6 && pak->from->resource) {
01269       found = (struct aji_resource *) malloc(sizeof(struct aji_resource));
01270       memset(found, 0, sizeof(struct aji_resource));
01271 
01272       if (!found) {
01273          ast_log(LOG_ERROR, "Out of memory!\n");
01274          return;
01275       }
01276       ast_copy_string(found->resource, pak->from->resource, sizeof(found->resource));
01277       found->status = status;
01278       found->description = descrip;
01279       found->priority = priority;
01280       found->next = NULL;
01281       last = NULL;
01282       tmp = buddy->resources;
01283       while (tmp) {
01284          if (found->priority > tmp->priority) {
01285             if (last)
01286                last->next = found;
01287             found->next = tmp;
01288             if (!last)
01289                buddy->resources = found;
01290             break;
01291          }
01292          if (!tmp->next) {
01293             tmp->next = found;
01294             break;
01295          }
01296          last = tmp;
01297          tmp = tmp->next;
01298       }
01299       if (!tmp)
01300          buddy->resources = found;
01301    }
01302    
01303    ASTOBJ_UNLOCK(buddy);
01304    ASTOBJ_UNREF(buddy, aji_buddy_destroy);
01305 
01306    node = iks_find_attrib(iks_find(pak->x, "c"), "node");
01307    ver = iks_find_attrib(iks_find(pak->x, "c"), "ver");
01308 
01309    /* handle gmail client's special caps:c tag */
01310    if (!node && !ver) {
01311       node = iks_find_attrib(iks_find(pak->x, "caps:c"), "node");
01312       ver = iks_find_attrib(iks_find(pak->x, "caps:c"), "ver");
01313    }
01314 
01315    /* retrieve capabilites of the new resource */
01316    if(status !=6 && found && !found->cap) {
01317       found->cap = aji_find_version(node, ver, pak);
01318       if(gtalk_yuck(pak->x)) /* gtalk should do discover */
01319          found->cap->jingle = 1;
01320       if(found->cap->jingle && option_debug > 4)
01321          ast_log(LOG_DEBUG,"Special case for google till they support discover.\n");
01322       else {
01323          iks *iq, *query;
01324          iq = iks_new("iq");
01325          query = iks_new("query");
01326          if(query && iq)  {
01327             iks_insert_attrib(iq, "type", "get");
01328             iks_insert_attrib(iq, "to", pak->from->full);
01329             iks_insert_attrib(iq,"from", client->jid->full);
01330             iks_insert_attrib(iq, "id", client->mid);
01331             ast_aji_increment_mid(client->mid);
01332             iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01333             iks_insert_node(iq, query);
01334             iks_send(client->p, iq);
01335             
01336          } else
01337             ast_log(LOG_ERROR, "Out of memory.\n");
01338          if(query)
01339             iks_delete(query);
01340          if(iq)
01341             iks_delete(iq);
01342       }
01343    }
01344    if (option_verbose > 4) {
01345       switch (pak->subtype) {
01346       case IKS_TYPE_AVAILABLE:
01347          ast_verbose(VERBOSE_PREFIX_3 "JABBER: I am available ^_* %i\n", pak->subtype);
01348          break;
01349       case IKS_TYPE_UNAVAILABLE:
01350          ast_verbose(VERBOSE_PREFIX_3 "JABBER: I am unavailable ^_* %i\n", pak->subtype);
01351          break;
01352       default:
01353          ast_verbose(VERBOSE_PREFIX_3 "JABBER: Ohh sexy and the wrong type: %i\n", pak->subtype);
01354       }
01355       switch (pak->show) {
01356       case IKS_SHOW_UNAVAILABLE:
01357          ast_verbose(VERBOSE_PREFIX_3 "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01358          break;
01359       case IKS_SHOW_AVAILABLE:
01360          ast_verbose(VERBOSE_PREFIX_3 "JABBER: type is available\n");
01361          break;
01362       case IKS_SHOW_CHAT:
01363          ast_verbose(VERBOSE_PREFIX_3 "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01364          break;
01365       case IKS_SHOW_AWAY:
01366          ast_verbose(VERBOSE_PREFIX_3 "JABBER: type is away\n");
01367          break;
01368       case IKS_SHOW_XA:
01369          ast_verbose(VERBOSE_PREFIX_3 "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01370          break;
01371       case IKS_SHOW_DND:
01372          ast_verbose(VERBOSE_PREFIX_3 "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01373          break;
01374       default:
01375          ast_verbose(VERBOSE_PREFIX_3 "JABBER: Kinky! how did that happen %i\n", pak->show);
01376       }
01377    }
01378 }

static void aji_handle_subscribe ( struct aji_client client,
ikspak *  pak 
) [static]

handles subscription requests.

Parameters:
aji_client struct and xml packet.
Returns:
void.

Definition at line 1385 of file res_jabber.c.

References aji_create_buddy(), aji_set_presence(), ast_log(), ast_verbose(), ASTOBJ_CONTAINER_FIND, aji_client::buddies, aji_client::component, aji_client::jid, LOG_ERROR, option_verbose, aji_client::p, aji_resource::status, aji_client::statusmessage, and VERBOSE_PREFIX_3.

Referenced by aji_act_hook().

01386 {
01387    iks *presence = NULL, *status = NULL;
01388    struct aji_buddy* buddy = NULL;
01389 
01390    switch (pak->subtype) { 
01391    case IKS_TYPE_SUBSCRIBE:
01392       presence = iks_new("presence");
01393       status = iks_new("status");
01394       if(presence && status) {
01395          iks_insert_attrib(presence, "type", "subscribed");
01396          iks_insert_attrib(presence, "to", pak->from->full);
01397          iks_insert_attrib(presence, "from", client->jid->full);
01398          if(pak->id)
01399             iks_insert_attrib(presence, "id", pak->id);
01400          iks_insert_cdata(status, "Asterisk has approved subscription", 0);
01401          iks_insert_node(presence, status);
01402          iks_send(client->p, presence);
01403       } else
01404          ast_log(LOG_ERROR, "Unable to allocate nodes\n");
01405       if(presence)
01406          iks_delete(presence);
01407       if(status)
01408          iks_delete(status);
01409       if(client->component)
01410          aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), 1, client->statusmessage);
01411    case IKS_TYPE_SUBSCRIBED:
01412       buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01413       if (!buddy && pak->from->partial) {
01414          aji_create_buddy(pak->from->partial, client);
01415       }
01416    default:
01417       if (option_verbose > 4) {
01418          ast_verbose(VERBOSE_PREFIX_3 "JABBER: This is a subcription of type %i\n", pak->subtype);
01419       }
01420    }
01421 }

static int aji_highest_bit ( int  number  )  [static]

Detects the highest bit in a number.

Parameters:
Number you want to have evaluated.
Returns:
the highest power of 2 that can go into the number.

Definition at line 322 of file res_jabber.c.

Referenced by aji_act_hook().

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 }

static int aji_load_config ( void   )  [static]

load config file.

Parameters:
void. 
Returns:
1.

Definition at line 2324 of file res_jabber.c.

References AJI_AUTOPRUNE, AJI_AUTOREGISTER, aji_create_client(), ast_category_browse(), ast_config_destroy(), ast_config_load(), ast_false(), ast_log(), ast_set2_flag, ast_true(), ast_variable_browse(), ast_variable_retrieve(), debug, globalflags, JABBER_CONFIG, LOG_WARNING, and var.

Referenced by aji_reload().

02325 {
02326    char *cat = NULL;
02327    int debug = 1;
02328    struct ast_config *cfg = NULL;
02329    struct ast_variable *var = NULL;
02330 
02331    cfg = ast_config_load(JABBER_CONFIG);
02332    if (!cfg) {
02333       ast_log(LOG_WARNING, "No such configuration file %s\n", JABBER_CONFIG);
02334       return 0;
02335    }
02336 
02337    cat = ast_category_browse(cfg, NULL);
02338    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
02339       if (!strcasecmp(var->name, "debug"))
02340          debug = (ast_false(ast_variable_retrieve(cfg, "general", "debug"))) ? 0 : 1;
02341       else if (!strcasecmp(var->name, "autoprune"))
02342          ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOPRUNE);
02343       else if (!strcasecmp(var->name, "autoregister"))
02344          ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOREGISTER);
02345    }
02346 
02347    while (cat) {
02348       if (strcasecmp(cat, "general")) {
02349             var = ast_variable_browse(cfg, cat);
02350             aji_create_client(cat, var, debug);
02351       }
02352       cat = ast_category_browse(cfg, cat);
02353    }
02354    ast_config_destroy(cfg); /* or leak memory */
02355    return 1;
02356 }

static void aji_log_hook ( void *  data,
const char *  xmpp,
size_t  size,
int  is_incoming 
) [static]

the debug loop.

Parameters:
aji_client structure, xml data as string, size of string, direction of packet, 1 for inbound 0 for outbound.

Definition at line 461 of file res_jabber.c.

References aji_client_destroy(), ast_verbose(), ASTOBJ_REF, ASTOBJ_UNREF, aji_client::debug, EVENT_FLAG_USER, manager_event(), aji_client::name, and option_debug.

Referenced by aji_create_client().

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 }

static int aji_no_debug ( int  fd,
int  argc,
char *  argv[] 
) [static]

turnoff console debugging.

Parameters:
fd,number of args, args.
Returns:
RESULT_SUCCESS.

Definition at line 2002 of file res_jabber.c.

References ast_cli(), ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_RDLOCK, ASTOBJ_UNLOCK, clients, and RESULT_SUCCESS.

02003 {
02004    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02005       ASTOBJ_RDLOCK(iterator);
02006       iterator->debug = 0;
02007       ASTOBJ_UNLOCK(iterator);
02008    });
02009    ast_cli(fd, "Jabber Debugging Disabled.\n");
02010    return RESULT_SUCCESS;
02011 }

static void aji_pruneregister ( struct aji_client client  )  [static]

attempts to register to a transport. attempts to register to a transport step 2. goes through roster and prunes users not needed in list, or adds them accordingly.

Parameters:
aji_client struct.
Returns:
void.

Definition at line 1691 of file res_jabber.c.

References AJI_AUTOPRUNE, AJI_AUTOREGISTER, ast_clear_flag, ast_test_flag, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_RDLOCK, ASTOBJ_UNLOCK, aji_client::buddies, aji_client::jid, and aji_client::p.

01692 {
01693    int res = 0;
01694    iks *removeiq = iks_new("iq");
01695    iks *removequery = iks_new("query");
01696    iks *removeitem = iks_new("item");
01697    iks *send = iks_make_iq(IKS_TYPE_GET, "http://jabber.org/protocol/disco#items");
01698 
01699    if (client && removeiq && removequery && removeitem && send) {
01700       iks_insert_node(removeiq, removequery);
01701       iks_insert_node(removequery, removeitem);
01702       ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
01703          ASTOBJ_RDLOCK(iterator);
01704          /* For an aji_buddy, both AUTOPRUNE and AUTOREGISTER will never
01705           * be called at the same time */
01706          if (ast_test_flag(iterator, AJI_AUTOPRUNE)) {
01707             res = iks_send(client->p, iks_make_s10n(IKS_TYPE_UNSUBSCRIBE, iterator->name,
01708                   "GoodBye your status is no longer needed by Asterisk the Open Source PBX"
01709                   " so I am no longer subscribing to your presence.\n"));
01710             res = iks_send(client->p, iks_make_s10n(IKS_TYPE_UNSUBSCRIBED, iterator->name,
01711                   "GoodBye you are no longer in the asterisk config file so I am removing"
01712                   " your access to my presence.\n"));
01713             iks_insert_attrib(removeiq, "from", client->jid->full); 
01714             iks_insert_attrib(removeiq, "type", "set"); 
01715             iks_insert_attrib(removequery, "xmlns", "jabber:iq:roster");
01716             iks_insert_attrib(removeitem, "jid", iterator->name);
01717             iks_insert_attrib(removeitem, "subscription", "remove");
01718             res = iks_send(client->p, removeiq);
01719          } else if (ast_test_flag(iterator, AJI_AUTOREGISTER)) {
01720             res = iks_send(client->p, iks_make_s10n(IKS_TYPE_SUBSCRIBE, iterator->name, 
01721                   "Greetings I am the Asterisk Open Source PBX and I want to subscribe to your presence\n"));
01722             ast_clear_flag(iterator, AJI_AUTOREGISTER);
01723          }
01724          ASTOBJ_UNLOCK(iterator);
01725       });
01726    } else
01727       ast_log(LOG_ERROR, "Out of memory.\n");
01728    if (removeiq)
01729       iks_delete(removeiq);
01730    if (removequery)
01731       iks_delete(removequery);
01732    if (removeitem)
01733       iks_delete(removeitem);
01734    if (send)
01735       iks_delete(send);
01736    ASTOBJ_CONTAINER_PRUNE_MARKED(&client->buddies, aji_buddy_destroy);
01737 }

static int aji_reconnect ( struct aji_client client  )  [static]

Definition at line 1816 of file res_jabber.c.

References aji_client_initialize(), aji_component_initialize(), AJI_DISCONNECTED, aji_client::authorized, aji_client::component, aji_client::p, aji_client::state, and aji_client::timeout.

Referenced by aji_recv_loop().

01817 {
01818    int res = 0;
01819 
01820    if (client->state)
01821       client->state = AJI_DISCONNECTED;
01822    client->timeout=50;
01823    if (client->p)
01824       iks_parser_reset(client->p);
01825    if (client->authorized)
01826       client->authorized = 0;
01827 
01828    if(client->component)
01829       res = aji_component_initialize(client);
01830    else
01831       res = aji_client_initialize(client);
01832 
01833    return res;
01834 }

static void * aji_recv_loop ( void *  data  )  [static]

receive message loop.

Parameters:
aji_client struct.
Returns:
void.

Definition at line 1540 of file res_jabber.c.

References aji_client_destroy(), AJI_CONNECTED, AJI_DISCONNECTING, aji_reconnect(), ast_log(), ast_verbose(), ASTOBJ_REF, ASTOBJ_UNREF, aji_client::keepalive, LOG_DEBUG, LOG_WARNING, option_debug, option_verbose, aji_client::p, aji_client::state, and aji_client::timeout.

Referenced by aji_reload().

01541 {
01542    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01543    int res = IKS_HOOK;
01544    do {
01545       if (res != IKS_OK) {
01546          while(res != IKS_OK) {
01547             if(option_verbose > 3)
01548                ast_verbose("JABBER: reconnecting.\n");
01549             res = aji_reconnect(client);
01550             sleep(4);
01551          }
01552       }
01553 
01554       res = iks_recv(client->p, 1);
01555 
01556       if (client->state == AJI_DISCONNECTING) {
01557          if (option_debug > 1)
01558             ast_log(LOG_DEBUG, "Ending our Jabber client's thread due to a disconnect\n");
01559          pthread_exit(NULL);
01560       }
01561       client->timeout--;
01562       if (res == IKS_HOOK) 
01563          ast_log(LOG_WARNING, "JABBER: Got hook event.\n");
01564       else if (res == IKS_NET_TLSFAIL)
01565          ast_log(LOG_WARNING, "JABBER:  Failure in TLS.\n");
01566       else if (client->timeout == 0 && client->state == AJI_CONNECTED) {
01567          res = client->keepalive ? iks_send_raw(client->p, " ") : IKS_OK;
01568          if(res == IKS_OK)
01569             client->timeout = 50;
01570          else
01571             ast_log(LOG_WARNING, "JABBER:  Network Timeout\n");
01572       } else if (res == IKS_NET_RWERR)
01573          ast_log(LOG_WARNING, "JABBER: socket read error\n");
01574    } while (client);
01575    ASTOBJ_UNREF(client, aji_client_destroy);
01576    return 0;
01577 }

static int aji_register_approve_handler ( void *  data,
ikspak *  pak 
) [static]

Definition at line 701 of file res_jabber.c.

References aji_client_destroy(), ast_aji_increment_mid(), ast_log(), ASTOBJ_REF, ASTOBJ_UNREF, aji_client::jid, LOG_ERROR, aji_client::mid, and aji_client::p.

Referenced by aji_create_client().

00702 {
00703    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00704    iks *iq = NULL, *presence = NULL, *x = NULL;
00705 
00706    iq = iks_new("iq");
00707    presence = iks_new("presence");
00708    x = iks_new("x");
00709    if (client && iq && presence && x) {
00710       if (!iks_find(pak->query, "remove")) {
00711          iks_insert_attrib(iq, "from", client->jid->full);
00712          iks_insert_attrib(iq, "to", pak->from->full);
00713          iks_insert_attrib(iq, "id", pak->id);
00714          iks_insert_attrib(iq, "type", "result");
00715          iks_send(client->p, iq);
00716 
00717          iks_insert_attrib(presence, "from", client->jid->full);
00718          iks_insert_attrib(presence, "to", pak->from->partial);
00719          iks_insert_attrib(presence, "id", client->mid);
00720          ast_aji_increment_mid(client->mid);
00721          iks_insert_attrib(presence, "type", "subscribe");
00722          iks_insert_attrib(x, "xmlns", "vcard-temp:x:update");
00723          iks_insert_node(presence, x);
00724          iks_send(client->p, presence); 
00725       }
00726    } else {
00727       ast_log(LOG_ERROR, "Out of memory.\n");
00728    }
00729 
00730    if (iq)
00731       iks_delete(iq);
00732    if(presence)
00733       iks_delete(presence);
00734    if (x)
00735       iks_delete(x);
00736    ASTOBJ_UNREF(client, aji_client_destroy);
00737    return IKS_FILTER_EAT;
00738 }

static int aji_register_query_handler ( void *  data,
ikspak *  pak 
) [static]

Definition at line 740 of file res_jabber.c.

References aji_client_destroy(), ast_log(), ast_verbose(), ASTOBJ_CONTAINER_FIND, ASTOBJ_REF, ASTOBJ_UNREF, aji_client::buddies, LOG_ERROR, aji_client::p, and aji_client::user.

Referenced by aji_create_client().

00741 {
00742    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00743    struct aji_buddy *buddy = NULL; 
00744    char *node = NULL;
00745 
00746    client = (struct aji_client *) data;
00747 
00748    buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
00749    if (!buddy) {
00750       iks *iq = NULL, *query = NULL, *error = NULL, *notacceptable = NULL;
00751       ast_verbose("Someone.... %s tried to register but they aren't allowed\n", pak->from->partial);
00752       iq = iks_new("iq");
00753       query = iks_new("query");
00754       error = iks_new("error");
00755       notacceptable = iks_new("not-acceptable");
00756       if(iq && query && error && notacceptable) {
00757          iks_insert_attrib(iq, "type", "error");
00758          iks_insert_attrib(iq, "from", client->user);
00759          iks_insert_attrib(iq, "to", pak->from->full);
00760          iks_insert_attrib(iq, "id", pak->id);
00761          iks_insert_attrib(query, "xmlns", "jabber:iq:register");
00762          iks_insert_attrib(error, "code" , "406");
00763          iks_insert_attrib(error, "type", "modify");
00764          iks_insert_attrib(notacceptable, "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas");
00765          iks_insert_node(iq, query);
00766          iks_insert_node(iq, error);
00767          iks_insert_node(error, notacceptable);
00768          iks_send(client->p, iq);
00769       } else {
00770          ast_log(LOG_ERROR, "Out of memory.\n");
00771       }
00772       if (iq)
00773          iks_delete(iq);
00774       if (query)
00775          iks_delete(query);
00776       if (error)
00777          iks_delete(error);
00778       if (notacceptable)
00779          iks_delete(notacceptable);
00780    } else   if (!(node = iks_find_attrib(pak->query, "node"))) {
00781       iks *iq = NULL, *query = NULL, *instructions = NULL;
00782       char *explain = "Welcome to Asterisk - the Open Source PBX.\n";
00783       iq = iks_new("iq");
00784       query = iks_new("query");
00785       instructions = iks_new("instructions");
00786       if (iq && query && instructions && client) {
00787          iks_insert_attrib(iq, "from", client->user);
00788          iks_insert_attrib(iq, "to", pak->from->full);
00789          iks_insert_attrib(iq, "id", pak->id);
00790          iks_insert_attrib(iq, "type", "result");
00791          iks_insert_attrib(query, "xmlns", "jabber:iq:register");
00792          iks_insert_cdata(instructions, explain, 0);
00793          iks_insert_node(iq, query);
00794          iks_insert_node(query, instructions);
00795          iks_send(client->p, iq);
00796       } else {
00797          ast_log(LOG_ERROR, "Out of memory.\n");
00798       }
00799       if (iq)
00800          iks_delete(iq);
00801       if (query)
00802          iks_delete(query);
00803       if (instructions)
00804          iks_delete(instructions);
00805    }
00806    ASTOBJ_UNREF(client, aji_client_destroy);
00807    return IKS_FILTER_EAT;
00808 }

static int aji_reload ( void   )  [static]

Definition at line 2440 of file res_jabber.c.

References aji_client_destroy(), AJI_CONNECTING, AJI_DISCONNECTED, aji_get_roster(), aji_load_config(), aji_recv_loop(), ast_log(), ast_pthread_create_background, ASTOBJ_CONTAINER_MARKALL, ASTOBJ_CONTAINER_PRUNE_MARKED, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_RDLOCK, ASTOBJ_UNLOCK, clients, and LOG_ERROR.

Referenced by aji_do_reload(), load_module(), and reload().

02441 {
02442    ASTOBJ_CONTAINER_MARKALL(&clients);
02443    if (!aji_load_config()) {
02444       ast_log(LOG_ERROR, "JABBER: Failed to load config.\n");
02445       return 0;
02446    }
02447    ASTOBJ_CONTAINER_PRUNE_MARKED(&clients, aji_client_destroy);
02448    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02449       ASTOBJ_RDLOCK(iterator);
02450       if(iterator->state == AJI_DISCONNECTED) {
02451          if (!iterator->thread)
02452             ast_pthread_create_background(&iterator->thread, NULL, aji_recv_loop, iterator);
02453       } else if (iterator->state == AJI_CONNECTING)
02454          aji_get_roster(iterator);
02455       ASTOBJ_UNLOCK(iterator);
02456    });
02457    
02458    return 1;
02459 }

static int aji_send_exec ( struct ast_channel chan,
void *  data 
) [static]

Dial plan function to send a message.

Parameters:
channel,and data, data is sender, reciever, message.
Returns:
0.

Definition at line 425 of file res_jabber.c.

References ast_aji_get_client(), ast_aji_send(), ast_log(), ast_strdupa, LOG_ERROR, LOG_WARNING, and s.

Referenced by load_module().

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 }

static void aji_set_presence ( struct aji_client client,
char *  to,
char *  from,
int  level,
char *  desc 
) [static]

set presence of client.

Parameters:
aji_client struct, user to send it to, and from, level, description.
Returns:
void.

Definition at line 1942 of file res_jabber.c.

References ast_log(), LOG_ERROR, and aji_client::p.

Referenced by aji_get_roster(), aji_handle_presence(), and aji_handle_subscribe().

01943 {
01944    int res = 0;
01945    iks *presence = iks_make_pres(level, desc);
01946    iks *cnode = iks_new("c");
01947    iks *priority = iks_new("priority");
01948 
01949    iks_insert_cdata(priority, "0", 1);
01950    if (presence && cnode && client) {
01951       if(to)
01952          iks_insert_attrib(presence, "to", to);
01953       if(from)
01954          iks_insert_attrib(presence, "from", from);
01955       iks_insert_attrib(cnode, "node", "http://www.asterisk.org/xmpp/client/caps");
01956       iks_insert_attrib(cnode, "ver", "asterisk-xmpp");
01957       iks_insert_attrib(cnode, "ext", "voice-v1");
01958       iks_insert_attrib(cnode, "xmlns", "http://jabber.org/protocol/caps");
01959       iks_insert_node(presence, cnode);
01960       res = iks_send(client->p, presence);
01961    } else
01962       ast_log(LOG_ERROR, "Out of memory.\n");
01963    if (cnode)
01964       iks_delete(cnode);
01965    if (presence)
01966       iks_delete(presence);
01967 }

static int aji_show_clients ( int  fd,
int  argc,
char *  argv[] 
) [static]

show client status.

Parameters:
fd,number of args, args.
Returns:
RESULT_SUCCESS.

Definition at line 2018 of file res_jabber.c.

References AJI_CONNECTED, AJI_CONNECTING, AJI_DISCONNECTED, ast_cli(), ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_RDLOCK, ASTOBJ_UNLOCK, and clients.

02019 {
02020    char *status;
02021    int count = 0;
02022    ast_cli(fd, "Jabber Users and their status:\n");
02023    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02024       ASTOBJ_RDLOCK(iterator);
02025       count++;
02026       switch (iterator->state) {
02027       case AJI_DISCONNECTED:
02028          status = "Disconnected";
02029          break;
02030       case AJI_CONNECTING:
02031          status = "Connecting";
02032          break;
02033       case AJI_CONNECTED:
02034          status = "Connected";
02035          break;
02036       default:
02037          status = "Unknown";
02038       }
02039       ast_cli(fd, "       User: %s     - %s\n", iterator->user, status);
02040       ASTOBJ_UNLOCK(iterator);
02041    });
02042    ast_cli(fd, "----\n");
02043    ast_cli(fd, "   Number of users: %d\n", count);
02044    return RESULT_SUCCESS;
02045 }

static int aji_status_exec ( struct ast_channel chan,
void *  data 
) [static]

Dial plan function status(). puts the status of watched user into a channel variable.

Parameters:
channel,and username,watched user, status var
Returns:
0.

Definition at line 361 of file res_jabber.c.

References aji_find_resource(), ast_aji_get_client(), ast_log(), ast_strdupa, ASTOBJ_CONTAINER_FIND, aji_client::buddies, LOG_ERROR, LOG_NOTICE, LOG_WARNING, pbx_builtin_setvar_helper(), aji_resource::resource, aji_buddy::resources, s, and aji_resource::status.

Referenced by load_module().

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 }

static int aji_test ( int  fd,
int  argc,
char *  argv[] 
) [static]

send test message for debugging.

Parameters:
fd,number of args, args.
Returns:
RESULT_SUCCESS.

Definition at line 2052 of file res_jabber.c.

References ast_aji_send(), ast_cli(), ast_verbose(), ASTOBJ_CONTAINER_FIND, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_RDLOCK, ASTOBJ_UNLOCK, aji_client::buddies, aji_resource::cap, clients, aji_resource::description, aji_version::jingle, name, aji_resource::next, aji_capabilities::node, aji_version::parent, aji_resource::priority, aji_resource::resource, RESULT_FAILURE, RESULT_SHOWUSAGE, S_OR, aji_resource::status, and aji_version::version.

02053 {
02054    struct aji_client *client;
02055    struct aji_resource *resource;
02056    const char *name = "asterisk";
02057    struct aji_message *tmp;
02058 
02059    if (argc > 3)
02060       return RESULT_SHOWUSAGE;
02061    else if (argc == 3)
02062       name = argv[2];
02063 
02064    if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
02065       ast_cli(fd, "Unable to find client '%s'!\n", name);
02066       return RESULT_FAILURE;
02067    }
02068 
02069    /* XXX Does Matt really want everyone to use his personal address for tests? */ /* XXX yes he does */
02070    ast_aji_send(client, "mogorman@astjab.org", "blahblah");
02071    ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02072       ASTOBJ_RDLOCK(iterator);
02073       ast_verbose("User: %s\n", iterator->name);
02074       for (resource = iterator->resources; resource; resource = resource->next) {
02075          ast_verbose("Resource: %s\n", resource->resource);
02076          if(resource->cap) {
02077             ast_verbose("   client: %s\n", resource->cap->parent->node);
02078             ast_verbose("   version: %s\n", resource->cap->version);
02079             ast_verbose("   Jingle Capable: %d\n", resource->cap->jingle);
02080          }
02081          ast_verbose("  Priority: %d\n", resource->priority);
02082          ast_verbose("  Status: %d\n", resource->status); 
02083          ast_verbose("  Message: %s\n", S_OR(resource->description,"")); 
02084       }
02085       ASTOBJ_UNLOCK(iterator);
02086    });
02087    ast_verbose("\nOooh a working message stack!\n");
02088    AST_LIST_LOCK(&client->messages);
02089    AST_LIST_TRAVERSE(&client->messages, tmp, list) {
02090       ast_verbose("  Message from: %s with id %s @ %s %s\n",tmp->from, S_OR(tmp->id,""), ctime(&tmp->arrived), S_OR(tmp->message, ""));
02091    }
02092    AST_LIST_UNLOCK(&client->messages);
02093    ASTOBJ_UNREF(client, aji_client_destroy);
02094 
02095    return RESULT_SUCCESS;
02096 }

int ast_aji_create_chat ( struct aji_client client,
char *  room,
char *  server,
char *  topic 
)

create a chatroom.

Parameters:
aji_client struct , room, server, topic for the room.
Returns:
0.

Definition at line 1452 of file res_jabber.c.

References ast_aji_increment_mid(), ast_log(), LOG_ERROR, aji_client::mid, and aji_client::p.

01453 {
01454    int res = 0;
01455    iks *iq = NULL;
01456    iq = iks_new("iq");
01457 
01458    if (iq && client) {
01459       iks_insert_attrib(iq, "type", "get");
01460       iks_insert_attrib(iq, "to", server);
01461       iks_insert_attrib(iq, "id", client->mid);
01462       ast_aji_increment_mid(client->mid);
01463       iks_send(client->p, iq);
01464    } else 
01465       ast_log(LOG_ERROR, "Out of memory.\n");
01466 
01467    iks_delete(iq);
01468 
01469    return res;
01470 }

int ast_aji_disconnect ( struct aji_client client  ) 

disconnect from jabber server.

Parameters:
aji_client struct.
Returns:
1.

Definition at line 1924 of file res_jabber.c.

References aji_client_destroy(), ast_verbose(), ASTOBJ_UNREF, option_verbose, aji_client::p, and VERBOSE_PREFIX_3.

Referenced by unload_module().

01925 {
01926    if (client) {
01927       if (option_verbose > 3)
01928          ast_verbose(VERBOSE_PREFIX_3 "JABBER: Disconnecting\n");
01929       iks_disconnect(client->p);
01930       iks_parser_delete(client->p);
01931       ASTOBJ_UNREF(client, aji_client_destroy);
01932    }
01933 
01934    return 1;
01935 }

struct aji_client* ast_aji_get_client ( const char *  name  ) 

grab a aji_client structure by label name or JID (without the resource string)

Parameters:
name label or JID
Returns:
aji_client.

Definition at line 2364 of file res_jabber.c.

References ast_strdupa, ASTOBJ_CONTAINER_FIND, ASTOBJ_CONTAINER_TRAVERSE, and clients.

Referenced by aji_send_exec(), aji_status_exec(), gtalk_create_member(), gtalk_newcall(), gtalk_request(), and manager_jabber_send().

02365 {
02366    struct aji_client *client = NULL;
02367    char *aux = NULL;
02368 
02369    client = ASTOBJ_CONTAINER_FIND(&clients, name);
02370    if (!client && strchr(name, '@')) {
02371       ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02372          aux = ast_strdupa(iterator->user);
02373          if (strchr(aux, '/')) {
02374             /* strip resource for comparison */
02375             aux = strsep(&aux, "/");
02376          }
02377          if (!strncasecmp(aux, name, strlen(aux))) {
02378             client = iterator;
02379          }           
02380       });
02381    }
02382  
02383    return client;
02384 }

struct aji_client_container* ast_aji_get_clients ( void   ) 

Definition at line 2386 of file res_jabber.c.

References clients.

02387 {
02388    return &clients;
02389 }

void ast_aji_increment_mid ( char *  mid  ) 

increments the mid field for messages and other events.

Parameters:
message id.
Returns:
void.

Definition at line 1584 of file res_jabber.c.

Referenced by aji_act_hook(), aji_handle_presence(), aji_register_approve_handler(), ast_aji_create_chat(), ast_aji_invite_chat(), gtalk_action(), gtalk_create_candidates(), gtalk_digit(), gtalk_invite(), and gtalk_invite_response().

01585 {
01586    int i = 0;
01587 
01588    for (i = strlen(mid) - 1; i >= 0; i--) {
01589       if (mid[i] != 'z') {
01590          mid[i] = mid[i] + 1;
01591          i = 0;
01592       } else
01593          mid[i] = 'a';
01594    }
01595 }

int ast_aji_invite_chat ( struct aji_client client,
char *  user,
char *  room,
char *  message 
)

invite to a chatroom.

Parameters:
aji_client struct ,user, room, message.
Returns:
res.

Definition at line 1505 of file res_jabber.c.

References ast_aji_increment_mid(), ast_log(), LOG_ERROR, aji_client::mid, and aji_client::p.

01506 {
01507    int res = 0;
01508    iks *invite, *body, *namespace;
01509 
01510    invite = iks_new("message");
01511    body = iks_new("body");
01512    namespace = iks_new("x");
01513    if (client && invite && body && namespace) {
01514       iks_insert_attrib(invite, "to", user);
01515       iks_insert_attrib(invite, "id", client->mid);
01516       ast_aji_increment_mid(client->mid);
01517       iks_insert_cdata(body, message, 0);
01518       iks_insert_attrib(namespace, "xmlns", "jabber:x:conference");
01519       iks_insert_attrib(namespace, "jid", room);
01520       iks_insert_node(invite, body);
01521       iks_insert_node(invite, namespace);
01522       res = iks_send(client->p, invite);
01523    } else 
01524       ast_log(LOG_ERROR, "Out of memory.\n");
01525    if (body)
01526       iks_delete(body);
01527    if (namespace)
01528       iks_delete(namespace);
01529    if (invite)
01530       iks_delete(invite);
01531    return res;
01532 }

int ast_aji_join_chat ( struct aji_client client,
char *  room 
)

join a chatroom.

Parameters:
aji_client struct , room.
Returns:
res.

Definition at line 1477 of file res_jabber.c.

References ast_log(), LOG_ERROR, and aji_client::p.

01478 {
01479    int res = 0;
01480    iks *presence = NULL, *priority = NULL;
01481    presence = iks_new("presence");
01482    priority = iks_new("priority");
01483    if (presence && priority && client) {
01484       iks_insert_cdata(priority, "0", 1);
01485       iks_insert_attrib(presence, "to", room);
01486       iks_insert_node(presence, priority);
01487       res = iks_send(client->p, presence);
01488       iks_insert_cdata(priority, "5", 1);
01489       iks_insert_attrib(presence, "to", room);
01490       res = iks_send(client->p, presence);
01491    } else 
01492       ast_log(LOG_ERROR, "Out of memory.\n");
01493    if (presence)
01494       iks_delete(presence);
01495    if (priority)
01496       iks_delete(priority);
01497    return res;
01498 }

int ast_aji_send ( struct aji_client client,
const char *  address,
const char *  message 
)

sends messages.

Parameters:
aji_client struct , reciever, message.
Returns:
1.

Definition at line 1428 of file res_jabber.c.

References AJI_CONNECTED, ast_log(), aji_client::jid, LOG_ERROR, LOG_WARNING, aji_client::p, and aji_client::state.

Referenced by aji_send_exec(), aji_test(), and manager_jabber_send().

01429 {
01430    int res = 0;
01431    iks *message_packet = NULL;
01432    if (client->state == AJI_CONNECTED) {
01433       message_packet = iks_make_msg(IKS_TYPE_CHAT, address, message);
01434       if (message_packet) {
01435          iks_insert_attrib(message_packet, "from", client->jid->full);
01436          res = iks_send(client->p, message_packet);
01437       } else {
01438          ast_log(LOG_ERROR, "Out of memory.\n");
01439       }
01440       if (message_packet)
01441          iks_delete(message_packet);
01442    } else
01443       ast_log(LOG_WARNING, "JABBER: Not connected can't send\n");
01444    return 1;
01445 }

static int gtalk_yuck ( iks *  node  )  [static]

Definition at line 310 of file res_jabber.c.

Referenced by aji_handle_presence().

00311 {
00312    if (iks_find_with_attrib(node, "c", "node", "http://www.google.com/xmpp/client/caps"))
00313       return 1;
00314    return 0;
00315 }

static iks * jabber_make_auth ( iksid *  id,
const char *  pass,
const char *  sid 
) [static]

Definition at line 334 of file res_jabber.c.

References ast_sha1_hash().

Referenced by aji_act_hook().

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 }

static int load_module ( void   )  [static]

Definition at line 2494 of file res_jabber.c.

References aji_cli, aji_reload(), aji_send_exec(), aji_status_exec(), ast_cli_register_multiple(), ast_manager_register2(), AST_MODULE_LOAD_DECLINE, ast_register_application(), ASTOBJ_CONTAINER_INIT, clients, EVENT_FLAG_SYSTEM, manager_jabber_send(), and mandescr_jabber_send.

static int manager_jabber_send ( struct mansession s,
const struct message m 
) [static]

Send a Jabber Message via call from the Manager.

Definition at line 2399 of file res_jabber.c.

References ast_aji_get_client(), ast_aji_send(), ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), astman_send_error(), and s.

Referenced by load_module().

02400 {
02401    struct aji_client *client = NULL;
02402    const char *id = astman_get_header(m,"ActionID");
02403    const char *jabber = astman_get_header(m,"Jabber");
02404    const char *screenname = astman_get_header(m,"ScreenName");
02405    const char *message = astman_get_header(m,"Message");
02406 
02407    if (ast_strlen_zero(jabber)) {
02408       astman_send_error(s, m, "No transport specified");
02409       return 0;
02410    }
02411    if (ast_strlen_zero(screenname)) {
02412       astman_send_error(s, m, "No ScreenName specified");
02413       return 0;
02414    }
02415    if (ast_strlen_zero(message)) {
02416       astman_send_error(s, m, "No Message specified");
02417       return 0;
02418    }
02419 
02420    astman_send_ack(s, m, "Attempting to send Jabber Message");
02421    client = ast_aji_get_client(jabber);
02422    if (!client) {
02423       astman_send_error(s, m, "Could not find Sender");
02424       return 0;
02425    }  
02426    if (strchr(screenname, '@') && message){
02427       ast_aji_send(client, screenname, message);   
02428       if (!ast_strlen_zero(id))
02429          astman_append(s, "ActionID: %s\r\n",id);
02430       astman_append(s, "Response: Success\r\n");
02431       return 0;
02432    }
02433    if (!ast_strlen_zero(id))
02434       astman_append(s, "ActionID: %s\r\n",id);
02435    astman_append(s, "Response: Failure\r\n");
02436    return 0;
02437 }

static int reload ( void   )  [static]

Definition at line 2508 of file res_jabber.c.

References aji_reload().

02509 {
02510    aji_reload();
02511    return 0;
02512 }

static int unload_module ( void   )  [static]

Definition at line 2461 of file res_jabber.c.

References aji_cli, aji_client_destroy(), AJI_DISCONNECTING, ast_aji_disconnect(), ast_cli_unregister_multiple(), ast_log(), ast_manager_unregister(), ast_unregister_application(), ASTOBJ_CONTAINER_DESTROY, ASTOBJ_CONTAINER_DESTROYALL, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_RDLOCK, ASTOBJ_UNLOCK, clients, LOG_DEBUG, LOG_ERROR, and option_debug.

02462 {
02463 
02464    /* Check if TLS is initialized. If that's the case, we can't unload this
02465       module due to a bug in the iksemel library that will cause a crash or
02466       a deadlock. We're trying to find a way to handle this, but in the meantime
02467       we will simply refuse to die... 
02468     */
02469    if (tls_initialized) {
02470       ast_log(LOG_ERROR, "Module can't be unloaded due to a bug in the Iksemel library when using TLS.\n");
02471       return 1;   /* You need a forced unload to get rid of this module */
02472    }
02473 
02474    ast_cli_unregister_multiple(aji_cli, sizeof(aji_cli) / sizeof(struct ast_cli_entry));
02475    ast_unregister_application(app_ajisend);
02476    ast_unregister_application(app_ajistatus);
02477    ast_manager_unregister("JabberSend");
02478    
02479    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02480       ASTOBJ_RDLOCK(iterator);
02481       if (option_debug > 2)
02482          ast_log(LOG_DEBUG, "JABBER: Releasing and disconneing client: %s\n", iterator->name);
02483       iterator->state = AJI_DISCONNECTING;
02484       ast_aji_disconnect(iterator);
02485       pthread_join(iterator->thread, NULL);
02486       ASTOBJ_UNLOCK(iterator);
02487    });
02488 
02489    ASTOBJ_CONTAINER_DESTROYALL(&clients, aji_client_destroy);
02490    ASTOBJ_CONTAINER_DESTROY(&clients);
02491    return 0;
02492 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_BUILDSUM, .description = "AJI - Asterisk Jabber Interface" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "f450f61f60e761b3aa089ebed76ca8a5" , .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 2518 of file res_jabber.c.

struct ast_cli_entry aji_cli[] [static]

Definition at line 131 of file res_jabber.c.

Referenced by load_module(), and unload_module().

char* ajisend_descrip [static]

Initial value:

"JabberSend(Jabber,ScreenName,Message)\n"
"  Jabber - Client or transport Asterisk uses to connect to Jabber\n" 
"  ScreenName - User Name to message.\n" 
"  Message - Message to be sent to the buddy\n"

Definition at line 157 of file res_jabber.c.

char* ajisend_synopsis = "JabberSend(jabber,screenname,message)" [static]

Definition at line 155 of file res_jabber.c.

char* ajistatus_descrip [static]

Definition at line 167 of file res_jabber.c.

char* ajistatus_synopsis = "JabberStatus(Jabber,ScreenName,Variable)" [static]

Definition at line 165 of file res_jabber.c.

char* app_ajisend = "JabberSend" [static]

Definition at line 153 of file res_jabber.c.

char* app_ajistatus = "JabberStatus" [static]

Definition at line 163 of file res_jabber.c.

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 2518 of file res_jabber.c.

struct aji_capabilities* capabilities = NULL

Definition at line 176 of file res_jabber.c.

Referenced by aji_find_version(), and ast_request().

struct aji_client_container clients

Definition at line 175 of file res_jabber.c.

Referenced by aji_create_client(), aji_do_debug(), aji_no_debug(), aji_reload(), aji_show_clients(), aji_test(), ast_aji_get_client(), ast_aji_get_clients(), gtalk_load_config(), load_module(), and unload_module().

char debug_usage[] [static]

Initial value:

 
"Usage: jabber debug\n" 
"       Enables dumping of Jabber packets for debugging purposes.\n"

Definition at line 114 of file res_jabber.c.

struct ast_flags globalflags = { AJI_AUTOPRUNE | AJI_AUTOREGISTER } [static]

Global flags, initialized to default values.

Definition at line 179 of file res_jabber.c.

char mandescr_jabber_send[] [static]

Definition at line 2391 of file res_jabber.c.

Referenced by load_module().

char no_debug_usage[] [static]

Initial value:

 
"Usage: jabber debug off\n" 
"       Disables dumping of Jabber packets for debugging purposes.\n"

Definition at line 118 of file res_jabber.c.

char reload_usage[] [static]

Initial value:

 
"Usage: jabber reload\n" 
"       Enables reloading of Jabber module.\n"

Definition at line 122 of file res_jabber.c.

char test_usage[] [static]

Initial value:

 
"Usage: jabber test [client]\n" 
"       Sends test message for debugging purposes.  A specific client\n"
"       as configured in jabber.conf can be optionally specified.\n"

Definition at line 126 of file res_jabber.c.

int tls_initialized = FALSE [static]

Definition at line 180 of file res_jabber.c.


Generated on Tue Apr 28 22:50:46 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7