Thu Jul 9 13:41:30 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"

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_start_tls (struct aji_client *client)
 Starts the TLS procedure.
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.
static int aji_tls_handshake (struct aji_client *client)
 TLS handshake, OpenSSL initialization.
int ast_aji_create_chat (struct aji_client *client, char *room, char *server, char *topic)
 create a chatroom.
int ast_aji_disconnect (struct aji_client *client)
 disconnect from jabber server.
aji_clientast_aji_get_client (const char *name)
 grab a aji_client structure by label name or JID (without the resource string)
aji_client_containerast_aji_get_clients (void)
void ast_aji_increment_mid (char *mid)
 increments the mid field for messages and other events.
int ast_aji_invite_chat (struct aji_client *client, char *user, char *room, char *message)
 invite to a chatroom.
int ast_aji_join_chat (struct aji_client *client, char *room)
 join a chatroom.
int ast_aji_send (struct aji_client *client, 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 = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, .reload = reload, }
static struct ast_cli_entry aji_cli []
static char * ajisend_descrip
static char * ajisend_synopsis = "JabberSend(jabber,screenname,message)"
static char * ajistatus_descrip
static char * ajistatus_synopsis = "JabberStatus(Jabber,ScreenName,Variable)"
static char * app_ajisend = "JabberSend"
static char * app_ajistatus = "JabberStatus"
static const struct ast_module_infoast_module_info = &__mod_info
aji_capabilitiescapabilities = NULL
static struct ast_cli_entry cli_aji_do_debug_deprecated = { .handler = aji_do_debug_deprecated , .summary = "Enable/disable jabber debugging" ,__VA_ARGS__ }
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?

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

static void __unreg_module ( void   )  [static]

Definition at line 3083 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 868 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(), aji_start_tls(), aji_tls_handshake(), 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.

Referenced by aji_create_client().

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

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 2251 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().

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

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_create_client(), aji_dinfo_handler(), aji_ditems_handler(), aji_log_hook(), aji_recv_loop(), aji_register_approve_handler(), aji_register_query_handler(), aji_reload(), ast_aji_disconnect(), and unload_module().

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 1277 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.

Referenced by aji_create_client().

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

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

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

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

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 1337 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.

Referenced by aji_create_client().

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

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

Handles stuff.

Parameters:
data void
pak ikspak
Returns:
IKS_FILTER_EAT.

Definition at line 1182 of file res_jabber.c.

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

Referenced by aji_create_client().

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

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 2406 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.

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

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 2446 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.

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

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 2366 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.

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

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 2124 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().

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

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

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]

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, capabilities, LOG_ERROR, aji_capabilities::next, aji_version::next, aji_capabilities::node, 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 2229 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().

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

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

Referenced by aji_act_hook().

01479 {
01480    /*Nothing to see here */
01481 }

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 1488 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::list, aji_message::message, aji_client::message_timeout, and aji_client::messages.

Referenced by aji_act_hook().

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

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 1528 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, type, and ver.

Referenced by aji_act_hook().

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

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 1746 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().

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

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 2277 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().

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

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

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

Referenced by aji_recv().

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

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

References AJI_AUTOPRUNE, AJI_AUTOREGISTER, ast_category_browse(), 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, globalflags, JABBER_CONFIG, LOG_WARNING, and var.

Referenced by aji_reload().

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

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 787 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_create_client(), aji_recv(), and aji_send_raw().

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

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 2070 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.

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

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 2207 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().

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

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 645 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().

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

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

receive message loop.

Parameters:
data void
Returns:
void.

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

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

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

Unknown.

Parameters:
data void
pak ikspak
Returns:
IKS_FILTER_EAT.

Definition at line 1068 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.

Referenced by aji_create_client().

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

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 1111 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.

Referenced by aji_create_client().

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

static int aji_reload ( int  reload  )  [static]

Reload the jabber module.

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

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

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

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

Referenced by aji_act_hook(), and aji_tls_handshake().

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

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 755 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().

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

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 2332 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().

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

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 2513 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.

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

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 2468 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, clients, ast_cli_entry::command, ast_cli_args::fd, status, and ast_cli_entry::usage.

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

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 819 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().

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

static int aji_start_tls ( struct aji_client client  )  [static]

Starts the TLS procedure.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
Returns:
IKS_OK on success, an error code if sending failed, IKS_NET_TLSFAIL if OpenSSL is not installed

Definition at line 519 of file res_jabber.c.

References aji_client::p.

Referenced by aji_act_hook().

00520 {
00521    int ret;
00522 
00523    /* This is sent not encrypted */
00524    ret = iks_send_raw(client->p, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
00525    if (ret)
00526       return ret;
00527 
00528    client->stream_flags |= TRY_SECURE;
00529    return IKS_OK;
00530 }

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, chan, 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 2559 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.

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

static int aji_tls_handshake ( struct aji_client client  )  [static]

TLS handshake, OpenSSL initialization.

Parameters:
client the configured XMPP client we use to connect to a XMPP server
Returns:
IKS_OK on success, IKS_NET_TLSFAIL on failure

Definition at line 537 of file res_jabber.c.

References aji_send_header(), ast_debug, aji_client::jid, and aji_client::p.

Referenced by aji_act_hook().

00538 {
00539    int ret;
00540    int sock;
00541    
00542    ast_debug(1, "Starting TLS handshake\n"); 
00543 
00544    /* Load encryption, hashing algorithms and error strings */
00545    SSL_library_init();
00546    SSL_load_error_strings();
00547 
00548    /* Choose an SSL/TLS protocol version, create SSL_CTX */
00549    client->ssl_method = SSLv3_method();
00550    client->ssl_context = SSL_CTX_new(client->ssl_method);                
00551    if (!client->ssl_context)
00552       return IKS_NET_TLSFAIL;
00553 
00554    /* Create new SSL session */
00555    client->ssl_session = SSL_new(client->ssl_context);
00556    if (!client->ssl_session)
00557       return IKS_NET_TLSFAIL;
00558 
00559    /* Enforce TLS on our XMPP connection */
00560    sock = iks_fd(client->p);
00561    ret = SSL_set_fd(client->ssl_session, sock);
00562    if (!ret)
00563       return IKS_NET_TLSFAIL;
00564 
00565    /* Perform SSL handshake */
00566    ret = SSL_connect(client->ssl_session);
00567    if (!ret)
00568       return IKS_NET_TLSFAIL;
00569 
00570    client->stream_flags &= (~TRY_SECURE);
00571    client->stream_flags |= SECURE;
00572 
00573    /* Sent over the established TLS connection */
00574    ret = aji_send_header(client, client->jid->server);
00575    if (ret != IKS_OK)
00576       return IKS_NET_TLSFAIL;
00577 
00578    ast_debug(1, "TLS started with server\n"); 
00579 
00580    return IKS_OK;
00581 }

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

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

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

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

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

Referenced by unload_module().

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

struct aji_client* ast_aji_get_client ( const char *  name  ) 

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

Parameters:
name label or JID
Returns:
aji_client.

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

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

struct aji_client_container* ast_aji_get_clients ( void   ) 

Definition at line 2948 of file res_jabber.c.

References clients.

02949 {
02950    return &clients;
02951 }

void ast_aji_increment_mid ( char *  mid  ) 

increments the mid field for messages and other events.

Parameters:
mid char.
Returns:
void.

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

01963 {
01964    int i = 0;
01965 
01966    for (i = strlen(mid) - 1; i >= 0; i--) {
01967       if (mid[i] != 'z') {
01968          mid[i] = mid[i] + 1;
01969          i = 0;
01970       } else
01971          mid[i] = 'a';
01972    }
01973 }

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

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

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

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

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

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

int ast_aji_send ( struct aji_client client,
iks *  x 
)

Wraps raw sending.

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

Definition at line 742 of file res_jabber.c.

References aji_send_raw().

Referenced by aji_act_hook(), aji_client_info_handler(), aji_dinfo_handler(), aji_ditems_handler(), aji_get_roster(), aji_handle_presence(), aji_handle_subscribe(), aji_pruneregister(), aji_register_approve_handler(), aji_register_query_handler(), aji_set_presence(), aji_start_sasl(), ast_aji_create_chat(), ast_aji_invite_chat(), ast_aji_join_chat(), ast_aji_send_chat(), gtalk_action(), gtalk_add_candidate(), gtalk_create_candidates(), gtalk_digit(), gtalk_invite(), gtalk_invite_response(), gtalk_response(), jingle_accept_call(), jingle_action(), jingle_add_candidate(), jingle_create_candidates(), jingle_digit(), jingle_response(), and jingle_transmit_invite().

00743 {
00744    return aji_send_raw(client, iks_string(iks_stack(x), x));
00745 }

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 1791 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().

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

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]

Unload the jabber module.

Definition at line 3057 of file res_jabber.c.

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

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

Send a Jabber Message via call from the Manager.

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

Definition at line 2966 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(), astman_send_error(), and s.

Referenced by load_module().

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

static int reload ( void   )  [static]

Wrapper for aji_reload.

Definition at line 3073 of file res_jabber.c.

References aji_reload().

03074 {
03075    aji_reload(1);
03076    return 0;
03077 }

static int unload_module ( void   )  [static]

Unload the jabber module.

Definition at line 3033 of file res_jabber.c.

References aji_cli, 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, clients, and jabberstatus_function.

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


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 = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 3083 of file res_jabber.c.

struct ast_cli_entry aji_cli[] [static]

Definition at line 127 of file res_jabber.c.

Referenced by load_module(), and unload_module().

char* ajisend_descrip [static]

Initial value:

"JabberSend(Jabber,ScreenName,Message)\n"
"  Jabber - Client or transport Asterisk uses to connect to Jabber\n" 
"  ScreenName - 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 3083 of file res_jabber.c.

struct aji_capabilities* capabilities = NULL

Definition at line 159 of file res_jabber.c.

Referenced by aji_find_version(), and ast_request().

struct ast_cli_entry cli_aji_do_debug_deprecated = { .handler = aji_do_debug_deprecated , .summary = "Enable/disable jabber debugging" ,__VA_ARGS__ } [static]

Definition at line 126 of file res_jabber.c.

struct aji_client_container clients

Definition at line 158 of file res_jabber.c.

Referenced by aji_create_client(), aji_do_debug_deprecated(), aji_do_set_debug(), aji_reload(), aji_show_buddies(), aji_show_clients(), aji_test(), ast_aji_get_client(), ast_aji_get_clients(), gtalk_load_config(), jingle_load_config(), load_module(), and unload_module().

struct ast_flags globalflags = { AJI_AUTOREGISTER } [static]

Global flags, initialized to default values.

Definition at line 162 of file res_jabber.c.

struct ast_custom_function jabberstatus_function [static]

Definition at line 449 of file res_jabber.c.

Referenced by load_module(), and unload_module().

char mandescr_jabber_send[] [static]

Definition at line 2953 of file res_jabber.c.

Referenced by load_module().


Generated on Thu Jul 9 13:41:30 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7