Wed Oct 28 11:46:18 2009

Asterisk developer's documentation


res_jabber.c File Reference

A resource for interfacing Asterisk directly as a client or a component to a XMPP/Jabber compliant server. More...

#include "asterisk.h"
#include <ctype.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/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"

Include dependency graph for res_jabber.c:

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 acf_jabberstatus_read (struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
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)
 Handle add extra info.
static int aji_create_buddy (char *label, struct aji_client *client)
 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)
 Handler of the return info packet.
static int aji_ditems_handler (void *data, ikspak *pak)
 Handles stuff.
static char * aji_do_debug_deprecated (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 Turn on/off console debugging (deprecated, use aji_do_set_debug).
static char * aji_do_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 Reload jabber module.
static char * aji_do_set_debug (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 Turn on/off console debugging.
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)
 Find the aji_resource we want.
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)
 Get the roster of jabber users.
static void aji_handle_iq (struct aji_client *client, iks *node)
 Handles.
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)
 Check the presence info.
static void aji_handle_subscribe (struct aji_client *client, ikspak *pak)
 handles subscription requests.
static int aji_initialize (struct aji_client *client)
 prepares client for connect.
static int aji_io_recv (struct aji_client *client, char *buffer, size_t buf_len, int timeout)
 Secured or unsecured IO socket receiving function.
static int aji_is_secure (struct aji_client *client)
 Tests whether the connection is secured or not.
static int aji_load_config (int reload)
static void aji_log_hook (void *data, const char *xmpp, size_t size, int is_incoming)
 the debug loop.
static void aji_pruneregister (struct aji_client *client)
 goes through roster and prunes users not needed in list, or adds them accordingly.
static int aji_reconnect (struct aji_client *client)
 reconnect to jabber server
static int aji_recv (struct aji_client *client, int timeout)
 Tries to receive data from the Jabber server.
static void * aji_recv_loop (void *data)
 receive message loop.
static int aji_register_approve_handler (void *data, ikspak *pak)
 Unknown.
static int aji_register_query_handler (void *data, ikspak *pak)
 register handler for incoming querys (IQ's)
static int aji_reload (int reload)
 Reload the jabber module.
static int aji_send_exec (struct ast_channel *chan, void *data)
 Dial plan function to send a message.
static int aji_send_header (struct aji_client *client, const char *to)
 Sends XMPP header to the server.
static int aji_send_raw (struct aji_client *client, const char *xmlstr)
 Sends an XML string over an XMPP connection.
static void aji_set_presence (struct aji_client *client, char *to, char *from, int level, char *desc)
 set presence of client.
static char * aji_show_buddies (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 Show buddy lists.
static char * aji_show_clients (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 Show client status.
static int aji_start_sasl (struct aji_client *client, enum ikssasltype type, char *username, char *pass)
 A wrapper function for iks_start_sasl.
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 char * aji_test (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 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.
struct aji_clientast_aji_get_client (const char *name)
 grab a aji_client structure by label name or JID (without the resource string)
struct 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, iks *x)
 Wraps raw sending.
int ast_aji_send_chat (struct aji_client *client, const char *address, const char *message)
 sends messages.
static int gtalk_yuck (iks *node)
 Jabber GTalk function.
static iks * jabber_make_auth (iksid *id, const char *pass, const char *sid)
 Setup the authentication struct.
static int load_module (void)
 Unload the jabber module.
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)
 Wrapper for aji_reload.
static int unload_module (void)
 Unload the jabber module.

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS , .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 = AST_BUILDOPT_SUM, .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_info
ast_module_info = &__mod_info
struct aji_capabilitiescapabilities = NULL
static struct ast_cli_entry cli_aji_do_debug_deprecated = AST_CLI_DEFINE(aji_do_debug_deprecated, "Enable/disable jabber debugging")
struct aji_client_container clients
static struct ast_flags globalflags = { AJI_AUTOREGISTER }
 Global flags, initialized to default values.
static struct ast_custom_function jabberstatus_function
static char mandescr_jabber_send []


Detailed Description

A resource for interfacing Asterisk directly as a client or a component to a XMPP/Jabber compliant server.

References:

ExtRef:
Iksemel http://code.google.com/p/iksemel/
Todo:
If you unload this module, chan_gtalk/jingle will be dead. How do we handle that?
Todo:
Dialplan applications need RETURN variable, like JABBERSENDSTATUS

Definition in file res_jabber.c.


Define Documentation

#define FALSE   0

Definition at line 67 of file res_jabber.c.

#define JABBER_CONFIG   "jabber.conf"

Todo:
This should really be renamed to xmpp.conf. For backwards compatibility, we need to read both files

Definition at line 64 of file res_jabber.c.

Referenced by aji_load_config().

#define TRUE   1

Definition at line 71 of file res_jabber.c.


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 3079 of file res_jabber.c.

static void __unreg_module ( void   )  [static]

Definition at line 3079 of file res_jabber.c.

static int acf_jabberstatus_read ( struct ast_channel chan,
const char *  name,
char *  data,
char *  buf,
size_t  buflen 
) [static]

Definition at line 401 of file res_jabber.c.

References aji_find_resource(), ast_aji_get_client(), AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_NONSTANDARD_APP_ARGS, AST_STANDARD_APP_ARGS, ASTOBJ_CONTAINER_FIND, aji_client::buddies, LOG_ERROR, LOG_NOTICE, LOG_WARNING, aji_resource::resource, aji_buddy::resources, and aji_resource::status.

00402 {
00403    struct aji_client *client = NULL;
00404    struct aji_buddy *buddy = NULL;
00405    struct aji_resource *r = NULL;
00406    int stat = 7;
00407    AST_DECLARE_APP_ARGS(args,
00408       AST_APP_ARG(sender);
00409       AST_APP_ARG(jid);
00410    );
00411    AST_DECLARE_APP_ARGS(jid,
00412       AST_APP_ARG(screenname);
00413       AST_APP_ARG(resource);
00414    );
00415 
00416    if (!data) {
00417       ast_log(LOG_ERROR, "Usage: JABBER_STATUS(<sender>,<jid>[/<resource>])\n");
00418       return 0;
00419    }
00420    AST_STANDARD_APP_ARGS(args, data);
00421 
00422    if (args.argc != 2) {
00423       ast_log(LOG_ERROR, "JABBER_STATUS requires 2 arguments: sender and jid.\n");
00424       return -1;
00425    }
00426 
00427    AST_NONSTANDARD_APP_ARGS(jid, args.jid, '/');
00428 
00429    if (!(client = ast_aji_get_client(args.sender))) {
00430       ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
00431       return -1;
00432    }
00433    buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, jid.screenname);
00434    if (!buddy) {
00435       ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
00436       return -1;
00437    }
00438    r = aji_find_resource(buddy, jid.resource);
00439    if (!r && buddy->resources) 
00440       r = buddy->resources;
00441    if (!r)
00442       ast_log(LOG_NOTICE, "Resource %s of buddy %s was not found.\n", jid.resource, jid.screenname);
00443    else
00444       stat = r->status;
00445    snprintf(buf, buflen, "%d", stat);
00446    return 0;
00447 }

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 864 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_is_secure(), aji_recv(), aji_send_header(), aji_send_raw(), aji_start_sasl(), asprintf, ast_aji_increment_mid(), ast_aji_send(), ast_debug, ast_free, ast_log(), ast_sha1_hash(), ASTOBJ_REF, ASTOBJ_UNREF, aji_client::authorized, aji_client::component, aji_client::f, jabber_make_auth(), aji_client::jid, LOG_ERROR, LOG_WARNING, aji_client::mid, aji_client::password, secret, aji_client::state, aji_client::usesasl, and aji_client::usetls.

00865 {
00866    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00867    ikspak *pak = NULL;
00868    iks *auth = NULL;
00869    int features = 0;
00870 
00871    if(!node) {
00872       ast_log(LOG_ERROR, "aji_act_hook was called with out a packet\n"); /* most likely cause type is IKS_NODE_ERROR lost connection */
00873       ASTOBJ_UNREF(client, aji_client_destroy);
00874       return IKS_HOOK;
00875    }
00876 
00877    if (client->state == AJI_DISCONNECTING) {
00878       ASTOBJ_UNREF(client, aji_client_destroy);
00879       return IKS_HOOK;
00880    }
00881 
00882    pak = iks_packet(node);
00883 
00884    if (!client->component) { /*client */
00885       switch (type) {
00886       case IKS_NODE_START:
00887          if (client->usetls && !aji_is_secure(client)) {
00888 #ifndef HAVE_OPENSSL
00889             ast_log(LOG_ERROR, "OpenSSL not installed. You need to install OpenSSL on this system, or disable the TLS option in your configuration file\n");
00890             ASTOBJ_UNREF(client, aji_client_destroy);
00891             return IKS_HOOK;
00892 #else
00893             if (aji_start_tls(client) == IKS_NET_TLSFAIL) {
00894                ast_log(LOG_ERROR, "Could not start TLS\n");
00895                ASTOBJ_UNREF(client, aji_client_destroy);
00896                return IKS_HOOK;     
00897             }
00898 #endif
00899             break;
00900          }
00901          if (!client->usesasl) {
00902             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);
00903             auth = jabber_make_auth(client->jid, client->password, iks_find_attrib(node, "id"));
00904             if (auth) {
00905                iks_insert_attrib(auth, "id", client->mid);
00906                iks_insert_attrib(auth, "to", client->jid->server);
00907                ast_aji_increment_mid(client->mid);
00908                ast_aji_send(client, auth);
00909                iks_delete(auth);
00910             } else
00911                ast_log(LOG_ERROR, "Out of memory.\n");
00912          }
00913          break;
00914 
00915       case IKS_NODE_NORMAL:
00916 #ifdef HAVE_OPENSSL
00917          if (client->stream_flags & TRY_SECURE) {
00918             if (!strcmp("proceed", iks_name(node))) {
00919                return aji_tls_handshake(client);
00920             }
00921          }
00922 #endif
00923          if (!strcmp("stream:features", iks_name(node))) {
00924             features = iks_stream_features(node);
00925             if (client->usesasl) {
00926                if (client->usetls && !aji_is_secure(client))
00927                   break;
00928                if (client->authorized) {
00929                   if (features & IKS_STREAM_BIND) {
00930                      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);
00931                      auth = iks_make_resource_bind(client->jid);
00932                      if (auth) {
00933                         iks_insert_attrib(auth, "id", client->mid);
00934                         ast_aji_increment_mid(client->mid);
00935                         ast_aji_send(client, auth);
00936                         iks_delete(auth);
00937                      } else {
00938                         ast_log(LOG_ERROR, "Out of memory.\n");
00939                         break;
00940                      }
00941                   }
00942                   if (features & IKS_STREAM_SESSION) {
00943                      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);
00944                      auth = iks_make_session();
00945                      if (auth) {
00946                         iks_insert_attrib(auth, "id", "auth");
00947                         ast_aji_increment_mid(client->mid);
00948                         ast_aji_send(client, auth);
00949                         iks_delete(auth);
00950                      } else {
00951                         ast_log(LOG_ERROR, "Out of memory.\n");
00952                      }
00953                   }
00954                } else {
00955                   int ret;
00956                   if (!client->jid->user) {
00957                      ast_log(LOG_ERROR, "Malformed Jabber ID : %s (domain missing?)\n", client->jid->full);
00958                      break;
00959                   }
00960 
00961                   ret = aji_start_sasl(client, features, client->jid->user, client->password);
00962                   if (ret != IKS_OK) {
00963                      ASTOBJ_UNREF(client, aji_client_destroy);
00964                      return IKS_HOOK;
00965                   }
00966                   break;
00967                }
00968             }
00969          } else if (!strcmp("failure", iks_name(node))) {
00970             ast_log(LOG_ERROR, "JABBER: encryption failure. possible bad password.\n");
00971          } else if (!strcmp("success", iks_name(node))) {
00972             client->authorized = 1;
00973             aji_send_header(client, client->jid->server);
00974          }
00975          break;
00976       case IKS_NODE_ERROR: 
00977             ast_log(LOG_ERROR, "JABBER: Node Error\n");
00978             ASTOBJ_UNREF(client, aji_client_destroy);
00979             return IKS_HOOK;
00980             break;
00981       case IKS_NODE_STOP: 
00982             ast_log(LOG_WARNING, "JABBER: Disconnected\n");
00983             ASTOBJ_UNREF(client, aji_client_destroy);
00984             return IKS_HOOK;
00985             break;
00986       }
00987    } else if (client->state != AJI_CONNECTED && client->component) {
00988       switch (type) {
00989       case IKS_NODE_START:
00990          if (client->state == AJI_DISCONNECTED) {
00991             char secret[160], shasum[320], *handshake;
00992 
00993             sprintf(secret, "%s%s", pak->id, client->password);
00994             ast_sha1_hash(shasum, secret);
00995             handshake = NULL;
00996             if (asprintf(&handshake, "<handshake>%s</handshake>", shasum) >= 0) {
00997                aji_send_raw(client, handshake);
00998                ast_free(handshake);
00999                handshake = NULL;
01000             }
01001             client->state = AJI_CONNECTING;
01002             if(aji_recv(client, 1) == 2) /*XXX proper result for iksemel library on iks_recv of <handshake/> XXX*/
01003                client->state = AJI_CONNECTED;
01004             else
01005                ast_log(LOG_WARNING, "Jabber didn't seem to handshake, failed to authenticate.\n");
01006             break;
01007          }
01008          break;
01009 
01010       case IKS_NODE_NORMAL:
01011          break;
01012 
01013       case IKS_NODE_ERROR:
01014          ast_log(LOG_ERROR, "JABBER: Node Error\n");
01015          ASTOBJ_UNREF(client, aji_client_destroy);
01016          return IKS_HOOK;
01017 
01018       case IKS_NODE_STOP:
01019          ast_log(LOG_WARNING, "JABBER: Disconnected\n");
01020          ASTOBJ_UNREF(client, aji_client_destroy);
01021          return IKS_HOOK;
01022       }
01023    }
01024 
01025    switch (pak->type) {
01026    case IKS_PAK_NONE:
01027       ast_debug(1, "JABBER: I don't know what to do with paktype NONE.\n");
01028       break;
01029    case IKS_PAK_MESSAGE:
01030       aji_handle_message(client, pak);
01031       ast_debug(1, "JABBER: Handling paktype MESSAGE.\n");
01032       break;
01033    case IKS_PAK_PRESENCE:
01034       aji_handle_presence(client, pak);
01035       ast_debug(1, "JABBER: Handling paktype PRESENCE\n");
01036       break;
01037    case IKS_PAK_S10N:
01038       aji_handle_subscribe(client, pak);
01039       ast_debug(1, "JABBER: Handling paktype S10N\n");
01040       break;
01041    case IKS_PAK_IQ:
01042       ast_debug(1, "JABBER: Handling paktype IQ\n");
01043       aji_handle_iq(client, node);
01044       break;
01045    default:
01046       ast_debug(1, "JABBER: I don't know anything about paktype '%d'\n", pak->type);
01047       break;
01048    }
01049    
01050    iks_filter_packet(client->f, pak);
01051 
01052    if (node)
01053       iks_delete(node);
01054 
01055    ASTOBJ_UNREF(client, aji_client_destroy);
01056    return IKS_OK;
01057 }

static void aji_buddy_destroy ( struct aji_buddy obj  )  [static]

Deletes the aji_buddy data structure.

Parameters:
obj aji_buddy The structure we will delete.
Returns:
void.

Definition at line 193 of file res_jabber.c.

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

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

00194 {
00195    struct aji_resource *tmp;
00196 
00197    while ((tmp = obj->resources)) {
00198       obj->resources = obj->resources->next;
00199       ast_free(tmp->description);
00200       ast_free(tmp);
00201    }
00202 
00203    ast_free(obj);
00204 }

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

connects as a client to jabber server.

Parameters:
data void
pak ikspak iksemel packet
Returns:
res.

Definition at line 2247 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().

02248 {
02249    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
02250    int res = 0;
02251 
02252    if (client) {
02253       if (client->state == AJI_DISCONNECTED) {
02254          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);
02255          client->state = AJI_CONNECTING;
02256          client->jid = (iks_find_cdata(pak->query, "jid")) ? iks_id_new(client->stack, iks_find_cdata(pak->query, "jid")) : client->jid;
02257          iks_filter_remove_hook(client->f, aji_client_connect);
02258          if(!client->component) /*client*/
02259             aji_get_roster(client);
02260       }
02261    } else
02262       ast_log(LOG_ERROR, "Out of memory.\n");
02263 
02264    ASTOBJ_UNREF(client, aji_client_destroy);
02265    return res;
02266 }

static void aji_client_destroy ( struct aji_client obj  )  [static]

Deletes the aji_client data structure.

Parameters:
obj aji_client The structure we will delete.
Returns:
void.

Definition at line 169 of file res_jabber.c.

References aji_buddy_destroy(), ast_free, AST_LIST_HEAD_DESTROY, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, ASTOBJ_CONTAINER_DESTROY, ASTOBJ_CONTAINER_DESTROYALL, aji_client::buddies, aji_client::f, 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_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().

00170 {
00171    struct aji_message *tmp;
00172    ASTOBJ_CONTAINER_DESTROYALL(&obj->buddies, aji_buddy_destroy);
00173    ASTOBJ_CONTAINER_DESTROY(&obj->buddies);
00174    iks_filter_delete(obj->f);
00175    iks_parser_delete(obj->p);
00176    iks_stack_delete(obj->stack);
00177    AST_LIST_LOCK(&obj->messages);
00178    while ((tmp = AST_LIST_REMOVE_HEAD(&obj->messages, list))) {
00179       if (tmp->from)
00180          ast_free(tmp->from);
00181       if (tmp->message)
00182          ast_free(tmp->message);
00183    }
00184    AST_LIST_HEAD_DESTROY(&obj->messages);
00185    ast_free(obj);
00186 }

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

Handle add extra info.

Parameters:
data void
pak ikspak
Returns:
IKS_FILTER_EAT

Definition at line 1273 of file res_jabber.c.

References aji_client_destroy(), aji_find_resource(), ast_aji_send(), 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, and aji_resource::resource.

01274 {
01275    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01276    struct aji_resource *resource = NULL;
01277    struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01278 
01279    resource = aji_find_resource(buddy, pak->from->resource);
01280    if (pak->subtype == IKS_TYPE_RESULT) {
01281       if (!resource) {
01282          ast_log(LOG_NOTICE, "JABBER: Received client info from %s when not requested.\n", pak->from->full);
01283          ASTOBJ_UNREF(client, aji_client_destroy);
01284          return IKS_FILTER_EAT;
01285       }
01286       if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
01287          resource->cap->jingle = 1;
01288       } else
01289          resource->cap->jingle = 0;
01290    } else if (pak->subtype == IKS_TYPE_GET) {
01291       iks *iq, *disco, *ident, *google, *query;
01292       iq = iks_new("iq");
01293       query = iks_new("query");
01294       ident = iks_new("identity");
01295       disco = iks_new("feature");
01296       google = iks_new("feature");
01297       if (iq && ident && disco && google) {
01298          iks_insert_attrib(iq, "from", client->jid->full);
01299          iks_insert_attrib(iq, "to", pak->from->full);
01300          iks_insert_attrib(iq, "type", "result");
01301          iks_insert_attrib(iq, "id", pak->id);
01302          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01303          iks_insert_attrib(ident, "category", "client");
01304          iks_insert_attrib(ident, "type", "pc");
01305          iks_insert_attrib(ident, "name", "asterisk");
01306          iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco#info");
01307          iks_insert_attrib(google, "var", "http://www.google.com/xmpp/protocol/voice/v1");
01308          iks_insert_node(iq, query);
01309          iks_insert_node(query, ident);
01310          iks_insert_node(query, google);
01311          iks_insert_node(query, disco);
01312          ast_aji_send(client, iq);
01313       } else
01314          ast_log(LOG_ERROR, "Out of Memory.\n");
01315 
01316       iks_delete(iq);
01317       iks_delete(query);
01318       iks_delete(ident);
01319       iks_delete(google);
01320       iks_delete(disco);
01321    } else if (pak->subtype == IKS_TYPE_ERROR) {
01322       ast_log(LOG_NOTICE, "User %s does not support discovery.\n", pak->from->full);
01323    }
01324    ASTOBJ_UNREF(client, aji_client_destroy);
01325    return IKS_FILTER_EAT;
01326 }

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

creates buddy.

Parameters:
label char.
client the configured XMPP client we use to connect to a XMPP server
Returns:
1 on success, 0 on failure. load config file.

1.

Definition at line 2848 of file res_jabber.c.

References aji_buddy_destroy(), ast_calloc, 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, and aji_buddy::name.

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

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

creates aji_client structure.

Parameters:
label 
var ast_variable
debug 
Returns:
0.

Definition at line 2620 of file res_jabber.c.

References AJI_AUTOPRUNE, AJI_AUTOREGISTER, aji_create_buddy(), AJI_DISCONNECTED, ast_calloc, 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_MARKALL, ASTOBJ_INIT, ASTOBJ_UNMARK, ASTOBJ_WRLOCK, aji_client::authorized, aji_client::buddies, clients, aji_client::component, aji_client::debug, aji_client::flags, aji_client::forcessl, aji_client::keepalive, LOG_ERROR, LOG_WARNING, aji_client::message_timeout, aji_client::messages, aji_client::mid, ast_variable::name, aji_client::name, ast_variable::next, aji_client::password, aji_client::port, aji_client::priority, aji_client::serverhost, aji_client::state, aji_client::status, aji_client::statusmessage, aji_client::timeout, aji_client::user, aji_client::usesasl, aji_client::usetls, and ast_variable::value.

Referenced by aji_load_config().

02621 {
02622    char *resource;
02623    struct aji_client *client = NULL;
02624    int flag = 0;
02625 
02626    client = ASTOBJ_CONTAINER_FIND(&clients,label);
02627    if (!client) {
02628       flag = 1;
02629       client = ast_calloc(1, sizeof(*client));
02630       if (!client) {
02631          ast_log(LOG_ERROR, "Out of memory!\n");
02632          return 0;
02633       }
02634       ASTOBJ_INIT(client);
02635       ASTOBJ_WRLOCK(client);
02636       ASTOBJ_CONTAINER_INIT(&client->buddies);
02637    } else {
02638       ASTOBJ_WRLOCK(client);
02639       ASTOBJ_UNMARK(client);
02640    }
02641    ASTOBJ_CONTAINER_MARKALL(&client->buddies);
02642    ast_copy_string(client->name, label, sizeof(client->name));
02643    ast_copy_string(client->mid, "aaaaa", sizeof(client->mid));
02644 
02645    /* Set default values for the client object */
02646    client->debug = debug;
02647    ast_copy_flags(&client->flags, &globalflags, AST_FLAGS_ALL);
02648    client->port = 5222;
02649    client->usetls = 1;
02650    client->usesasl = 1;
02651    client->forcessl = 0;
02652    client->keepalive = 1;
02653    client->timeout = 50;
02654    client->message_timeout = 100;
02655    AST_LIST_HEAD_INIT(&client->messages);
02656    client->component = 0;
02657    ast_copy_string(client->statusmessage, "Online and Available", sizeof(client->statusmessage));
02658    client->priority = 0;
02659    client->status = IKS_SHOW_AVAILABLE;
02660 
02661    if (flag) {
02662       client->authorized = 0;
02663       client->state = AJI_DISCONNECTED;
02664    }
02665    while (var) {
02666       if (!strcasecmp(var->name, "username"))
02667          ast_copy_string(client->user, var->value, sizeof(client->user));
02668       else if (!strcasecmp(var->name, "serverhost"))
02669          ast_copy_string(client->serverhost, var->value, sizeof(client->serverhost));
02670       else if (!strcasecmp(var->name, "secret"))
02671          ast_copy_string(client->password, var->value, sizeof(client->password));
02672       else if (!strcasecmp(var->name, "statusmessage"))
02673          ast_copy_string(client->statusmessage, var->value, sizeof(client->statusmessage));
02674       else if (!strcasecmp(var->name, "port"))
02675          client->port = atoi(var->value);
02676       else if (!strcasecmp(var->name, "timeout"))
02677          client->message_timeout = atoi(var->value);
02678       else if (!strcasecmp(var->name, "debug"))
02679          client->debug = (ast_false(var->value)) ? 0 : 1;
02680       else if (!strcasecmp(var->name, "type")) {
02681          if (!strcasecmp(var->value, "component"))
02682             client->component = 1;
02683       } else if (!strcasecmp(var->name, "usetls")) {
02684          client->usetls = (ast_false(var->value)) ? 0 : 1;
02685       } else if (!strcasecmp(var->name, "usesasl")) {
02686          client->usesasl = (ast_false(var->value)) ? 0 : 1;
02687       } else if (!strcasecmp(var->name, "forceoldssl"))
02688          client->forcessl = (ast_false(var->value)) ? 0 : 1;
02689       else if (!strcasecmp(var->name, "keepalive"))
02690          client->keepalive = (ast_false(var->value)) ? 0 : 1;
02691       else if (!strcasecmp(var->name, "autoprune"))
02692          ast_set2_flag(&client->flags, ast_true(var->value), AJI_AUTOPRUNE);
02693       else if (!strcasecmp(var->name, "autoregister"))
02694          ast_set2_flag(&client->flags, ast_true(var->value), AJI_AUTOREGISTER);
02695       else if (!strcasecmp(var->name, "buddy"))
02696          aji_create_buddy((char *)var->value, client);
02697       else if (!strcasecmp(var->name, "priority"))
02698          client->priority = atoi(var->value);
02699       else if (!strcasecmp(var->name, "status")) {
02700          if (!strcasecmp(var->value, "unavailable"))
02701             client->status = IKS_SHOW_UNAVAILABLE;
02702          else
02703          if (!strcasecmp(var->value, "available")
02704           || !strcasecmp(var->value, "online"))
02705             client->status = IKS_SHOW_AVAILABLE;
02706          else
02707          if (!strcasecmp(var->value, "chat")
02708           || !strcasecmp(var->value, "chatty"))
02709             client->status = IKS_SHOW_CHAT;
02710          else
02711          if (!strcasecmp(var->value, "away"))
02712             client->status = IKS_SHOW_AWAY;
02713          else
02714          if (!strcasecmp(var->value, "xa")
02715           || !strcasecmp(var->value, "xaway"))
02716             client->status = IKS_SHOW_XA;
02717          else
02718          if (!strcasecmp(var->value, "dnd"))
02719             client->status = IKS_SHOW_DND;
02720          else
02721          if (!strcasecmp(var->value, "invisible"))
02722          #ifdef IKS_SHOW_INVISIBLE
02723             client->status = IKS_SHOW_INVISIBLE;
02724          #else
02725          {
02726             ast_log(LOG_WARNING, "Your iksemel doesn't support invisible status: falling back to DND\n");
02727             client->status = IKS_SHOW_DND;
02728          }
02729          #endif
02730          else
02731             ast_log(LOG_WARNING, "Unknown presence status: %s\n", var->value);
02732       }
02733    /* no transport support in this version */
02734    /* else if (!strcasecmp(var->name, "transport"))
02735             aji_create_transport(var->value, client);
02736    */
02737       var = var->next;
02738    }
02739    if (!flag) {
02740       ASTOBJ_UNLOCK(client);
02741       ASTOBJ_UNREF(client, aji_client_destroy);
02742       return 1;
02743    }
02744 
02745    ast_copy_string(client->name_space, (client->component) ? "jabber:component:accept" : "jabber:client", sizeof(client->name_space));
02746    client->p = iks_stream_new(client->name_space, client, aji_act_hook);
02747    if (!client->p) {
02748       ast_log(LOG_ERROR, "Failed to create stream for client '%s'!\n", client->name);
02749       return 0;
02750    }
02751    client->stack = iks_stack_new(8192, 8192);
02752    if (!client->stack) {
02753       ast_log(LOG_ERROR, "Failed to allocate stack for client '%s'\n", client->name);
02754       return 0;
02755    }
02756    client->f = iks_filter_new();
02757    if (!client->f) {
02758       ast_log(LOG_ERROR, "Failed to create filter for client '%s'\n", client->name);
02759       return 0;
02760    }
02761    if (!strchr(client->user, '/') && !client->component) { /*client */
02762       resource = NULL;
02763       if (asprintf(&resource, "%s/asterisk", client->user) >= 0) {
02764          client->jid = iks_id_new(client->stack, resource);
02765          ast_free(resource);
02766       }
02767    } else
02768       client->jid = iks_id_new(client->stack, client->user);
02769    if (client->component) {
02770       iks_filter_add_rule(client->f, aji_dinfo_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
02771       iks_filter_add_rule(client->f, aji_ditems_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#items", IKS_RULE_DONE);
02772       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);
02773       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);
02774    } else {
02775       iks_filter_add_rule(client->f, aji_client_info_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
02776    }
02777    if (!strchr(client->user, '/') && !client->component) { /*client */
02778       resource = NULL;
02779       if (asprintf(&resource, "%s/asterisk", client->user) >= 0) {
02780          client->jid = iks_id_new(client->stack, resource);
02781          ast_free(resource);
02782       }
02783    } else
02784       client->jid = iks_id_new(client->stack, client->user);
02785    iks_set_log_hook(client->p, aji_log_hook);
02786    ASTOBJ_UNLOCK(client);
02787    ASTOBJ_CONTAINER_LINK(&clients,client);
02788    return 1;
02789 }

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

Handler of the return info packet.

Parameters:
data aji_client
pak ikspak
Returns:
IKS_FILTER_EAT

Definition at line 1333 of file res_jabber.c.

References aji_client_destroy(), aji_find_resource(), ast_aji_send(), 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_resource::resource, aji_client::user, and version.

01334 {
01335    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01336    char *node = NULL;
01337    struct aji_resource *resource = NULL;
01338    struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01339 
01340    resource = aji_find_resource(buddy, pak->from->resource);
01341    if (pak->subtype == IKS_TYPE_ERROR) {
01342       ast_log(LOG_WARNING, "Received error from a client, turn on jabber debug!\n");
01343       return IKS_FILTER_EAT;
01344    }
01345    if (pak->subtype == IKS_TYPE_RESULT) {
01346       if (!resource) {
01347          ast_log(LOG_NOTICE,"JABBER: Received client info from %s when not requested.\n", pak->from->full);
01348          ASTOBJ_UNREF(client, aji_client_destroy);
01349          return IKS_FILTER_EAT;
01350       }
01351       if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
01352          resource->cap->jingle = 1;
01353       } else
01354          resource->cap->jingle = 0;
01355    } else if (pak->subtype == IKS_TYPE_GET && !(node = iks_find_attrib(pak->query, "node"))) {
01356       iks *iq, *query, *identity, *disco, *reg, *commands, *gateway, *version, *vcard, *search;
01357 
01358       iq = iks_new("iq");
01359       query = iks_new("query");
01360       identity = iks_new("identity");
01361       disco = iks_new("feature");
01362       reg = iks_new("feature");
01363       commands = iks_new("feature");
01364       gateway = iks_new("feature");
01365       version = iks_new("feature");
01366       vcard = iks_new("feature");
01367       search = iks_new("feature");
01368 
01369       if (iq && query && identity && disco && reg && commands && gateway && version && vcard && search && client) {
01370          iks_insert_attrib(iq, "from", client->user);
01371          iks_insert_attrib(iq, "to", pak->from->full);
01372          iks_insert_attrib(iq, "id", pak->id);
01373          iks_insert_attrib(iq, "type", "result");
01374          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01375          iks_insert_attrib(identity, "category", "gateway");
01376          iks_insert_attrib(identity, "type", "pstn");
01377          iks_insert_attrib(identity, "name", "Asterisk The Open Source PBX");
01378          iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco");
01379          iks_insert_attrib(reg, "var", "jabber:iq:register");
01380          iks_insert_attrib(commands, "var", "http://jabber.org/protocol/commands");
01381          iks_insert_attrib(gateway, "var", "jabber:iq:gateway");
01382          iks_insert_attrib(version, "var", "jabber:iq:version");
01383          iks_insert_attrib(vcard, "var", "vcard-temp");
01384          iks_insert_attrib(search, "var", "jabber:iq:search");
01385 
01386          iks_insert_node(iq, query);
01387          iks_insert_node(query, identity);
01388          iks_insert_node(query, disco);
01389          iks_insert_node(query, reg);
01390          iks_insert_node(query, commands);
01391          iks_insert_node(query, gateway);
01392          iks_insert_node(query, version);
01393          iks_insert_node(query, vcard);
01394          iks_insert_node(query, search);
01395          ast_aji_send(client, iq);
01396       } else {
01397          ast_log(LOG_ERROR, "Out of memory.\n");
01398       }
01399 
01400       iks_delete(iq);
01401       iks_delete(query);
01402       iks_delete(identity);
01403       iks_delete(disco);
01404       iks_delete(reg);
01405       iks_delete(commands);
01406       iks_delete(gateway);
01407       iks_delete(version);
01408       iks_delete(vcard);
01409       iks_delete(search);
01410 
01411    } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "http://jabber.org/protocol/commands")) {
01412       iks *iq, *query, *confirm;
01413       iq = iks_new("iq");
01414       query = iks_new("query");
01415       confirm = iks_new("item");
01416 
01417       if (iq && query && confirm && client) {
01418          iks_insert_attrib(iq, "from", client->user);
01419          iks_insert_attrib(iq, "to", pak->from->full);
01420          iks_insert_attrib(iq, "id", pak->id);
01421          iks_insert_attrib(iq, "type", "result");
01422          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01423          iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
01424          iks_insert_attrib(confirm, "node", "confirmaccount");
01425          iks_insert_attrib(confirm, "name", "Confirm AIM account");
01426          iks_insert_attrib(confirm, "jid", client->user);
01427          iks_insert_node(iq, query);
01428          iks_insert_node(query, confirm);
01429          ast_aji_send(client, iq);
01430       } else {
01431          ast_log(LOG_ERROR, "Out of memory.\n");
01432       }
01433 
01434       iks_delete(iq);
01435       iks_delete(query);
01436       iks_delete(confirm);
01437 
01438    } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "confirmaccount")) {
01439       iks *iq, *query, *feature;
01440 
01441       iq = iks_new("iq");
01442       query = iks_new("query");
01443       feature = iks_new("feature");
01444 
01445       if (iq && query && feature && client) {
01446          iks_insert_attrib(iq, "from", client->user);
01447          iks_insert_attrib(iq, "to", pak->from->full);
01448          iks_insert_attrib(iq, "id", pak->id);
01449          iks_insert_attrib(iq, "type", "result");
01450          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01451          iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
01452          iks_insert_node(iq, query);
01453          iks_insert_node(query, feature);
01454          ast_aji_send(client, iq);
01455       } else {
01456          ast_log(LOG_ERROR, "Out of memory.\n");
01457       }
01458 
01459       iks_delete(iq);
01460       iks_delete(query);
01461       iks_delete(feature);
01462    }
01463 
01464    ASTOBJ_UNREF(client, aji_client_destroy);
01465    return IKS_FILTER_EAT;
01466 }

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

Handles stuff.

Parameters:
data void
pak ikspak
Returns:
IKS_FILTER_EAT.

Definition at line 1178 of file res_jabber.c.

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

01179 {
01180    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01181    char *node = NULL;
01182 
01183    if (!(node = iks_find_attrib(pak->query, "node"))) {
01184       iks *iq = NULL, *query = NULL, *item = NULL;
01185       iq = iks_new("iq");
01186       query = iks_new("query");
01187       item = iks_new("item");
01188 
01189       if (iq && query && item) {
01190          iks_insert_attrib(iq, "from", client->user);
01191          iks_insert_attrib(iq, "to", pak->from->full);
01192          iks_insert_attrib(iq, "id", pak->id);
01193          iks_insert_attrib(iq, "type", "result");
01194          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01195          iks_insert_attrib(item, "node", "http://jabber.org/protocol/commands");
01196          iks_insert_attrib(item, "name", "Million Dollar Asterisk Commands");
01197          iks_insert_attrib(item, "jid", client->user);
01198 
01199          iks_insert_node(iq, query);
01200          iks_insert_node(query, item);
01201          ast_aji_send(client, iq);
01202       } else {
01203          ast_log(LOG_ERROR, "Out of memory.\n");
01204       }
01205 
01206       iks_delete(iq);
01207       iks_delete(query);
01208       iks_delete(item);
01209 
01210    } else if (!strcasecmp(node, "http://jabber.org/protocol/commands")) {
01211       iks *iq, *query, *confirm;
01212       iq = iks_new("iq");
01213       query = iks_new("query");
01214       confirm = iks_new("item");
01215       if (iq && query && confirm && client) {
01216          iks_insert_attrib(iq, "from", client->user);
01217          iks_insert_attrib(iq, "to", pak->from->full);
01218          iks_insert_attrib(iq, "id", pak->id);
01219          iks_insert_attrib(iq, "type", "result");
01220          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01221          iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
01222          iks_insert_attrib(confirm, "node", "confirmaccount");
01223          iks_insert_attrib(confirm, "name", "Confirm AIM account");
01224          iks_insert_attrib(confirm, "jid", "blog.astjab.org");
01225 
01226          iks_insert_node(iq, query);
01227          iks_insert_node(query, confirm);
01228          ast_aji_send(client, iq);
01229       } else {
01230          ast_log(LOG_ERROR, "Out of memory.\n");
01231       }
01232 
01233       iks_delete(iq);
01234       iks_delete(query);
01235       iks_delete(confirm);
01236 
01237    } else if (!strcasecmp(node, "confirmaccount")) {
01238       iks *iq = NULL, *query = NULL, *feature = NULL;
01239 
01240       iq = iks_new("iq");
01241       query = iks_new("query");
01242       feature = iks_new("feature");
01243 
01244       if (iq && query && feature && client) {
01245          iks_insert_attrib(iq, "from", client->user);
01246          iks_insert_attrib(iq, "to", pak->from->full);
01247          iks_insert_attrib(iq, "id", pak->id);
01248          iks_insert_attrib(iq, "type", "result");
01249          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01250          iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
01251          iks_insert_node(iq, query);
01252          iks_insert_node(query, feature);
01253          ast_aji_send(client, iq);
01254       } else {
01255          ast_log(LOG_ERROR, "Out of memory.\n");
01256       }
01257 
01258       iks_delete(iq);
01259       iks_delete(query);
01260       iks_delete(feature);
01261    }
01262 
01263    ASTOBJ_UNREF(client, aji_client_destroy);
01264    return IKS_FILTER_EAT;
01265 
01266 }

static char * aji_do_debug_deprecated ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Turn on/off console debugging (deprecated, use aji_do_set_debug).

Returns:
CLI_SUCCESS.

Definition at line 2402 of file res_jabber.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_RDLOCK, ASTOBJ_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, clients, ast_cli_entry::command, ast_cli_args::fd, and ast_cli_entry::usage.

02403 {
02404 
02405    switch (cmd) {
02406    case CLI_INIT:
02407       e->command = "jabber debug [off]";
02408       e->usage =
02409          "Usage: jabber debug [off]\n"
02410          "       Enables/disables dumping of Jabber packets for debugging purposes.\n";
02411       return NULL;
02412    case CLI_GENERATE:
02413       return NULL;
02414    }
02415 
02416    if (a->argc == 2) {
02417       ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02418          ASTOBJ_RDLOCK(iterator); 
02419          iterator->debug = 1;
02420          ASTOBJ_UNLOCK(iterator);
02421       });
02422       ast_cli(a->fd, "Jabber Debugging Enabled.\n");
02423       return CLI_SUCCESS;
02424    } else if (a->argc == 3) {
02425       if (!strncasecmp(a->argv[2], "off", 3)) {
02426          ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02427             ASTOBJ_RDLOCK(iterator); 
02428             iterator->debug = 0;
02429             ASTOBJ_UNLOCK(iterator);
02430          });
02431          ast_cli(a->fd, "Jabber Debugging Disabled.\n");
02432          return CLI_SUCCESS;
02433       }
02434    }
02435    return CLI_SHOWUSAGE; /* defaults to invalid */
02436 }

static char * aji_do_reload ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Reload jabber module.

Returns:
CLI_SUCCESS.

Definition at line 2442 of file res_jabber.c.

References aji_reload(), ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, and ast_cli_entry::usage.

02443 {
02444    switch (cmd) {
02445    case CLI_INIT:
02446       e->command = "jabber reload";
02447       e->usage =
02448          "Usage: jabber reload\n"
02449          "       Reloads the Jabber module.\n";
02450       return NULL;
02451    case CLI_GENERATE:
02452       return NULL;
02453    }
02454 
02455    aji_reload(1);
02456    ast_cli(a->fd, "Jabber Reloaded.\n");
02457    return CLI_SUCCESS;
02458 }

static char * aji_do_set_debug ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Turn on/off console debugging.

Returns:
CLI_SUCCESS.

Definition at line 2362 of file res_jabber.c.

References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_RDLOCK, ASTOBJ_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, clients, ast_cli_entry::command, ast_cli_args::fd, and ast_cli_entry::usage.

02363 {
02364    switch (cmd) {
02365    case CLI_INIT:
02366       e->command = "jabber set debug {on|off}";
02367       e->usage =
02368          "Usage: jabber set debug {on|off}\n"
02369          "       Enables/disables dumping of XMPP/Jabber packets for debugging purposes.\n";
02370       return NULL;
02371    case CLI_GENERATE:
02372       return NULL;
02373    }
02374 
02375    if (a->argc != e->args)
02376       return CLI_SHOWUSAGE;
02377 
02378    if (!strncasecmp(a->argv[e->args - 1], "on", 2)) {
02379       ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02380          ASTOBJ_RDLOCK(iterator); 
02381          iterator->debug = 1;
02382          ASTOBJ_UNLOCK(iterator);
02383       });
02384       ast_cli(a->fd, "Jabber Debugging Enabled.\n");
02385       return CLI_SUCCESS;
02386    } else if (!strncasecmp(a->argv[e->args - 1], "off", 3)) {
02387       ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02388          ASTOBJ_RDLOCK(iterator); 
02389          iterator->debug = 0;
02390          ASTOBJ_UNLOCK(iterator);
02391       });
02392       ast_cli(a->fd, "Jabber Debugging Disabled.\n");
02393       return CLI_SUCCESS;
02394    }
02395    return CLI_SHOWUSAGE; /* defaults to invalid */
02396 }

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

filters the roster packet we get back from server.

Parameters:
data void
pak ikspak iksemel packet.
Returns:
IKS_FILTER_EAT.

Definition at line 2120 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, aji_client::flags, and aji_client::state.

Referenced by aji_client_connect().

02121 {
02122    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
02123    int flag = 0;
02124    iks *x = NULL;
02125    struct aji_buddy *buddy;
02126    
02127    client->state = AJI_CONNECTED;
02128    ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02129       ASTOBJ_RDLOCK(iterator);
02130       x = iks_child(pak->query);
02131       flag = 0;
02132       while (x) {
02133          if (!iks_strcmp(iks_name(x), "item")) {
02134             if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid"))) {
02135                flag = 1;
02136                ast_clear_flag(&iterator->flags, AJI_AUTOPRUNE | AJI_AUTOREGISTER);
02137             }
02138          }
02139          x = iks_next(x);
02140       }
02141       if (!flag)
02142          ast_copy_flags(&iterator->flags, &client->flags, AJI_AUTOREGISTER);
02143       iks_delete(x);
02144       
02145       ASTOBJ_UNLOCK(iterator);
02146    });
02147 
02148    x = iks_child(pak->query);
02149    while (x) {
02150       flag = 0;
02151       if (iks_strcmp(iks_name(x), "item") == 0) {
02152          ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02153             ASTOBJ_RDLOCK(iterator);
02154             if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid")))
02155                flag = 1;
02156             ASTOBJ_UNLOCK(iterator);
02157          });
02158 
02159          if (flag) {
02160             /* found buddy, don't create a new one */
02161             x = iks_next(x);
02162             continue;
02163          }
02164          
02165          buddy = ast_calloc(1, sizeof(*buddy));
02166          if (!buddy) {
02167             ast_log(LOG_WARNING, "Out of memory\n");
02168             return 0;
02169          }
02170          ASTOBJ_INIT(buddy);
02171          ASTOBJ_WRLOCK(buddy);
02172          ast_copy_string(buddy->name, iks_find_attrib(x, "jid"), sizeof(buddy->name));
02173          ast_clear_flag(&buddy->flags, AST_FLAGS_ALL);
02174          if(ast_test_flag(&client->flags, AJI_AUTOPRUNE)) {
02175             ast_set_flag(&buddy->flags, AJI_AUTOPRUNE);
02176             ASTOBJ_MARK(buddy);
02177          } else if (!iks_strcmp(iks_find_attrib(x, "subscription"), "none") || !iks_strcmp(iks_find_attrib(x, "subscription"), "from")) {
02178             /* subscribe to buddy's presence only 
02179                if we really need to */
02180             ast_set_flag(&buddy->flags, AJI_AUTOREGISTER);
02181          }
02182          ASTOBJ_UNLOCK(buddy);
02183          if (buddy) {
02184             ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
02185             ASTOBJ_UNREF(buddy, aji_buddy_destroy);
02186          }
02187       }
02188       x = iks_next(x);
02189    }
02190 
02191    iks_delete(x);
02192    aji_pruneregister(client);
02193 
02194    ASTOBJ_UNREF(client, aji_client_destroy);
02195    return IKS_FILTER_EAT;
02196 }

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

Find the aji_resource we want.

Parameters:
buddy aji_buddy A buddy
name 
Returns:
aji_resource object

Definition at line 282 of file res_jabber.c.

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

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

00283 {
00284    struct aji_resource *res = NULL;
00285    if (!buddy || !name)
00286       return res;
00287    res = buddy->resources;
00288    while (res) {
00289       if (!strcasecmp(res->resource, name)) {
00290          break;
00291       }
00292       res = res->next;
00293    }
00294    return res;
00295 }

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

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 struct The XML stanza we're processing
Returns:
a pointer to the added or found aji_version structure

Definition at line 215 of file res_jabber.c.

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

Referenced by aji_handle_presence().

00216 {
00217    struct aji_capabilities *list = NULL;
00218    struct aji_version *res = NULL;
00219 
00220    list = capabilities;
00221 
00222    if(!node)
00223       node = pak->from->full;
00224    if(!version)
00225       version = "none supplied.";
00226    while(list) {
00227       if(!strcasecmp(list->node, node)) {
00228          res = list->versions;
00229          while(res) {
00230              if(!strcasecmp(res->version, version))
00231                 return res;
00232              res = res->next;
00233          }
00234          /* Specified version not found. Let's add it to 
00235             this node in our capabilities list */
00236          if(!res) {
00237             res = ast_malloc(sizeof(*res));
00238             if(!res) {
00239                ast_log(LOG_ERROR, "Out of memory!\n");
00240                return NULL;
00241             }
00242             res->jingle = 0;
00243             res->parent = list;
00244             ast_copy_string(res->version, version, sizeof(res->version));
00245             res->next = list->versions;
00246             list->versions = res;
00247             return res;
00248          }
00249       }
00250       list = list->next;
00251    }
00252    /* Specified node not found. Let's add it our capabilities list */
00253    if(!list) {
00254       list = ast_malloc(sizeof(*list));
00255       if(!list) {
00256          ast_log(LOG_ERROR, "Out of memory!\n");
00257          return NULL;
00258       }
00259       res = ast_malloc(sizeof(*res));
00260       if(!res) {
00261          ast_log(LOG_ERROR, "Out of memory!\n");
00262          ast_free(list);
00263          return NULL;
00264       }
00265       ast_copy_string(list->node, node, sizeof(list->node));
00266       ast_copy_string(res->version, version, sizeof(res->version));
00267       res->jingle = 0;
00268       res->parent = list;
00269       res->next = NULL;
00270       list->versions = res;
00271       list->next = capabilities;
00272       capabilities = list;
00273    }
00274    return res;
00275 }

static int aji_get_roster ( struct aji_client client  )  [static]

Get the roster of jabber users.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
Returns:
1.

Definition at line 2225 of file res_jabber.c.

References aji_set_presence(), ast_aji_send(), aji_client::jid, aji_client::status, and aji_client::statusmessage.

Referenced by aji_client_connect(), and aji_reload().

02226 {
02227    iks *roster = NULL;
02228    roster = iks_make_iq(IKS_TYPE_GET, IKS_NS_ROSTER);
02229 
02230    if(roster) {
02231       iks_insert_attrib(roster, "id", "roster");
02232       aji_set_presence(client, NULL, client->jid->full, client->status, client->statusmessage);
02233       ast_aji_send(client, roster);
02234    }
02235 
02236    iks_delete(roster);
02237    
02238    return 1;
02239 }

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

Handles.

<iq> 
tags.
Parameters:
client the configured XMPP client we use to connect to a XMPP server
node iks
Returns:
void.

Definition at line 1474 of file res_jabber.c.

Referenced by aji_act_hook().

01475 {
01476    /*Nothing to see here */
01477 }

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

Handles presence packets.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
pak ikspak the node

Definition at line 1484 of file res_jabber.c.

References aji_message::arrived, ast_calloc, ast_copy_string(), ast_free, 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, 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().

01485 {
01486    struct aji_message *insert, *tmp;
01487    int flag = 0;
01488    
01489    if (!(insert = ast_calloc(1, sizeof(*insert))))
01490       return;
01491    time(&insert->arrived);
01492    if (iks_find_cdata(pak->x, "body"))
01493       insert->message = ast_strdup(iks_find_cdata(pak->x, "body"));
01494    if (pak->id)
01495       ast_copy_string(insert->id, pak->id, sizeof(insert->message));
01496    if (pak->from)
01497       insert->from = ast_strdup(pak->from->full);
01498    AST_LIST_LOCK(&client->messages);
01499    AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, tmp, list) {
01500       if (flag) {
01501          AST_LIST_REMOVE_CURRENT(list);
01502          if (tmp->from)
01503             ast_free(tmp->from);
01504          if (tmp->message)
01505             ast_free(tmp->message);
01506       } else if (difftime(time(NULL), tmp->arrived) >= client->message_timeout) {
01507          flag = 1;
01508          AST_LIST_REMOVE_CURRENT(list);
01509          if (tmp->from)
01510             ast_free(tmp->from);
01511          if (tmp->message)
01512             ast_free(tmp->message);
01513       }
01514    }
01515    AST_LIST_TRAVERSE_SAFE_END;
01516    AST_LIST_INSERT_HEAD(&client->messages, insert, list);
01517    AST_LIST_UNLOCK(&client->messages);
01518 }

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

Check the presence info.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
pak ikspak

Definition at line 1524 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_aji_send(), ast_calloc, ast_copy_string(), ast_debug, ast_free, 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, gtalk_yuck(), aji_client::jid, last, LOG_ERROR, LOG_NOTICE, aji_client::mid, aji_resource::next, option_debug, aji_resource::priority, aji_resource::resource, aji_buddy::resources, aji_client::state, aji_resource::status, aji_client::status, status, aji_client::statusmessage, type, and ver.

Referenced by aji_act_hook().

01525 {
01526    int status, priority;
01527    struct aji_buddy *buddy;
01528    struct aji_resource *tmp = NULL, *last = NULL, *found = NULL;
01529    char *ver, *node, *descrip, *type;
01530    
01531    if(client->state != AJI_CONNECTED)
01532       aji_create_buddy(pak->from->partial, client);
01533 
01534    buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01535    if (!buddy && pak->from->partial) {
01536       /* allow our jid to be used to log in with another resource */
01537       if (!strcmp((const char *)pak->from->partial, (const char *)client->jid->partial))
01538          aji_create_buddy(pak->from->partial, client);
01539       else
01540          ast_log(LOG_NOTICE, "Got presence packet from %s, someone not in our roster!!!!\n", pak->from->partial);
01541       return;
01542    }
01543    type = iks_find_attrib(pak->x, "type");
01544    if(client->component && type &&!strcasecmp("probe", type)) {
01545       aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), client->status, client->statusmessage);
01546       ast_verbose("what i was looking for \n");
01547    }
01548    ASTOBJ_WRLOCK(buddy);
01549    status = (pak->show) ? pak->show : 6;
01550    priority = atoi((iks_find_cdata(pak->x, "priority")) ? iks_find_cdata(pak->x, "priority") : "0");
01551    tmp = buddy->resources;
01552    descrip = ast_strdup(iks_find_cdata(pak->x,"status"));
01553 
01554    while (tmp && pak->from->resource) {
01555       if (!strcasecmp(tmp->resource, pak->from->resource)) {
01556          tmp->status = status;
01557          if (tmp->description) ast_free(tmp->description);
01558          tmp->description = descrip;
01559          found = tmp;
01560          if (status == 6) {   /* Sign off Destroy resource */
01561             if (last && found->next) {
01562                last->next = found->next;
01563             } else if (!last) {
01564                if (found->next)
01565                   buddy->resources = found->next;
01566                else
01567                   buddy->resources = NULL;
01568             } else if (!found->next) {
01569                if (last)
01570                   last->next = NULL;
01571                else
01572                   buddy->resources = NULL;
01573             }
01574             ast_free(found);
01575             found = NULL;
01576             break;
01577          }
01578          /* resource list is sorted by descending priority */
01579          if (tmp->priority != priority) {
01580             found->priority = priority;
01581             if (!last && !found->next)
01582                /* resource was found to be unique,
01583                   leave loop */
01584                break;
01585             /* search for resource in our list
01586                and take it out for the moment */
01587             if (last)
01588                last->next = found->next;
01589             else
01590                buddy->resources = found->next;
01591 
01592             last = NULL;
01593             tmp = buddy->resources;
01594             if (!buddy->resources)
01595                buddy->resources = found;
01596             /* priority processing */
01597             while (tmp) {
01598                /* insert resource back according to 
01599                   its priority value */
01600                if (found->priority > tmp->priority) {
01601                   if (last)
01602                      /* insert within list */
01603                      last->next = found;
01604                   found->next = tmp;
01605                   if (!last)
01606                      /* insert on top */
01607                      buddy->resources = found;
01608                   break;
01609                }
01610                if (!tmp->next) {
01611                   /* insert at the end of the list */
01612                   tmp->next = found;
01613                   found->next = NULL;
01614                   break;
01615                }
01616                last = tmp;
01617                tmp = tmp->next;
01618             }
01619          }
01620          break;
01621       }
01622       last = tmp;
01623       tmp = tmp->next;
01624    }
01625 
01626    /* resource not found in our list, create it */
01627    if (!found && status != 6 && pak->from->resource) {
01628       found = ast_calloc(1, sizeof(*found));
01629 
01630       if (!found) {
01631          ast_log(LOG_ERROR, "Out of memory!\n");
01632          return;
01633       }
01634       ast_copy_string(found->resource, pak->from->resource, sizeof(found->resource));
01635       found->status = status;
01636       found->description = descrip;
01637       found->priority = priority;
01638       found->next = NULL;
01639       last = NULL;
01640       tmp = buddy->resources;
01641       while (tmp) {
01642          if (found->priority > tmp->priority) {
01643             if (last)
01644                last->next = found;
01645             found->next = tmp;
01646             if (!last)
01647                buddy->resources = found;
01648             break;
01649          }
01650          if (!tmp->next) {
01651             tmp->next = found;
01652             break;
01653          }
01654          last = tmp;
01655          tmp = tmp->next;
01656       }
01657       if (!tmp)
01658          buddy->resources = found;
01659    }
01660    
01661    ASTOBJ_UNLOCK(buddy);
01662    ASTOBJ_UNREF(buddy, aji_buddy_destroy);
01663 
01664    node = iks_find_attrib(iks_find(pak->x, "c"), "node");
01665    ver = iks_find_attrib(iks_find(pak->x, "c"), "ver");
01666 
01667    /* handle gmail client's special caps:c tag */
01668    if (!node && !ver) {
01669       node = iks_find_attrib(iks_find(pak->x, "caps:c"), "node");
01670       ver = iks_find_attrib(iks_find(pak->x, "caps:c"), "ver");
01671    }
01672 
01673    /* retrieve capabilites of the new resource */
01674    if(status !=6 && found && !found->cap) {
01675       found->cap = aji_find_version(node, ver, pak);
01676       if(gtalk_yuck(pak->x)) /* gtalk should do discover */
01677          found->cap->jingle = 1;
01678       if(found->cap->jingle && option_debug > 4) {
01679          ast_debug(1,"Special case for google till they support discover.\n");
01680       }
01681       else {
01682          iks *iq, *query;
01683          iq = iks_new("iq");
01684          query = iks_new("query");
01685          if(query && iq)  {
01686             iks_insert_attrib(iq, "type", "get");
01687             iks_insert_attrib(iq, "to", pak->from->full);
01688             iks_insert_attrib(iq,"from", client->jid->full);
01689             iks_insert_attrib(iq, "id", client->mid);
01690             ast_aji_increment_mid(client->mid);
01691             iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01692             iks_insert_node(iq, query);
01693             ast_aji_send(client, iq);
01694             
01695          } else
01696             ast_log(LOG_ERROR, "Out of memory.\n");
01697          
01698          iks_delete(query);
01699          iks_delete(iq);
01700       }
01701    }
01702    switch (pak->subtype) {
01703    case IKS_TYPE_AVAILABLE:
01704       ast_debug(3, "JABBER: I am available ^_* %i\n", pak->subtype);
01705       break;
01706    case IKS_TYPE_UNAVAILABLE:
01707       ast_debug(3, "JABBER: I am unavailable ^_* %i\n", pak->subtype);
01708       break;
01709    default:
01710       ast_debug(3, "JABBER: Ohh sexy and the wrong type: %i\n", pak->subtype);
01711    }
01712    switch (pak->show) {
01713    case IKS_SHOW_UNAVAILABLE:
01714       ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01715       break;
01716    case IKS_SHOW_AVAILABLE:
01717       ast_debug(3, "JABBER: type is available\n");
01718       break;
01719    case IKS_SHOW_CHAT:
01720       ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01721       break;
01722    case IKS_SHOW_AWAY:
01723       ast_debug(3, "JABBER: type is away\n");
01724       break;
01725    case IKS_SHOW_XA:
01726       ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01727       break;
01728    case IKS_SHOW_DND:
01729       ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01730       break;
01731    default:
01732       ast_debug(3, "JABBER: Kinky! how did that happen %i\n", pak->show);
01733    }
01734 }

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

handles subscription requests.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
pak ikspak iksemel packet.
Returns:
void.

Definition at line 1742 of file res_jabber.c.

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

Referenced by aji_act_hook().

01743 {
01744    iks *presence = NULL, *status = NULL;
01745    struct aji_buddy* buddy = NULL;
01746 
01747    switch (pak->subtype) { 
01748    case IKS_TYPE_SUBSCRIBE:
01749       presence = iks_new("presence");
01750       status = iks_new("status");
01751       if (presence && status) {
01752          iks_insert_attrib(presence, "type", "subscribed");
01753          iks_insert_attrib(presence, "to", pak->from->full);
01754          iks_insert_attrib(presence, "from", client->jid->full);
01755          if (pak->id)
01756             iks_insert_attrib(presence, "id", pak->id);
01757          iks_insert_cdata(status, "Asterisk has approved subscription", 0);
01758          iks_insert_node(presence, status);
01759          ast_aji_send(client, presence);
01760       } else
01761          ast_log(LOG_ERROR, "Unable to allocate nodes\n");
01762 
01763       iks_delete(presence);
01764       iks_delete(status);
01765 
01766       if (client->component)
01767          aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), client->status, client->statusmessage);
01768    case IKS_TYPE_SUBSCRIBED:
01769       buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01770       if (!buddy && pak->from->partial) {
01771          aji_create_buddy(pak->from->partial, client);
01772       }
01773    default:
01774       if (option_verbose > 4) {
01775          ast_verbose(VERBOSE_PREFIX_3 "JABBER: This is a subcription of type %i\n", pak->subtype);
01776       }
01777    }
01778 }

static int aji_initialize ( struct aji_client client  )  [static]

prepares client for connect.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
Returns:
1.

Definition at line 2273 of file res_jabber.c.

References ast_log(), aji_client::component, 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().

02274 {
02275    int connected = IKS_NET_NOCONN;
02276 
02277 #ifdef HAVE_OPENSSL  
02278    /* reset stream flags */
02279    client->stream_flags = 0;
02280 #endif
02281    /* If it's a component, connect to user, otherwise, connect to server */
02282    connected = iks_connect_via(client->p, S_OR(client->serverhost, client->jid->server), client->port, client->component ? client->user : client->jid->server);
02283 
02284    if (connected == IKS_NET_NOCONN) {
02285       ast_log(LOG_ERROR, "JABBER ERROR: No Connection\n");
02286       return IKS_HOOK;
02287    } else   if (connected == IKS_NET_NODNS) {
02288       ast_log(LOG_ERROR, "JABBER ERROR: No DNS %s for client to  %s\n", client->name, S_OR(client->serverhost, client->jid->server));
02289       return IKS_HOOK;
02290    }
02291 
02292    return IKS_OK;
02293 }

static int aji_io_recv ( struct aji_client client,
char *  buffer,
size_t  buf_len,
int  timeout 
) [static]

Secured or unsecured IO socket receiving function.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
buffer the reception buffer
buf_len the size of the buffer
timeout the select timer
Returns:
the number of read bytes on success, 0 on timeout expiration, -1 on error

Definition at line 589 of file res_jabber.c.

References aji_is_secure(), ast_select(), len(), and aji_client::p.

Referenced by aji_recv().

00590 {
00591    int sock;
00592    fd_set fds;
00593    struct timeval tv, *tvptr = NULL;
00594    int len, res;
00595 
00596 #ifdef HAVE_OPENSSL
00597    if (aji_is_secure(client)) {
00598       sock = SSL_get_fd(client->ssl_session);
00599       if (sock < 0)
00600          return -1;     
00601    } else
00602 #endif /* HAVE_OPENSSL */
00603       sock = iks_fd(client->p);  
00604 
00605    memset(&tv, 0, sizeof(struct timeval));
00606    FD_ZERO(&fds);
00607    FD_SET(sock, &fds);
00608    tv.tv_sec = timeout;
00609 
00610    /* NULL value for tvptr makes ast_select wait indefinitely */
00611    tvptr = (timeout != -1) ? &tv : NULL;
00612 
00613    /* ast_select emulates linux behaviour in terms of timeout handling */
00614    res = ast_select(sock + 1, &fds, NULL, NULL, tvptr);
00615    if (res > 0) {
00616 #ifdef HAVE_OPENSSL
00617       if (aji_is_secure(client)) {
00618          len = SSL_read(client->ssl_session, buffer, buf_len);
00619       } else
00620 #endif /* HAVE_OPENSSL */
00621          len = recv(sock, buffer, buf_len, 0);
00622 
00623       if (len > 0) {
00624          return len;
00625       } else if (len <= 0) {
00626          return -1;
00627       }
00628    }
00629    return res;
00630 }

static int aji_is_secure ( struct aji_client client  )  [static]

Tests whether the connection is secured or not.

Returns:
0 if the connection is not secured

Definition at line 503 of file res_jabber.c.

Referenced by aji_act_hook(), aji_io_recv(), aji_send_raw(), and aji_start_sasl().

00504 {
00505 #ifdef HAVE_OPENSSL
00506    return client->stream_flags & SECURE;
00507 #else
00508    return 0;
00509 #endif
00510 }

static int aji_load_config ( int  reload  )  [static]

Definition at line 2875 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_set_flag, ast_true(), ast_variable_browse(), ast_variable_retrieve(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEUNCHANGED, debug, JABBER_CONFIG, LOG_WARNING, ast_variable::name, ast_variable::next, ast_variable::value, and var.

Referenced by aji_reload().

02876 {
02877    char *cat = NULL;
02878    int debug = 1;
02879    struct ast_config *cfg = NULL;
02880    struct ast_variable *var = NULL;
02881    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
02882 
02883    if ((cfg = ast_config_load(JABBER_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
02884       return -1;
02885 
02886    /* Reset flags to default value */
02887    ast_set_flag(&globalflags, AJI_AUTOREGISTER);
02888 
02889    if (!cfg) {
02890       ast_log(LOG_WARNING, "No such configuration file %s\n", JABBER_CONFIG);
02891       return 0;
02892    }
02893 
02894    cat = ast_category_browse(cfg, NULL);
02895    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
02896       if (!strcasecmp(var->name, "debug")) {
02897          debug = (ast_false(ast_variable_retrieve(cfg, "general", "debug"))) ? 0 : 1;
02898       } else if (!strcasecmp(var->name, "autoprune")) {
02899          ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOPRUNE);
02900       } else if (!strcasecmp(var->name, "autoregister")) {
02901          ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOREGISTER);
02902       }
02903    }
02904 
02905    while (cat) {
02906       if (strcasecmp(cat, "general")) {
02907             var = ast_variable_browse(cfg, cat);
02908             aji_create_client(cat, var, debug);
02909       }
02910       cat = ast_category_browse(cfg, cat);
02911    }
02912    ast_config_destroy(cfg); /* or leak memory */
02913    return 1;
02914 }

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

the debug loop.

Parameters:
data void
xmpp xml data as string
size size of string
is_incoming direction of packet 1 for inbound 0 for outbound.

Definition at line 783 of file res_jabber.c.

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

Referenced by aji_recv(), and aji_send_raw().

00784 {
00785    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00786 
00787    if (!ast_strlen_zero(xmpp))
00788       manager_event(EVENT_FLAG_USER, "JabberEvent", "Account: %s\r\nPacket: %s\r\n", client->name, xmpp);
00789 
00790    if (client->debug) {
00791       if (is_incoming)
00792          ast_verbose("\nJABBER: %s INCOMING: %s\n", client->name, xmpp);
00793       else {
00794          if( strlen(xmpp) == 1) {
00795             if(option_debug > 2  && xmpp[0] == ' ') {
00796                ast_verbose("\nJABBER: Keep alive packet\n");
00797             }
00798          } else
00799             ast_verbose("\nJABBER: %s OUTGOING: %s\n", client->name, xmpp);
00800       }
00801 
00802    }
00803    ASTOBJ_UNREF(client, aji_client_destroy);
00804 }

static void aji_pruneregister ( struct aji_client client  )  [static]

goes through roster and prunes users not needed in list, or adds them accordingly.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
Returns:
void.
Note:
The messages here should be configurable.

Definition at line 2066 of file res_jabber.c.

References AJI_AUTOPRUNE, ast_aji_send(), ast_log(), ast_test_flag, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_RDLOCK, aji_client::buddies, aji_client::jid, and LOG_ERROR.

02067 {
02068    int res = 0;
02069    iks *removeiq = iks_new("iq");
02070    iks *removequery = iks_new("query");
02071    iks *removeitem = iks_new("item");
02072    iks *send = iks_make_iq(IKS_TYPE_GET, "http://jabber.org/protocol/disco#items");
02073    if (!client || !removeiq || !removequery || !removeitem || !send) {
02074       ast_log(LOG_ERROR, "Out of memory.\n");
02075       goto safeout;
02076    }
02077 
02078    iks_insert_node(removeiq, removequery);
02079    iks_insert_node(removequery, removeitem);
02080    ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02081       ASTOBJ_RDLOCK(iterator);
02082       /* For an aji_buddy, both AUTOPRUNE and AUTOREGISTER will never
02083        * be called at the same time */
02084       if (ast_test_flag(&iterator->flags, AJI_AUTOPRUNE)) { /* If autoprune is set on jabber.conf */
02085          res = ast_aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBE, iterator->name,
02086                          "GoodBye. Your status is no longer needed by Asterisk the Open Source PBX"
02087                          " so I am no longer subscribing to your presence.\n"));
02088          res = ast_aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBED, iterator->name,
02089                          "GoodBye.  You are no longer in the Asterisk config file so I am removing"
02090                          " your access to my presence.\n"));
02091          iks_insert_attrib(removeiq, "from", client->jid->full); 
02092          iks_insert_attrib(removeiq, "type", "set"); 
02093          iks_insert_attrib(removequery, "xmlns", "jabber:iq:roster");
02094          iks_insert_attrib(removeitem, "jid", iterator->name);
02095          iks_insert_attrib(removeitem, "subscription", "remove");
02096          res = ast_aji_send(client, removeiq);
02097       } else if (ast_test_flag(&iterator->flags, AJI_AUTOREGISTER)) {
02098          res = ast_aji_send(client, iks_make_s10n(IKS_TYPE_SUBSCRIBE, iterator->name, 
02099                          "Greetings! I am the Asterisk Open Source PBX and I want to subscribe to your presence\n"));
02100          ast_clear_flag(&iterator->flags, AJI_AUTOREGISTER);
02101       }
02102       ASTOBJ_UNLOCK(iterator);
02103    });
02104 
02105  safeout:
02106    iks_delete(removeiq);
02107    iks_delete(removequery);
02108    iks_delete(removeitem);
02109    iks_delete(send);
02110    
02111    ASTOBJ_CONTAINER_PRUNE_MARKED(&client->buddies, aji_buddy_destroy);
02112 }

static int aji_reconnect ( struct aji_client client  )  [static]

reconnect to jabber server

Parameters:
client the configured XMPP client we use to connect to a XMPP server
Returns:
res.

Definition at line 2203 of file res_jabber.c.

References AJI_DISCONNECTED, aji_initialize(), aji_client::authorized, aji_client::p, aji_client::state, and aji_client::timeout.

Referenced by aji_recv_loop().

02204 {
02205    int res = 0;
02206 
02207    if (client->state)
02208       client->state = AJI_DISCONNECTED;
02209    client->timeout=50;
02210    if (client->p)
02211       iks_parser_reset(client->p);
02212    if (client->authorized)
02213       client->authorized = 0;
02214 
02215    res = aji_initialize(client);
02216 
02217    return res;
02218 }

static int aji_recv ( struct aji_client client,
int  timeout 
) [static]

Tries to receive data from the Jabber server.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
timeout the timeout value This function receives (encrypted or unencrypted) data from the XMPP server, and passes it to the parser.
Returns:
IKS_OK on success, IKS_NET_RWERR on IO error, IKS_NET_NOCONN, if no connection available, IKS_NET_EXPIRED on timeout expiration

Definition at line 641 of file res_jabber.c.

References aji_io_recv(), aji_log_hook(), ast_debug, ast_log(), buf, IKS_NET_EXPIRED, len(), LOG_WARNING, NET_IO_BUF_SIZE, and aji_client::p.

Referenced by aji_act_hook(), and aji_recv_loop().

00642 {
00643    int len, ret;
00644    char buf[NET_IO_BUF_SIZE - 1];
00645    char newbuf[NET_IO_BUF_SIZE - 1];
00646    int pos = 0;
00647    int newbufpos = 0;
00648    unsigned char c;
00649 
00650    memset(buf, 0, sizeof(buf));
00651    memset(newbuf, 0, sizeof(newbuf));
00652 
00653    while (1) {
00654       len = aji_io_recv(client, buf, NET_IO_BUF_SIZE - 2, timeout);
00655       if (len < 0) return IKS_NET_RWERR;
00656       if (len == 0) return IKS_NET_EXPIRED;
00657       buf[len] = '\0';
00658 
00659       /* our iksemel parser won't work as expected if we feed
00660          it with XML packets that contain multiple whitespace 
00661          characters between tags */
00662       while (pos < len) {
00663          c = buf[pos];
00664          /* if we stumble on the ending tag character,
00665             we skip any whitespace that follows it*/
00666          if (c == '>') {
00667             while (isspace(buf[pos+1])) {
00668                pos++;
00669             }
00670          }
00671          newbuf[newbufpos] = c;
00672          newbufpos ++;
00673          pos++;
00674       }
00675       pos = 0;
00676       newbufpos = 0;
00677 
00678       /* Log the message here, because iksemel's logHook is 
00679          unaccessible */
00680       aji_log_hook(client, buf, len, 1);
00681 
00682       /* let iksemel deal with the string length, 
00683          and reset our buffer */
00684       ret = iks_parse(client->p, newbuf, 0, 0);
00685       memset(newbuf, 0, sizeof(newbuf));
00686 
00687       switch (ret) {
00688       case IKS_NOMEM:
00689          ast_log(LOG_WARNING, "Parsing failure: Out of memory.\n");
00690          break;
00691       case IKS_BADXML:
00692          ast_log(LOG_WARNING, "Parsing failure: Invalid XML.\n");
00693          break;
00694       case IKS_HOOK:
00695          ast_log(LOG_WARNING, "Parsing failure: Hook returned an error.\n");
00696          break;
00697       }
00698       if (ret != IKS_OK) {
00699          return ret;
00700       }
00701       ast_debug(3, "XML parsing successful\n"); 
00702    }
00703    return IKS_OK;
00704 }

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

receive message loop.

Parameters:
data void
Returns:
void.

Definition at line 1905 of file res_jabber.c.

References aji_client_destroy(), AJI_CONNECTED, AJI_DISCONNECTING, aji_reconnect(), aji_recv(), aji_send_raw(), ast_debug, ast_log(), ASTOBJ_REF, ASTOBJ_UNREF, IKS_NET_EXPIRED, aji_client::keepalive, LOG_ERROR, LOG_WARNING, aji_client::state, and aji_client::timeout.

Referenced by aji_reload().

01906 {
01907    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01908    int res = IKS_HOOK;
01909 
01910    while(res != IKS_OK) {
01911       ast_debug(3, "JABBER: Connecting.\n");
01912       res = aji_reconnect(client);
01913       sleep(4);
01914    }
01915 
01916    do {
01917       if (res == IKS_NET_RWERR || client->timeout == 0) {
01918          while(res != IKS_OK) {
01919             ast_debug(3, "JABBER: reconnecting.\n");
01920             res = aji_reconnect(client);
01921             sleep(4);
01922          }
01923       }
01924 
01925       res = aji_recv(client, 1);
01926       
01927       if (client->state == AJI_DISCONNECTING) {
01928          ast_debug(2, "Ending our Jabber client's thread due to a disconnect\n");
01929          pthread_exit(NULL);
01930       }
01931 
01932       /* Decrease timeout if no data received */
01933       if (res == IKS_NET_EXPIRED)
01934          client->timeout--;
01935 
01936       if (res == IKS_HOOK) 
01937          ast_log(LOG_WARNING, "JABBER: Got hook event.\n");
01938       else if (res == IKS_NET_TLSFAIL)
01939          ast_log(LOG_ERROR, "JABBER:  Failure in TLS.\n");
01940       else if (client->timeout == 0 && client->state == AJI_CONNECTED) {
01941          res = client->keepalive ? aji_send_raw(client, " ") : IKS_OK;
01942          if(res == IKS_OK)
01943             client->timeout = 50;
01944          else
01945             ast_log(LOG_WARNING, "JABBER:  Network Timeout\n");
01946       } else if (res == IKS_NET_RWERR)
01947          ast_log(LOG_WARNING, "JABBER: socket read error\n");
01948    } while (client);
01949    ASTOBJ_UNREF(client, aji_client_destroy);
01950    return 0;
01951 }

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

Unknown.

Parameters:
data void
pak ikspak
Returns:
IKS_FILTER_EAT.

Definition at line 1064 of file res_jabber.c.

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

01065 {
01066    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01067    iks *iq = NULL, *presence = NULL, *x = NULL;
01068 
01069    iq = iks_new("iq");
01070    presence = iks_new("presence");
01071    x = iks_new("x");
01072    if (client && iq && presence && x) {
01073       if (!iks_find(pak->query, "remove")) {
01074          iks_insert_attrib(iq, "from", client->jid->full);
01075          iks_insert_attrib(iq, "to", pak->from->full);
01076          iks_insert_attrib(iq, "id", pak->id);
01077          iks_insert_attrib(iq, "type", "result");
01078          ast_aji_send(client, iq);
01079 
01080          iks_insert_attrib(presence, "from", client->jid->full);
01081          iks_insert_attrib(presence, "to", pak->from->partial);
01082          iks_insert_attrib(presence, "id", client->mid);
01083          ast_aji_increment_mid(client->mid);
01084          iks_insert_attrib(presence, "type", "subscribe");
01085          iks_insert_attrib(x, "xmlns", "vcard-temp:x:update");
01086          iks_insert_node(presence, x);
01087          ast_aji_send(client, presence); 
01088       }
01089    } else {
01090       ast_log(LOG_ERROR, "Out of memory.\n");
01091    }
01092 
01093 
01094    iks_delete(iq);
01095    iks_delete(presence);
01096    iks_delete(x);
01097    
01098    ASTOBJ_UNREF(client, aji_client_destroy);
01099    return IKS_FILTER_EAT;
01100 }

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

register handler for incoming querys (IQ's)

Parameters:
data incoming aji_client request
pak ikspak
Returns:
IKS_FILTER_EAT.

Definition at line 1107 of file res_jabber.c.

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

01108 {
01109    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01110    struct aji_buddy *buddy = NULL; 
01111    char *node = NULL;
01112    iks *iq = NULL, *query = NULL;
01113 
01114    client = (struct aji_client *) data;
01115 
01116    buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01117    if (!buddy) {
01118       iks  *error = NULL, *notacceptable = NULL;
01119 
01120       ast_log(LOG_ERROR, "Someone.... %s tried to register but they aren't allowed\n", pak->from->partial);
01121       iq = iks_new("iq");
01122       query = iks_new("query");
01123       error = iks_new("error");
01124       notacceptable = iks_new("not-acceptable");
01125       if(iq && query && error && notacceptable) {
01126          iks_insert_attrib(iq, "type", "error");
01127          iks_insert_attrib(iq, "from", client->user);
01128          iks_insert_attrib(iq, "to", pak->from->full);
01129          iks_insert_attrib(iq, "id", pak->id);
01130          iks_insert_attrib(query, "xmlns", "jabber:iq:register");
01131          iks_insert_attrib(error, "code" , "406");
01132          iks_insert_attrib(error, "type", "modify");
01133          iks_insert_attrib(notacceptable, "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas");
01134          iks_insert_node(iq, query);
01135          iks_insert_node(iq, error);
01136          iks_insert_node(error, notacceptable);
01137          ast_aji_send(client, iq);
01138       } else {
01139          ast_log(LOG_ERROR, "Out of memory.\n");
01140       }
01141 
01142       iks_delete(error);
01143       iks_delete(notacceptable);
01144    } else   if (!(node = iks_find_attrib(pak->query, "node"))) {
01145       iks *instructions = NULL;
01146       char *explain = "Welcome to Asterisk - the Open Source PBX.\n";
01147       iq = iks_new("iq");
01148       query = iks_new("query");
01149       instructions = iks_new("instructions");
01150       if (iq && query && instructions && client) {
01151          iks_insert_attrib(iq, "from", client->user);
01152          iks_insert_attrib(iq, "to", pak->from->full);
01153          iks_insert_attrib(iq, "id", pak->id);
01154          iks_insert_attrib(iq, "type", "result");
01155          iks_insert_attrib(query, "xmlns", "jabber:iq:register");
01156          iks_insert_cdata(instructions, explain, 0);
01157          iks_insert_node(iq, query);
01158          iks_insert_node(query, instructions);
01159          ast_aji_send(client, iq);
01160       } else {
01161          ast_log(LOG_ERROR, "Out of memory.\n");
01162       }
01163 
01164       iks_delete(instructions);
01165    }
01166    iks_delete(iq);
01167    iks_delete(query);
01168    ASTOBJ_UNREF(client, aji_client_destroy);
01169    return IKS_FILTER_EAT;
01170 }

static int aji_reload ( int  reload  )  [static]

Reload the jabber module.

Definition at line 3003 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().

03004 {
03005    int res;
03006 
03007    ASTOBJ_CONTAINER_MARKALL(&clients);
03008    if (!(res = aji_load_config(reload))) {
03009       ast_log(LOG_ERROR, "JABBER: Failed to load config.\n");
03010       return 0;
03011    } else if (res == -1)
03012       return 1;
03013 
03014    ASTOBJ_CONTAINER_PRUNE_MARKED(&clients, aji_client_destroy);
03015    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
03016       ASTOBJ_RDLOCK(iterator);
03017       if(iterator->state == AJI_DISCONNECTED) {
03018          if (!iterator->thread)
03019             ast_pthread_create_background(&iterator->thread, NULL, aji_recv_loop, iterator);
03020       } else if (iterator->state == AJI_CONNECTING)
03021          aji_get_roster(iterator);
03022       ASTOBJ_UNLOCK(iterator);
03023    });
03024    
03025    return 1;
03026 }

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

Dial plan function to send a message.

Parameters:
chan ast_channel
data Data is sender|receiver|message.
Returns:
0 on success,-1 on error.

Definition at line 468 of file res_jabber.c.

References ast_aji_get_client(), ast_aji_send_chat(), AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), LOG_ERROR, LOG_WARNING, and s.

Referenced by load_module().

00469 {
00470    struct aji_client *client = NULL;
00471    char *s;
00472    AST_DECLARE_APP_ARGS(args,
00473       AST_APP_ARG(sender);
00474       AST_APP_ARG(recipient);
00475       AST_APP_ARG(message);
00476    );
00477 
00478    if (!data) {
00479       ast_log(LOG_ERROR, "Usage:  JabberSend(<sender>,<recipient>,<message>)\n");
00480       return 0;
00481    }
00482    s = ast_strdupa(data);
00483 
00484    AST_STANDARD_APP_ARGS(args, s);
00485    if (args.argc < 3) {
00486       ast_log(LOG_ERROR, "JabberSend requires 3 arguments: '%s'\n", (char *) data);
00487       return -1;
00488    }
00489 
00490    if (!(client = ast_aji_get_client(args.sender))) {
00491       ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
00492       return -1;
00493    }
00494    if (strchr(args.recipient, '@') && !ast_strlen_zero(args.message))
00495       ast_aji_send_chat(client, args.recipient, args.message);
00496    return 0;
00497 }

static int aji_send_header ( struct aji_client client,
const char *  to 
) [static]

Sends XMPP header to the server.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
to the target XMPP server
Returns:
IKS_OK on success, any other value on failure

Definition at line 712 of file res_jabber.c.

References aji_send_raw(), len(), msg, and aji_client::name_space.

Referenced by aji_act_hook().

00713 {
00714    char *msg;
00715    int len, err;
00716 
00717    len = 91 + strlen(client->name_space) + 6 + strlen(to) + 16 + 1;
00718    msg = iks_malloc(len);
00719    if (!msg)
00720       return IKS_NOMEM;
00721    sprintf(msg, "<?xml version='1.0'?>"
00722       "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='"
00723       "%s' to='%s' version='1.0'>", client->name_space, to);
00724    err = aji_send_raw(client, msg);
00725    iks_free(msg);
00726    if (err != IKS_OK)
00727       return err;
00728 
00729    return IKS_OK;
00730 }

static int aji_send_raw ( struct aji_client client,
const char *  xmlstr 
) [static]

Sends an XML string over an XMPP connection.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
xmlstr the XML string to send The XML data is sent whether the connection is secured or not. In the latter case, we just call iks_send_raw().
Returns:
IKS_OK on success, any other value on failure

Definition at line 751 of file res_jabber.c.

References aji_is_secure(), aji_log_hook(), len(), and aji_client::p.

Referenced by aji_act_hook(), aji_recv_loop(), aji_send_header(), and ast_aji_send().

00752 {
00753    int ret;
00754 #ifdef HAVE_OPENSSL
00755    int len = strlen(xmlstr);
00756 
00757    if (aji_is_secure(client)) {
00758       ret = SSL_write(client->ssl_session, xmlstr, len);
00759       if (ret) {
00760          /* Log the message here, because iksemel's logHook is 
00761             unaccessible */
00762          aji_log_hook(client, xmlstr, len, 0);
00763          return IKS_OK;
00764       }
00765    }
00766 #endif
00767    /* If needed, data will be sent unencrypted, and logHook will 
00768       be called inside iks_send_raw */
00769    ret = iks_send_raw(client->p, xmlstr);
00770    if (ret != IKS_OK)
00771       return ret; 
00772 
00773    return IKS_OK;
00774 }

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

set presence of client.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
to user send it to
from user it came from
level 
desc 
Returns:
void.

Definition at line 2328 of file res_jabber.c.

References ast_aji_send(), ast_log(), LOG_ERROR, and aji_client::priority.

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

02329 {
02330    int res = 0;
02331    iks *presence = iks_make_pres(level, desc);
02332    iks *cnode = iks_new("c");
02333    iks *priority = iks_new("priority");
02334    char priorityS[10];
02335 
02336    if (presence && cnode && client && priority) {
02337       if(to)
02338          iks_insert_attrib(presence, "to", to);
02339       if(from)
02340          iks_insert_attrib(presence, "from", from);
02341       snprintf(priorityS, sizeof(priorityS), "%d", client->priority);
02342       iks_insert_cdata(priority, priorityS, strlen(priorityS));
02343       iks_insert_node(presence, priority);
02344       iks_insert_attrib(cnode, "node", "http://www.asterisk.org/xmpp/client/caps");
02345       iks_insert_attrib(cnode, "ver", "asterisk-xmpp");
02346       iks_insert_attrib(cnode, "ext", "voice-v1");
02347       iks_insert_attrib(cnode, "xmlns", "http://jabber.org/protocol/caps");
02348       iks_insert_node(presence, cnode);
02349       res = ast_aji_send(client, presence);
02350    } else
02351       ast_log(LOG_ERROR, "Out of memory.\n");
02352 
02353    iks_delete(cnode);
02354    iks_delete(presence);
02355    iks_delete(priority);
02356 }

static char * aji_show_buddies ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Show buddy lists.

Returns:
CLI_SUCCESS.

Definition at line 2509 of file res_jabber.c.

References ast_cli(), ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_RDLOCK, ASTOBJ_UNLOCK, aji_client::buddies, aji_resource::cap, CLI_GENERATE, CLI_INIT, clients, ast_cli_entry::command, ast_cli_args::fd, aji_version::jingle, aji_resource::next, aji_capabilities::node, aji_version::parent, aji_resource::priority, aji_resource::resource, aji_resource::status, ast_cli_entry::usage, and aji_version::version.

02510 {
02511    struct aji_resource *resource;
02512    struct aji_client *client;
02513 
02514    switch (cmd) {
02515    case CLI_INIT:
02516       e->command = "jabber show buddies";
02517       e->usage =
02518          "Usage: jabber show buddies\n"
02519          "       Shows buddy lists of our clients\n";
02520       return NULL;
02521    case CLI_GENERATE:
02522       return NULL;
02523    }
02524 
02525    ast_cli(a->fd, "Jabber buddy lists\n");
02526    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02527       ast_cli(a->fd,"Client: %s\n", iterator->user);
02528       client = iterator;
02529       ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02530          ASTOBJ_RDLOCK(iterator);
02531          ast_cli(a->fd,"\tBuddy:\t%s\n", iterator->name);
02532          if (!iterator->resources)
02533             ast_cli(a->fd,"\t\tResource: None\n"); 
02534          for (resource = iterator->resources; resource; resource = resource->next) {
02535             ast_cli(a->fd,"\t\tResource: %s\n", resource->resource);
02536             if(resource->cap) {
02537                ast_cli(a->fd,"\t\t\tnode: %s\n", resource->cap->parent->node);
02538                ast_cli(a->fd,"\t\t\tversion: %s\n", resource->cap->version);
02539                ast_cli(a->fd,"\t\t\tJingle capable: %s\n", resource->cap->jingle ? "yes" : "no");
02540             }
02541             ast_cli(a->fd,"\t\tStatus: %d\n", resource->status);
02542             ast_cli(a->fd,"\t\tPriority: %d\n", resource->priority);
02543          }
02544          ASTOBJ_UNLOCK(iterator);
02545       });
02546       iterator = client;
02547    });
02548    return CLI_SUCCESS;
02549 }

static char * aji_show_clients ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Show client status.

Returns:
CLI_SUCCESS.

Definition at line 2464 of file res_jabber.c.

References AJI_CONNECTED, AJI_CONNECTING, AJI_DISCONNECTED, ast_cli(), ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_RDLOCK, ASTOBJ_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, clients, ast_cli_entry::command, ast_cli_args::fd, status, and ast_cli_entry::usage.

02465 {
02466    char *status;
02467    int count = 0;
02468    
02469    switch (cmd) {
02470    case CLI_INIT:
02471       e->command = "jabber show connected";
02472       e->usage =
02473          "Usage: jabber show connected\n"
02474          "       Shows state of clients and components\n";
02475       return NULL;
02476    case CLI_GENERATE:
02477       return NULL;
02478    }
02479 
02480    ast_cli(a->fd, "Jabber Users and their status:\n");
02481    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02482       ASTOBJ_RDLOCK(iterator);
02483       count++;
02484       switch (iterator->state) {
02485       case AJI_DISCONNECTED:
02486          status = "Disconnected";
02487          break;
02488       case AJI_CONNECTING:
02489          status = "Connecting";
02490          break;
02491       case AJI_CONNECTED:
02492          status = "Connected";
02493          break;
02494       default:
02495          status = "Unknown";
02496       }
02497       ast_cli(a->fd, "       User: %s     - %s\n", iterator->user, status);
02498       ASTOBJ_UNLOCK(iterator);
02499    });
02500    ast_cli(a->fd, "----\n");
02501    ast_cli(a->fd, "   Number of users: %d\n", count);
02502    return CLI_SUCCESS;
02503 }

static int aji_start_sasl ( struct aji_client client,
enum ikssasltype  type,
char *  username,
char *  pass 
) [static]

A wrapper function for iks_start_sasl.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
type the SASL authentication type. Supported types are PLAIN and MD5
username 
pass password.
Returns:
IKS_OK on success, IKSNET_NOTSUPP on failure.

Definition at line 815 of file res_jabber.c.

References aji_is_secure(), ast_aji_send(), ast_base64encode(), ast_log(), base64, len(), LOG_ERROR, aji_client::p, and s.

Referenced by aji_act_hook().

00816 {
00817    iks *x = NULL;
00818    int len;
00819    char *s;
00820    char *base64;
00821 
00822    /* trigger SASL DIGEST-MD5 only over an unsecured connection.
00823       iks_start_sasl is an iksemel API function and relies on GnuTLS,
00824       whereas we use OpenSSL */
00825    if ((type & IKS_STREAM_SASL_MD5) && !aji_is_secure(client))
00826       return iks_start_sasl(client->p, IKS_SASL_DIGEST_MD5, username, pass); 
00827    if (!(type & IKS_STREAM_SASL_PLAIN)) {
00828       ast_log(LOG_ERROR, "Server does not support SASL PLAIN authentication\n");
00829       return IKS_NET_NOTSUPP;
00830    }
00831 
00832    x = iks_new("auth"); 
00833    if (!x) {
00834       ast_log(LOG_ERROR, "Out of memory.\n");
00835       return IKS_NET_NOTSUPP;
00836    }
00837 
00838    iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_SASL);
00839    len = strlen(username) + strlen(pass) + 3;
00840    s = alloca(len);
00841    base64 = alloca((len + 2) * 4 / 3);
00842    iks_insert_attrib(x, "mechanism", "PLAIN");
00843    snprintf(s, len, "%c%s%c%s", 0, username, 0, pass);
00844 
00845    /* exclude the NULL training byte from the base64 encoding operation
00846       as some XMPP servers will refuse it.
00847       The format for authentication is [authzid]\0authcid\0password
00848       not [authzid]\0authcid\0password\0 */
00849    ast_base64encode(base64, (const unsigned char *) s, len - 1, (len + 2) * 4 / 3);
00850    iks_insert_cdata(x, base64, 0);
00851    ast_aji_send(client, x);
00852    iks_delete(x);
00853 
00854    return IKS_OK;
00855 }

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:
chan ast_channel
data 
Returns:
0 on success, -1 on error

Definition at line 344 of file res_jabber.c.

References aji_find_resource(), ast_aji_get_client(), AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_NONSTANDARD_APP_ARGS, AST_STANDARD_APP_ARGS, 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, aji_resource::status, and status.

Referenced by load_module().

00345 {
00346    struct aji_client *client = NULL;
00347    struct aji_buddy *buddy = NULL;
00348    struct aji_resource *r = NULL;
00349    char *s = NULL;
00350    int stat = 7;
00351    char status[2];
00352    static int deprecation_warning = 0;
00353    AST_DECLARE_APP_ARGS(args,
00354       AST_APP_ARG(sender);
00355       AST_APP_ARG(jid);
00356       AST_APP_ARG(variable);
00357    );
00358    AST_DECLARE_APP_ARGS(jid,
00359       AST_APP_ARG(screenname);
00360       AST_APP_ARG(resource);
00361    );
00362 
00363    if (deprecation_warning++ % 10 == 0)
00364       ast_log(LOG_WARNING, "JabberStatus is deprecated.  Please use the JABBER_STATUS dialplan function in the future.\n");
00365 
00366    if (!data) {
00367       ast_log(LOG_ERROR, "Usage: JabberStatus(<sender>,<screenname>[/<resource>],<varname>\n");
00368       return 0;
00369    }
00370    s = ast_strdupa(data);
00371    AST_STANDARD_APP_ARGS(args, s);
00372 
00373    if (args.argc != 3) {
00374       ast_log(LOG_ERROR, "JabberStatus() requires 3 arguments.\n");
00375       return -1;
00376    }
00377 
00378    AST_NONSTANDARD_APP_ARGS(jid, args.jid, '/');
00379 
00380    if (!(client = ast_aji_get_client(args.sender))) {
00381       ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
00382       return -1;
00383    }
00384    buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, jid.screenname);
00385    if (!buddy) {
00386       ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
00387       return -1;
00388    }
00389    r = aji_find_resource(buddy, jid.resource);
00390    if (!r && buddy->resources) 
00391       r = buddy->resources;
00392    if (!r)
00393       ast_log(LOG_NOTICE, "Resource '%s' of buddy '%s' was not found\n", jid.resource, jid.screenname);
00394    else
00395       stat = r->status;
00396    snprintf(status, sizeof(status), "%d", stat);
00397    pbx_builtin_setvar_helper(chan, args.variable, status);
00398    return 0;
00399 }

static char * aji_test ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Send test message for debugging.

Returns:
CLI_SUCCESS,CLI_FAILURE.

Definition at line 2555 of file res_jabber.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_aji_send_chat(), ast_cli(), ast_verbose(), ASTOBJ_CONTAINER_FIND, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_RDLOCK, ASTOBJ_UNLOCK, aji_client::buddies, aji_resource::cap, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, clients, ast_cli_entry::command, aji_resource::description, ast_cli_args::fd, aji_version::jingle, name, aji_resource::next, aji_capabilities::node, aji_version::parent, aji_resource::priority, aji_resource::resource, S_OR, aji_resource::status, ast_cli_entry::usage, and aji_version::version.

02556 {
02557    struct aji_client *client;
02558    struct aji_resource *resource;
02559    const char *name = "asterisk";
02560    struct aji_message *tmp;
02561 
02562    switch (cmd) {
02563    case CLI_INIT:
02564       e->command = "jabber test";
02565       e->usage =
02566          "Usage: jabber test [client]\n"
02567          "       Sends test message for debugging purposes.  A specific client\n"
02568          "       as configured in jabber.conf can be optionally specified.\n";
02569       return NULL;
02570    case CLI_GENERATE:
02571       return NULL;
02572    }
02573 
02574    if (a->argc > 3)
02575       return CLI_SHOWUSAGE;
02576    else if (a->argc == 3)
02577       name = a->argv[2];
02578 
02579    if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
02580       ast_cli(a->fd, "Unable to find client '%s'!\n", name);
02581       return CLI_FAILURE;
02582    }
02583 
02584    /* XXX Does Matt really want everyone to use his personal address for tests? */ /* XXX yes he does */
02585    ast_aji_send_chat(client, "mogorman@astjab.org", "blahblah");
02586    ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02587       ASTOBJ_RDLOCK(iterator);
02588       ast_verbose("User: %s\n", iterator->name);
02589       for (resource = iterator->resources; resource; resource = resource->next) {
02590          ast_verbose("Resource: %s\n", resource->resource);
02591          if(resource->cap) {
02592             ast_verbose("   client: %s\n", resource->cap->parent->node);
02593             ast_verbose("   version: %s\n", resource->cap->version);
02594             ast_verbose("   Jingle Capable: %d\n", resource->cap->jingle);
02595          }
02596          ast_verbose("  Priority: %d\n", resource->priority);
02597          ast_verbose("  Status: %d\n", resource->status); 
02598          ast_verbose("  Message: %s\n", S_OR(resource->description,"")); 
02599       }
02600       ASTOBJ_UNLOCK(iterator);
02601    });
02602    ast_verbose("\nOooh a working message stack!\n");
02603    AST_LIST_LOCK(&client->messages);
02604    AST_LIST_TRAVERSE(&client->messages, tmp, list) {
02605       ast_verbose("  Message from: %s with id %s @ %s %s\n",tmp->from, S_OR(tmp->id,""), ctime(&tmp->arrived), S_OR(tmp->message, ""));
02606    }
02607    AST_LIST_UNLOCK(&client->messages);
02608    ASTOBJ_UNREF(client, aji_client_destroy);
02609 
02610    return CLI_SUCCESS;
02611 }

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

create a chatroom.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
room name of room
server name of server
topic topic for the room.
Returns:
0.

Definition at line 1814 of file res_jabber.c.

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

01815 {
01816    int res = 0;
01817    iks *iq = NULL;
01818    iq = iks_new("iq");
01819 
01820    if (iq && client) {
01821       iks_insert_attrib(iq, "type", "get");
01822       iks_insert_attrib(iq, "to", server);
01823       iks_insert_attrib(iq, "id", client->mid);
01824       ast_aji_increment_mid(client->mid);
01825       ast_aji_send(client, iq);
01826    } else 
01827       ast_log(LOG_ERROR, "Out of memory.\n");
01828 
01829    iks_delete(iq);
01830 
01831    return res;
01832 }

int ast_aji_disconnect ( struct aji_client client  ) 

disconnect from jabber server.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
Returns:
1.

Definition at line 2300 of file res_jabber.c.

References aji_client_destroy(), ast_verb, ASTOBJ_UNREF, and aji_client::p.

Referenced by unload_module().

02301 {
02302    if (client) {
02303       ast_verb(4, "JABBER: Disconnecting\n");
02304 #ifdef HAVE_OPENSSL
02305       if (client->stream_flags & SECURE) {
02306          SSL_shutdown(client->ssl_session);
02307          SSL_CTX_free(client->ssl_context);
02308          SSL_free(client->ssl_session);
02309       }
02310 #endif
02311       iks_disconnect(client->p);
02312       iks_parser_delete(client->p);
02313       ASTOBJ_UNREF(client, aji_client_destroy);
02314    }
02315 
02316    return 1;
02317 }

struct aji_client* ast_aji_get_client ( const char *  name  )  [read]

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 2922 of file res_jabber.c.

References ast_strdupa, ASTOBJ_CONTAINER_FIND, ASTOBJ_CONTAINER_TRAVERSE, clients, and strsep().

Referenced by acf_jabberstatus_read(), aji_send_exec(), aji_status_exec(), gtalk_create_member(), gtalk_newcall(), gtalk_request(), jingle_create_member(), jingle_newcall(), jingle_request(), and manager_jabber_send().

02923 {
02924    struct aji_client *client = NULL;
02925    char *aux = NULL;
02926 
02927    client = ASTOBJ_CONTAINER_FIND(&clients, name);
02928    if (!client && strchr(name, '@')) {
02929       ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02930          aux = ast_strdupa(iterator->user);
02931          if (strchr(aux, '/')) {
02932             /* strip resource for comparison */
02933             aux = strsep(&aux, "/");
02934          }
02935          if (!strncasecmp(aux, name, strlen(aux))) {
02936             client = iterator;
02937          }           
02938       });
02939    }
02940 
02941    return client;
02942 }

struct aji_client_container* ast_aji_get_clients ( void   )  [read]

Definition at line 2944 of file res_jabber.c.

References clients.

Referenced by gtalk_load_config(), and jingle_load_config().

02945 {
02946    return &clients;
02947 }

void ast_aji_increment_mid ( char *  mid  ) 

increments the mid field for messages and other events.

Parameters:
mid char.
Returns:
void.

Definition at line 1958 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(), gtalk_invite_response(), jingle_accept_call(), jingle_action(), jingle_create_candidates(), jingle_digit(), and jingle_transmit_invite().

01959 {
01960    int i = 0;
01961 
01962    for (i = strlen(mid) - 1; i >= 0; i--) {
01963       if (mid[i] != 'z') {
01964          mid[i] = mid[i] + 1;
01965          i = 0;
01966       } else
01967          mid[i] = 'a';
01968    }
01969 }

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

invite to a chatroom.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
user 
room 
message 
Returns:
res.

Definition at line 1871 of file res_jabber.c.

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

01872 {
01873    int res = 0;
01874    iks *invite, *body, *namespace;
01875 
01876    invite = iks_new("message");
01877    body = iks_new("body");
01878    namespace = iks_new("x");
01879    if (client && invite && body && namespace) {
01880       iks_insert_attrib(invite, "to", user);
01881       iks_insert_attrib(invite, "id", client->mid);
01882       ast_aji_increment_mid(client->mid);
01883       iks_insert_cdata(body, message, 0);
01884       iks_insert_attrib(namespace, "xmlns", "jabber:x:conference");
01885       iks_insert_attrib(namespace, "jid", room);
01886       iks_insert_node(invite, body);
01887       iks_insert_node(invite, namespace);
01888       res = ast_aji_send(client, invite);
01889    } else 
01890       ast_log(LOG_ERROR, "Out of memory.\n");
01891 
01892    iks_delete(body);
01893    iks_delete(namespace);
01894    iks_delete(invite);
01895    
01896    return res;
01897 }

int ast_aji_join_chat ( struct aji_client client,
char *  room 
)

join a chatroom.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
room room to join
Returns:
res.

Definition at line 1840 of file res_jabber.c.

References ast_aji_send(), ast_log(), and LOG_ERROR.

01841 {
01842    int res = 0;
01843    iks *presence = NULL, *priority = NULL;
01844    presence = iks_new("presence");
01845    priority = iks_new("priority");
01846    if (presence && priority && client) {
01847       iks_insert_cdata(priority, "0", 1);
01848       iks_insert_attrib(presence, "to", room);
01849       iks_insert_node(presence, priority);
01850       res = ast_aji_send(client, presence);
01851       iks_insert_cdata(priority, "5", 1);
01852       iks_insert_attrib(presence, "to", room);
01853       res = ast_aji_send(client, presence);
01854    } else 
01855       ast_log(LOG_ERROR, "Out of memory.\n");
01856    
01857    iks_delete(presence);
01858    iks_delete(priority);
01859    
01860    return res;
01861 }

int ast_aji_send ( struct aji_client client,
iks *  x 
)

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

sends messages.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
address 
message 
Returns:
1.

Definition at line 1787 of file res_jabber.c.

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

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

01788 {
01789    int res = 0;
01790    iks *message_packet = NULL;
01791    if (client->state == AJI_CONNECTED) {
01792       message_packet = iks_make_msg(IKS_TYPE_CHAT, address, message);
01793       if (message_packet) {
01794          iks_insert_attrib(message_packet, "from", client->jid->full);
01795          res = ast_aji_send(client, message_packet);
01796       } else {
01797          ast_log(LOG_ERROR, "Out of memory.\n");
01798       }
01799 
01800       iks_delete(message_packet);
01801    } else
01802       ast_log(LOG_WARNING, "JABBER: Not connected can't send\n");
01803    return 1;
01804 }

static int gtalk_yuck ( iks *  node  )  [static]

Jabber GTalk function.

Parameters:
node iks
Returns:
1 on success, 0 on failure.

Definition at line 302 of file res_jabber.c.

Referenced by aji_handle_presence().

00303 {
00304    if (iks_find_with_attrib(node, "c", "node", "http://www.google.com/xmpp/client/caps"))
00305       return 1;
00306    return 0;
00307 }

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

Setup the authentication struct.

Parameters:
id iksid
pass password
sid 
Returns:
x iks

Definition at line 316 of file res_jabber.c.

References ast_sha1_hash(), and buf.

Referenced by aji_act_hook().

00317 {
00318    iks *x, *y;
00319    x = iks_new("iq");
00320    iks_insert_attrib(x, "type", "set");
00321    y = iks_insert(x, "query");
00322    iks_insert_attrib(y, "xmlns", IKS_NS_AUTH);
00323    iks_insert_cdata(iks_insert(y, "username"), id->user, 0);
00324    iks_insert_cdata(iks_insert(y, "resource"), id->resource, 0);
00325    if (sid) {
00326       char buf[41];
00327       char sidpass[100];
00328       snprintf(sidpass, sizeof(sidpass), "%s%s", sid, pass);
00329       ast_sha1_hash(buf, sidpass);
00330       iks_insert_cdata(iks_insert(y, "digest"), buf, 0);
00331    } else {
00332       iks_insert_cdata(iks_insert(y, "password"), pass, 0);
00333    }
00334    return x;
00335 }

static int load_module ( void   )  [static]

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

Send a Jabber Message via call from the Manager.

Parameters:
s mansession Manager session
m message Message to send
Returns:
0

Definition at line 2962 of file res_jabber.c.

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

Referenced by load_module().

02963 {
02964    struct aji_client *client = NULL;
02965    const char *id = astman_get_header(m,"ActionID");
02966    const char *jabber = astman_get_header(m,"Jabber");
02967    const char *screenname = astman_get_header(m,"ScreenName");
02968    const char *message = astman_get_header(m,"Message");
02969 
02970    if (ast_strlen_zero(jabber)) {
02971       astman_send_error(s, m, "No transport specified");
02972       return 0;
02973    }
02974    if (ast_strlen_zero(screenname)) {
02975       astman_send_error(s, m, "No ScreenName specified");
02976       return 0;
02977    }
02978    if (ast_strlen_zero(message)) {
02979       astman_send_error(s, m, "No Message specified");
02980       return 0;
02981    }
02982 
02983    astman_send_ack(s, m, "Attempting to send Jabber Message");
02984    client = ast_aji_get_client(jabber);
02985    if (!client) {
02986       astman_send_error(s, m, "Could not find Sender");
02987       return 0;
02988    }
02989    if (strchr(screenname, '@') && message) {
02990       ast_aji_send_chat(client, screenname, message);
02991       astman_append(s, "Response: Success\r\n");
02992    } else {
02993       astman_append(s, "Response: Error\r\n");
02994    }
02995    if (!ast_strlen_zero(id)) {
02996       astman_append(s, "ActionID: %s\r\n",id);
02997    }
02998    astman_append(s, "\r\n");
02999    return 0;
03000 }

static int reload ( void   )  [static]

Wrapper for aji_reload.

Definition at line 3069 of file res_jabber.c.

References aji_reload().

03070 {
03071    aji_reload(1);
03072    return 0;
03073 }

static int unload_module ( void   )  [static]

Unload the jabber module.

Definition at line 3029 of file res_jabber.c.

References aji_client_destroy(), AJI_DISCONNECTING, ast_aji_disconnect(), ast_cli_unregister_multiple(), ast_custom_function_unregister(), ast_debug, ast_manager_unregister(), ast_unregister_application(), ASTOBJ_CONTAINER_DESTROY, ASTOBJ_CONTAINER_DESTROYALL, ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_RDLOCK, ASTOBJ_UNLOCK, and clients.

03030 {
03031 
03032    ast_cli_unregister_multiple(aji_cli, sizeof(aji_cli) / sizeof(struct ast_cli_entry));
03033    ast_unregister_application(app_ajisend);
03034    ast_unregister_application(app_ajistatus);
03035    ast_manager_unregister("JabberSend");
03036    ast_custom_function_unregister(&jabberstatus_function);
03037    
03038    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
03039       ASTOBJ_RDLOCK(iterator);
03040       ast_debug(3, "JABBER: Releasing and disconnecting client: %s\n", iterator->name);
03041       iterator->state = AJI_DISCONNECTING;
03042       ast_aji_disconnect(iterator);
03043       pthread_join(iterator->thread, NULL);
03044       ASTOBJ_UNLOCK(iterator);
03045    });
03046 
03047    ASTOBJ_CONTAINER_DESTROYALL(&clients, aji_client_destroy);
03048    ASTOBJ_CONTAINER_DESTROY(&clients);
03049    return 0;
03050 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS , .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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 3079 of file res_jabber.c.

struct ast_cli_entry aji_cli[] [static]

Definition at line 127 of file res_jabber.c.

char* ajisend_descrip [static]

Initial value:

"JabberSend(Jabber,ScreenName,Message)\n"
"  Jabber - Client or transport Asterisk uses to connect to Jabber\n" 
"  ScreenName - XMPP/Jabber JID (Name) of recipient\n" 
"  Message - Message to be sent to the budd (UTF8)y\n"

Definition at line 139 of file res_jabber.c.

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

Definition at line 137 of file res_jabber.c.

char* ajistatus_descrip [static]

Definition at line 149 of file res_jabber.c.

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

Definition at line 147 of file res_jabber.c.

char* app_ajisend = "JabberSend" [static]

Definition at line 135 of file res_jabber.c.

char* app_ajistatus = "JabberStatus" [static]

Definition at line 145 of file res_jabber.c.

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 3079 of file res_jabber.c.

Definition at line 159 of file res_jabber.c.

Referenced by ast_request().

struct ast_cli_entry cli_aji_do_debug_deprecated = AST_CLI_DEFINE(aji_do_debug_deprecated, "Enable/disable jabber debugging") [static]

Definition at line 126 of file res_jabber.c.

struct ast_flags globalflags = { AJI_AUTOREGISTER } [static]

Global flags, initialized to default values.

Definition at line 162 of file res_jabber.c.

Definition at line 449 of file res_jabber.c.

char mandescr_jabber_send[] [static]

Definition at line 2949 of file res_jabber.c.


Generated on Wed Oct 28 11:46:18 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6