Fri Jun 19 12:10:48 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 = "a9c98e5d177805051735cb5b0b16b0a0" , .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 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_AUTOPRUNE | 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 3072 of file res_jabber.c.

static void __unreg_module ( void   )  [static]

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

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

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

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

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

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

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 2842 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 2614 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.

Referenced by aji_load_config().

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

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

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

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

Handles stuff.

Parameters:
data void
pak ikspak
Returns:
IKS_FILTER_EAT.

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

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

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

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

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

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

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

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

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

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

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

02220 {
02221    iks *roster = NULL;
02222    roster = iks_make_iq(IKS_TYPE_GET, IKS_NS_ROSTER);
02223 
02224    if(roster) {
02225       iks_insert_attrib(roster, "id", "roster");
02226       aji_set_presence(client, NULL, client->jid->full, client->status, client->statusmessage);
02227       ast_aji_send(client, roster);
02228    }
02229 
02230    iks_delete(roster);
02231    
02232    return 1;
02233 }

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

Referenced by aji_act_hook().

01469 {
01470    /*Nothing to see here */
01471 }

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

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

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

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

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

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

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

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

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

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

Referenced by aji_reload().

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

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

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

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

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

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

02198 {
02199    int res = 0;
02200 
02201    if (client->state)
02202       client->state = AJI_DISCONNECTED;
02203    client->timeout=50;
02204    if (client->p)
02205       iks_parser_reset(client->p);
02206    if (client->authorized)
02207       client->authorized = 0;
02208 
02209    res = aji_initialize(client);
02210 
02211    return res;
02212 }

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 - 1, 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       if (ret != IKS_OK) {
00692          ast_log(LOG_WARNING, "XML parsing failed\n");
00693          return ret;
00694       }
00695       ast_debug(3, "XML parsing successful\n"); 
00696    }
00697    return IKS_OK;
00698 }

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

receive message loop.

Parameters:
data void
Returns:
void.

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

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

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

Unknown.

Parameters:
data void
pak ikspak
Returns:
IKS_FILTER_EAT.

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

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

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

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

static int aji_reload ( int  reload  )  [static]

Reload the jabber module.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Referenced by unload_module().

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

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

02916 {
02917    struct aji_client *client = NULL;
02918    char *aux = NULL;
02919 
02920    client = ASTOBJ_CONTAINER_FIND(&clients, name);
02921    if (!client && strchr(name, '@')) {
02922       ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02923          aux = ast_strdupa(iterator->user);
02924          if (strchr(aux, '/')) {
02925             /* strip resource for comparison */
02926             aux = strsep(&aux, "/");
02927          }
02928          if (!strncasecmp(aux, name, strlen(aux))) {
02929             client = iterator;
02930          }           
02931       });
02932    }
02933 
02934    return client;
02935 }

struct aji_client_container* ast_aji_get_clients ( void   ) 

Definition at line 2937 of file res_jabber.c.

References clients.

02938 {
02939    return &clients;
02940 }

void ast_aji_increment_mid ( char *  mid  ) 

increments the mid field for messages and other events.

Parameters:
mid char.
Returns:
void.

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

01953 {
01954    int i = 0;
01955 
01956    for (i = strlen(mid) - 1; i >= 0; i--) {
01957       if (mid[i] != 'z') {
01958          mid[i] = mid[i] + 1;
01959          i = 0;
01960       } else
01961          mid[i] = 'a';
01962    }
01963 }

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

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

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

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

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

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

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

00733 {
00734    return aji_send_raw(client, iks_string(iks_stack(x), x));
00735 }

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

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

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 3046 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 2955 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().

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

static int reload ( void   )  [static]

Wrapper for aji_reload.

Definition at line 3062 of file res_jabber.c.

References aji_reload().

03063 {
03064    aji_reload(1);
03065    return 0;
03066 }

static int unload_module ( void   )  [static]

Unload the jabber module.

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

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


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

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

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 3072 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_AUTOPRUNE | 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 2942 of file res_jabber.c.

Referenced by load_module().


Generated on Fri Jun 19 12:10:49 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7