Fri Nov 12 12:08:17 2010

Asterisk developer's documentation


res_jabber.c File Reference

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

#include "asterisk.h"
#include <ctype.h>
#include <iksemel.h>
#include "asterisk/channel.h"
#include "asterisk/jabber.h"
#include "asterisk/file.h"
#include "asterisk/config.h"
#include "asterisk/callerid.h"
#include "asterisk/lock.h"
#include "asterisk/cli.h"
#include "asterisk/app.h"
#include "asterisk/pbx.h"
#include "asterisk/md5.h"
#include "asterisk/acl.h"
#include "asterisk/utils.h"
#include "asterisk/module.h"
#include "asterisk/astobj.h"
#include "asterisk/astdb.h"
#include "asterisk/manager.h"
Include dependency graph for res_jabber.c:

Go to the source code of this file.

Defines

#define JABBER_CONFIG   "jabber.conf"

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_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.
struct aji_clientast_aji_get_client (const char *name)
 grab a aji_client structure by label name or JID (without the resource string)
struct aji_client_containerast_aji_get_clients (void)
void ast_aji_increment_mid (char *mid)
 increments the mid field for messages and other events.
int ast_aji_invite_chat (struct aji_client *client, char *user, char *room, char *message)
 invite to a chatroom.
int ast_aji_join_chat (struct aji_client *client, char *room)
 join a chatroom.
int ast_aji_send (struct aji_client *client, iks *x)
 Wraps raw sending.
int ast_aji_send_chat (struct aji_client *client, const char *address, const char *message)
 sends messages.
static int gtalk_yuck (iks *node)
 Jabber GTalk function.
static iks * jabber_make_auth (iksid *id, const char *pass, const char *sid)
 Setup the authentication struct.
static int load_module (void)
 Unload the jabber module.
static int manager_jabber_send (struct mansession *s, const struct message *m)
 Send a Jabber Message via call from the Manager.
static int reload (void)
 Wrapper for aji_reload.
static int unload_module (void)
 Unload the jabber module.

Variables

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

Detailed Description

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

References:

ExtRef:
Iksemel http://code.google.com/p/iksemel/
Todo:

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

Dialplan applications need RETURN variable, like JABBERSENDSTATUS

Definition in file res_jabber.c.


Define Documentation

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

Referenced by aji_load_config().


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 3111 of file res_jabber.c.

static void __unreg_module ( void   )  [static]

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

00490 {
00491    struct aji_client *client = NULL;
00492    struct aji_buddy *buddy = NULL;
00493    struct aji_resource *r = NULL;
00494    int stat = 7;
00495    AST_DECLARE_APP_ARGS(args,
00496       AST_APP_ARG(sender);
00497       AST_APP_ARG(jid);
00498    );
00499    AST_DECLARE_APP_ARGS(jid,
00500       AST_APP_ARG(screenname);
00501       AST_APP_ARG(resource);
00502    );
00503 
00504    if (!data) {
00505       ast_log(LOG_ERROR, "Usage: JABBER_STATUS(<sender>,<jid>[/<resource>])\n");
00506       return 0;
00507    }
00508    AST_STANDARD_APP_ARGS(args, data);
00509 
00510    if (args.argc != 2) {
00511       ast_log(LOG_ERROR, "JABBER_STATUS requires 2 arguments: sender and jid.\n");
00512       return -1;
00513    }
00514 
00515    AST_NONSTANDARD_APP_ARGS(jid, args.jid, '/');
00516 
00517    if (!(client = ast_aji_get_client(args.sender))) {
00518       ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
00519       return -1;
00520    }
00521    buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, jid.screenname);
00522    if (!buddy) {
00523       ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
00524       return -1;
00525    }
00526    r = aji_find_resource(buddy, jid.resource);
00527    if (!r && buddy->resources) 
00528       r = buddy->resources;
00529    if (!r)
00530       ast_log(LOG_NOTICE, "Resource %s of buddy %s was not found.\n", jid.resource, jid.screenname);
00531    else
00532       stat = r->status;
00533    snprintf(buf, buflen, "%d", stat);
00534    return 0;
00535 }

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 944 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::stream_flags, TRY_SECURE, aji_client::usesasl, and aji_client::usetls.

00945 {
00946    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00947    ikspak *pak = NULL;
00948    iks *auth = NULL;
00949    int features = 0;
00950 
00951    if(!node) {
00952       ast_log(LOG_ERROR, "aji_act_hook was called with out a packet\n"); /* most likely cause type is IKS_NODE_ERROR lost connection */
00953       ASTOBJ_UNREF(client, aji_client_destroy);
00954       return IKS_HOOK;
00955    }
00956 
00957    if (client->state == AJI_DISCONNECTING) {
00958       ASTOBJ_UNREF(client, aji_client_destroy);
00959       return IKS_HOOK;
00960    }
00961 
00962    pak = iks_packet(node);
00963 
00964    if (!client->component) { /*client */
00965       switch (type) {
00966       case IKS_NODE_START:
00967          if (client->usetls && !aji_is_secure(client)) {
00968 #ifndef HAVE_OPENSSL
00969             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");
00970             ASTOBJ_UNREF(client, aji_client_destroy);
00971             return IKS_HOOK;
00972 #else
00973             if (aji_start_tls(client) == IKS_NET_TLSFAIL) {
00974                ast_log(LOG_ERROR, "Could not start TLS\n");
00975                ASTOBJ_UNREF(client, aji_client_destroy);
00976                return IKS_HOOK;     
00977             }
00978 #endif
00979             break;
00980          }
00981          if (!client->usesasl) {
00982             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);
00983             auth = jabber_make_auth(client->jid, client->password, iks_find_attrib(node, "id"));
00984             if (auth) {
00985                iks_insert_attrib(auth, "id", client->mid);
00986                iks_insert_attrib(auth, "to", client->jid->server);
00987                ast_aji_increment_mid(client->mid);
00988                ast_aji_send(client, auth);
00989                iks_delete(auth);
00990             } else
00991                ast_log(LOG_ERROR, "Out of memory.\n");
00992          }
00993          break;
00994 
00995       case IKS_NODE_NORMAL:
00996 #ifdef HAVE_OPENSSL
00997          if (client->stream_flags & TRY_SECURE) {
00998             if (!strcmp("proceed", iks_name(node))) {
00999                return aji_tls_handshake(client);
01000             }
01001          }
01002 #endif
01003          if (!strcmp("stream:features", iks_name(node))) {
01004             features = iks_stream_features(node);
01005             if (client->usesasl) {
01006                if (client->usetls && !aji_is_secure(client))
01007                   break;
01008                if (client->authorized) {
01009                   if (features & IKS_STREAM_BIND) {
01010                      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);
01011                      auth = iks_make_resource_bind(client->jid);
01012                      if (auth) {
01013                         iks_insert_attrib(auth, "id", client->mid);
01014                         ast_aji_increment_mid(client->mid);
01015                         ast_aji_send(client, auth);
01016                         iks_delete(auth);
01017                      } else {
01018                         ast_log(LOG_ERROR, "Out of memory.\n");
01019                         break;
01020                      }
01021                   }
01022                   if (features & IKS_STREAM_SESSION) {
01023                      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);
01024                      auth = iks_make_session();
01025                      if (auth) {
01026                         iks_insert_attrib(auth, "id", "auth");
01027                         ast_aji_increment_mid(client->mid);
01028                         ast_aji_send(client, auth);
01029                         iks_delete(auth);
01030                      } else {
01031                         ast_log(LOG_ERROR, "Out of memory.\n");
01032                      }
01033                   }
01034                } else {
01035                   int ret;
01036                   if (!client->jid->user) {
01037                      ast_log(LOG_ERROR, "Malformed Jabber ID : %s (domain missing?)\n", client->jid->full);
01038                      break;
01039                   }
01040 
01041                   ret = aji_start_sasl(client, features, client->jid->user, client->password);
01042                   if (ret != IKS_OK) {
01043                      ASTOBJ_UNREF(client, aji_client_destroy);
01044                      return IKS_HOOK;
01045                   }
01046                   break;
01047                }
01048             }
01049          } else if (!strcmp("failure", iks_name(node))) {
01050             ast_log(LOG_ERROR, "JABBER: encryption failure. possible bad password.\n");
01051          } else if (!strcmp("success", iks_name(node))) {
01052             client->authorized = 1;
01053             aji_send_header(client, client->jid->server);
01054          }
01055          break;
01056       case IKS_NODE_ERROR: 
01057             ast_log(LOG_ERROR, "JABBER: Node Error\n");
01058             ASTOBJ_UNREF(client, aji_client_destroy);
01059             return IKS_HOOK;
01060             break;
01061       case IKS_NODE_STOP: 
01062             ast_log(LOG_WARNING, "JABBER: Disconnected\n");
01063             ASTOBJ_UNREF(client, aji_client_destroy);
01064             return IKS_HOOK;
01065             break;
01066       }
01067    } else if (client->state != AJI_CONNECTED && client->component) {
01068       switch (type) {
01069       case IKS_NODE_START:
01070          if (client->state == AJI_DISCONNECTED) {
01071             char secret[160], shasum[320], *handshake;
01072 
01073             sprintf(secret, "%s%s", pak->id, client->password);
01074             ast_sha1_hash(shasum, secret);
01075             handshake = NULL;
01076             if (asprintf(&handshake, "<handshake>%s</handshake>", shasum) >= 0) {
01077                aji_send_raw(client, handshake);
01078                ast_free(handshake);
01079                handshake = NULL;
01080             }
01081             client->state = AJI_CONNECTING;
01082             if(aji_recv(client, 1) == 2) /*XXX proper result for iksemel library on iks_recv of <handshake/> XXX*/
01083                client->state = AJI_CONNECTED;
01084             else
01085                ast_log(LOG_WARNING, "Jabber didn't seem to handshake, failed to authenticate.\n");
01086             break;
01087          }
01088          break;
01089 
01090       case IKS_NODE_NORMAL:
01091          break;
01092 
01093       case IKS_NODE_ERROR:
01094          ast_log(LOG_ERROR, "JABBER: Node Error\n");
01095          ASTOBJ_UNREF(client, aji_client_destroy);
01096          return IKS_HOOK;
01097 
01098       case IKS_NODE_STOP:
01099          ast_log(LOG_WARNING, "JABBER: Disconnected\n");
01100          ASTOBJ_UNREF(client, aji_client_destroy);
01101          return IKS_HOOK;
01102       }
01103    }
01104 
01105    switch (pak->type) {
01106    case IKS_PAK_NONE:
01107       ast_debug(1, "JABBER: I don't know what to do with paktype NONE.\n");
01108       break;
01109    case IKS_PAK_MESSAGE:
01110       aji_handle_message(client, pak);
01111       ast_debug(1, "JABBER: Handling paktype MESSAGE.\n");
01112       break;
01113    case IKS_PAK_PRESENCE:
01114       aji_handle_presence(client, pak);
01115       ast_debug(1, "JABBER: Handling paktype PRESENCE\n");
01116       break;
01117    case IKS_PAK_S10N:
01118       aji_handle_subscribe(client, pak);
01119       ast_debug(1, "JABBER: Handling paktype S10N\n");
01120       break;
01121    case IKS_PAK_IQ:
01122       ast_debug(1, "JABBER: Handling paktype IQ\n");
01123       aji_handle_iq(client, node);
01124       break;
01125    default:
01126       ast_debug(1, "JABBER: I don't know anything about paktype '%d'\n", pak->type);
01127       break;
01128    }
01129    
01130    iks_filter_packet(client->f, pak);
01131 
01132    if (node)
01133       iks_delete(node);
01134 
01135    ASTOBJ_UNREF(client, aji_client_destroy);
01136    return IKS_OK;
01137 }

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

00282 {
00283    struct aji_resource *tmp;
00284 
00285    while ((tmp = obj->resources)) {
00286       obj->resources = obj->resources->next;
00287       ast_free(tmp->description);
00288       ast_free(tmp);
00289    }
00290 
00291    ast_free(obj);
00292 }

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

02328 {
02329    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
02330    int res = 0;
02331 
02332    if (client) {
02333       if (client->state == AJI_DISCONNECTED) {
02334          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);
02335          client->state = AJI_CONNECTING;
02336          client->jid = (iks_find_cdata(pak->query, "jid")) ? iks_id_new(client->stack, iks_find_cdata(pak->query, "jid")) : client->jid;
02337          iks_filter_remove_hook(client->f, aji_client_connect);
02338          if(!client->component) /*client*/
02339             aji_get_roster(client);
02340       }
02341    } else
02342       ast_log(LOG_ERROR, "Out of memory.\n");
02343 
02344    ASTOBJ_UNREF(client, aji_client_destroy);
02345    return res;
02346 }

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

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

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

00258 {
00259    struct aji_message *tmp;
00260    ASTOBJ_CONTAINER_DESTROYALL(&obj->buddies, aji_buddy_destroy);
00261    ASTOBJ_CONTAINER_DESTROY(&obj->buddies);
00262    iks_filter_delete(obj->f);
00263    iks_parser_delete(obj->p);
00264    iks_stack_delete(obj->stack);
00265    AST_LIST_LOCK(&obj->messages);
00266    while ((tmp = AST_LIST_REMOVE_HEAD(&obj->messages, list))) {
00267       if (tmp->from)
00268          ast_free(tmp->from);
00269       if (tmp->message)
00270          ast_free(tmp->message);
00271    }
00272    AST_LIST_HEAD_DESTROY(&obj->messages);
00273    ast_free(obj);
00274 }

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

01354 {
01355    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01356    struct aji_resource *resource = NULL;
01357    struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01358 
01359    resource = aji_find_resource(buddy, pak->from->resource);
01360    if (pak->subtype == IKS_TYPE_RESULT) {
01361       if (!resource) {
01362          ast_log(LOG_NOTICE, "JABBER: Received client info from %s when not requested.\n", pak->from->full);
01363          ASTOBJ_UNREF(client, aji_client_destroy);
01364          return IKS_FILTER_EAT;
01365       }
01366       if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
01367          resource->cap->jingle = 1;
01368       } else
01369          resource->cap->jingle = 0;
01370    } else if (pak->subtype == IKS_TYPE_GET) {
01371       iks *iq, *disco, *ident, *google, *query;
01372       iq = iks_new("iq");
01373       query = iks_new("query");
01374       ident = iks_new("identity");
01375       disco = iks_new("feature");
01376       google = iks_new("feature");
01377       if (iq && ident && disco && google) {
01378          iks_insert_attrib(iq, "from", client->jid->full);
01379          iks_insert_attrib(iq, "to", pak->from->full);
01380          iks_insert_attrib(iq, "type", "result");
01381          iks_insert_attrib(iq, "id", pak->id);
01382          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01383          iks_insert_attrib(ident, "category", "client");
01384          iks_insert_attrib(ident, "type", "pc");
01385          iks_insert_attrib(ident, "name", "asterisk");
01386          iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco#info");
01387          iks_insert_attrib(google, "var", "http://www.google.com/xmpp/protocol/voice/v1");
01388          iks_insert_node(iq, query);
01389          iks_insert_node(query, ident);
01390          iks_insert_node(query, google);
01391          iks_insert_node(query, disco);
01392          ast_aji_send(client, iq);
01393       } else
01394          ast_log(LOG_ERROR, "Out of Memory.\n");
01395 
01396       iks_delete(iq);
01397       iks_delete(query);
01398       iks_delete(ident);
01399       iks_delete(google);
01400       iks_delete(disco);
01401    } else if (pak->subtype == IKS_TYPE_ERROR) {
01402       ast_log(LOG_NOTICE, "User %s does not support discovery.\n", pak->from->full);
01403    }
01404    ASTOBJ_UNREF(client, aji_client_destroy);
01405    return IKS_FILTER_EAT;
01406 }

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

References AJI_AUTOPRUNE, AJI_AUTOREGISTER, aji_create_buddy(), AJI_DISCONNECTED, ast_calloc, ast_copy_flags, ast_copy_string(), ast_false(), AST_FLAGS_ALL, AST_LIST_HEAD_INIT, ast_log(), ast_set2_flag, ast_true(), ASTOBJ_CONTAINER_FIND, ASTOBJ_CONTAINER_INIT, ASTOBJ_CONTAINER_MARKALL, ASTOBJ_INIT, ASTOBJ_UNMARK, ASTOBJ_WRLOCK, aji_client::authorized, aji_client::buddies, clients, aji_client::component, aji_client::debug, aji_client::flags, aji_client::forcessl, aji_client::keepalive, LOG_ERROR, LOG_WARNING, aji_client::message_timeout, aji_client::messages, aji_client::mid, ast_variable::name, aji_client::name, ast_variable::next, aji_client::password, aji_client::port, aji_client::priority, aji_client::serverhost, aji_client::state, aji_client::status, aji_client::statusmessage, aji_client::timeout, aji_client::user, aji_client::usesasl, aji_client::usetls, and ast_variable::value.

Referenced by aji_load_config().

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

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

01414 {
01415    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01416    char *node = NULL;
01417    struct aji_resource *resource = NULL;
01418    struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01419 
01420    resource = aji_find_resource(buddy, pak->from->resource);
01421    if (pak->subtype == IKS_TYPE_ERROR) {
01422       ast_log(LOG_WARNING, "Received error from a client, turn on jabber debug!\n");
01423       return IKS_FILTER_EAT;
01424    }
01425    if (pak->subtype == IKS_TYPE_RESULT) {
01426       if (!resource) {
01427          ast_log(LOG_NOTICE,"JABBER: Received client info from %s when not requested.\n", pak->from->full);
01428          ASTOBJ_UNREF(client, aji_client_destroy);
01429          return IKS_FILTER_EAT;
01430       }
01431       if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
01432          resource->cap->jingle = 1;
01433       } else
01434          resource->cap->jingle = 0;
01435    } else if (pak->subtype == IKS_TYPE_GET && !(node = iks_find_attrib(pak->query, "node"))) {
01436       iks *iq, *query, *identity, *disco, *reg, *commands, *gateway, *version, *vcard, *search;
01437 
01438       iq = iks_new("iq");
01439       query = iks_new("query");
01440       identity = iks_new("identity");
01441       disco = iks_new("feature");
01442       reg = iks_new("feature");
01443       commands = iks_new("feature");
01444       gateway = iks_new("feature");
01445       version = iks_new("feature");
01446       vcard = iks_new("feature");
01447       search = iks_new("feature");
01448 
01449       if (iq && query && identity && disco && reg && commands && gateway && version && vcard && search && client) {
01450          iks_insert_attrib(iq, "from", client->user);
01451          iks_insert_attrib(iq, "to", pak->from->full);
01452          iks_insert_attrib(iq, "id", pak->id);
01453          iks_insert_attrib(iq, "type", "result");
01454          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01455          iks_insert_attrib(identity, "category", "gateway");
01456          iks_insert_attrib(identity, "type", "pstn");
01457          iks_insert_attrib(identity, "name", "Asterisk The Open Source PBX");
01458          iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco");
01459          iks_insert_attrib(reg, "var", "jabber:iq:register");
01460          iks_insert_attrib(commands, "var", "http://jabber.org/protocol/commands");
01461          iks_insert_attrib(gateway, "var", "jabber:iq:gateway");
01462          iks_insert_attrib(version, "var", "jabber:iq:version");
01463          iks_insert_attrib(vcard, "var", "vcard-temp");
01464          iks_insert_attrib(search, "var", "jabber:iq:search");
01465 
01466          iks_insert_node(iq, query);
01467          iks_insert_node(query, identity);
01468          iks_insert_node(query, disco);
01469          iks_insert_node(query, reg);
01470          iks_insert_node(query, commands);
01471          iks_insert_node(query, gateway);
01472          iks_insert_node(query, version);
01473          iks_insert_node(query, vcard);
01474          iks_insert_node(query, search);
01475          ast_aji_send(client, iq);
01476       } else {
01477          ast_log(LOG_ERROR, "Out of memory.\n");
01478       }
01479 
01480       iks_delete(iq);
01481       iks_delete(query);
01482       iks_delete(identity);
01483       iks_delete(disco);
01484       iks_delete(reg);
01485       iks_delete(commands);
01486       iks_delete(gateway);
01487       iks_delete(version);
01488       iks_delete(vcard);
01489       iks_delete(search);
01490 
01491    } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "http://jabber.org/protocol/commands")) {
01492       iks *iq, *query, *confirm;
01493       iq = iks_new("iq");
01494       query = iks_new("query");
01495       confirm = iks_new("item");
01496 
01497       if (iq && query && confirm && client) {
01498          iks_insert_attrib(iq, "from", client->user);
01499          iks_insert_attrib(iq, "to", pak->from->full);
01500          iks_insert_attrib(iq, "id", pak->id);
01501          iks_insert_attrib(iq, "type", "result");
01502          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01503          iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
01504          iks_insert_attrib(confirm, "node", "confirmaccount");
01505          iks_insert_attrib(confirm, "name", "Confirm AIM account");
01506          iks_insert_attrib(confirm, "jid", client->user);
01507          iks_insert_node(iq, query);
01508          iks_insert_node(query, confirm);
01509          ast_aji_send(client, iq);
01510       } else {
01511          ast_log(LOG_ERROR, "Out of memory.\n");
01512       }
01513 
01514       iks_delete(iq);
01515       iks_delete(query);
01516       iks_delete(confirm);
01517 
01518    } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "confirmaccount")) {
01519       iks *iq, *query, *feature;
01520 
01521       iq = iks_new("iq");
01522       query = iks_new("query");
01523       feature = iks_new("feature");
01524 
01525       if (iq && query && feature && client) {
01526          iks_insert_attrib(iq, "from", client->user);
01527          iks_insert_attrib(iq, "to", pak->from->full);
01528          iks_insert_attrib(iq, "id", pak->id);
01529          iks_insert_attrib(iq, "type", "result");
01530          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01531          iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
01532          iks_insert_node(iq, query);
01533          iks_insert_node(query, feature);
01534          ast_aji_send(client, iq);
01535       } else {
01536          ast_log(LOG_ERROR, "Out of memory.\n");
01537       }
01538 
01539       iks_delete(iq);
01540       iks_delete(query);
01541       iks_delete(feature);
01542    }
01543 
01544    ASTOBJ_UNREF(client, aji_client_destroy);
01545    return IKS_FILTER_EAT;
01546 }

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

Handles stuff.

Parameters:
data void
pak ikspak
Returns:
IKS_FILTER_EAT.

Definition at line 1258 of file res_jabber.c.

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

01259 {
01260    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01261    char *node = NULL;
01262 
01263    if (!(node = iks_find_attrib(pak->query, "node"))) {
01264       iks *iq = NULL, *query = NULL, *item = NULL;
01265       iq = iks_new("iq");
01266       query = iks_new("query");
01267       item = iks_new("item");
01268 
01269       if (iq && query && item) {
01270          iks_insert_attrib(iq, "from", client->user);
01271          iks_insert_attrib(iq, "to", pak->from->full);
01272          iks_insert_attrib(iq, "id", pak->id);
01273          iks_insert_attrib(iq, "type", "result");
01274          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01275          iks_insert_attrib(item, "node", "http://jabber.org/protocol/commands");
01276          iks_insert_attrib(item, "name", "Million Dollar Asterisk Commands");
01277          iks_insert_attrib(item, "jid", client->user);
01278 
01279          iks_insert_node(iq, query);
01280          iks_insert_node(query, item);
01281          ast_aji_send(client, iq);
01282       } else {
01283          ast_log(LOG_ERROR, "Out of memory.\n");
01284       }
01285 
01286       iks_delete(iq);
01287       iks_delete(query);
01288       iks_delete(item);
01289 
01290    } else if (!strcasecmp(node, "http://jabber.org/protocol/commands")) {
01291       iks *iq, *query, *confirm;
01292       iq = iks_new("iq");
01293       query = iks_new("query");
01294       confirm = iks_new("item");
01295       if (iq && query && confirm && client) {
01296          iks_insert_attrib(iq, "from", client->user);
01297          iks_insert_attrib(iq, "to", pak->from->full);
01298          iks_insert_attrib(iq, "id", pak->id);
01299          iks_insert_attrib(iq, "type", "result");
01300          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01301          iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
01302          iks_insert_attrib(confirm, "node", "confirmaccount");
01303          iks_insert_attrib(confirm, "name", "Confirm AIM account");
01304          iks_insert_attrib(confirm, "jid", "blog.astjab.org");
01305 
01306          iks_insert_node(iq, query);
01307          iks_insert_node(query, confirm);
01308          ast_aji_send(client, iq);
01309       } else {
01310          ast_log(LOG_ERROR, "Out of memory.\n");
01311       }
01312 
01313       iks_delete(iq);
01314       iks_delete(query);
01315       iks_delete(confirm);
01316 
01317    } else if (!strcasecmp(node, "confirmaccount")) {
01318       iks *iq = NULL, *query = NULL, *feature = NULL;
01319 
01320       iq = iks_new("iq");
01321       query = iks_new("query");
01322       feature = iks_new("feature");
01323 
01324       if (iq && query && feature && client) {
01325          iks_insert_attrib(iq, "from", client->user);
01326          iks_insert_attrib(iq, "to", pak->from->full);
01327          iks_insert_attrib(iq, "id", pak->id);
01328          iks_insert_attrib(iq, "type", "result");
01329          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01330          iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
01331          iks_insert_node(iq, query);
01332          iks_insert_node(query, feature);
01333          ast_aji_send(client, iq);
01334       } else {
01335          ast_log(LOG_ERROR, "Out of memory.\n");
01336       }
01337 
01338       iks_delete(iq);
01339       iks_delete(query);
01340       iks_delete(feature);
01341    }
01342 
01343    ASTOBJ_UNREF(client, aji_client_destroy);
01344    return IKS_FILTER_EAT;
01345 
01346 }

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

02483 {
02484    switch (cmd) {
02485    case CLI_INIT:
02486       e->command = "jabber reload";
02487       e->usage =
02488          "Usage: jabber reload\n"
02489          "       Reloads the Jabber module.\n";
02490       return NULL;
02491    case CLI_GENERATE:
02492       return NULL;
02493    }
02494 
02495    aji_reload(1);
02496    ast_cli(a->fd, "Jabber Reloaded.\n");
02497    return CLI_SUCCESS;
02498 }

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

02443 {
02444    switch (cmd) {
02445    case CLI_INIT:
02446       e->command = "jabber set debug {on|off}";
02447       e->usage =
02448          "Usage: jabber set debug {on|off}\n"
02449          "       Enables/disables dumping of XMPP/Jabber packets for debugging purposes.\n";
02450       return NULL;
02451    case CLI_GENERATE:
02452       return NULL;
02453    }
02454 
02455    if (a->argc != e->args)
02456       return CLI_SHOWUSAGE;
02457 
02458    if (!strncasecmp(a->argv[e->args - 1], "on", 2)) {
02459       ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02460          ASTOBJ_RDLOCK(iterator); 
02461          iterator->debug = 1;
02462          ASTOBJ_UNLOCK(iterator);
02463       });
02464       ast_cli(a->fd, "Jabber Debugging Enabled.\n");
02465       return CLI_SUCCESS;
02466    } else if (!strncasecmp(a->argv[e->args - 1], "off", 3)) {
02467       ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02468          ASTOBJ_RDLOCK(iterator); 
02469          iterator->debug = 0;
02470          ASTOBJ_UNLOCK(iterator);
02471       });
02472       ast_cli(a->fd, "Jabber Debugging Disabled.\n");
02473       return CLI_SUCCESS;
02474    }
02475    return CLI_SHOWUSAGE; /* defaults to invalid */
02476 }

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

02201 {
02202    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
02203    int flag = 0;
02204    iks *x = NULL;
02205    struct aji_buddy *buddy;
02206    
02207    client->state = AJI_CONNECTED;
02208    ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02209       ASTOBJ_RDLOCK(iterator);
02210       x = iks_child(pak->query);
02211       flag = 0;
02212       while (x) {
02213          if (!iks_strcmp(iks_name(x), "item")) {
02214             if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid"))) {
02215                flag = 1;
02216                ast_clear_flag(&iterator->flags, AJI_AUTOPRUNE | AJI_AUTOREGISTER);
02217             }
02218          }
02219          x = iks_next(x);
02220       }
02221       if (!flag)
02222          ast_copy_flags(&iterator->flags, &client->flags, AJI_AUTOREGISTER);
02223       iks_delete(x);
02224       
02225       ASTOBJ_UNLOCK(iterator);
02226    });
02227 
02228    x = iks_child(pak->query);
02229    while (x) {
02230       flag = 0;
02231       if (iks_strcmp(iks_name(x), "item") == 0) {
02232          ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02233             ASTOBJ_RDLOCK(iterator);
02234             if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid")))
02235                flag = 1;
02236             ASTOBJ_UNLOCK(iterator);
02237          });
02238 
02239          if (flag) {
02240             /* found buddy, don't create a new one */
02241             x = iks_next(x);
02242             continue;
02243          }
02244          
02245          buddy = ast_calloc(1, sizeof(*buddy));
02246          if (!buddy) {
02247             ast_log(LOG_WARNING, "Out of memory\n");
02248             return 0;
02249          }
02250          ASTOBJ_INIT(buddy);
02251          ASTOBJ_WRLOCK(buddy);
02252          ast_copy_string(buddy->name, iks_find_attrib(x, "jid"), sizeof(buddy->name));
02253          ast_clear_flag(&buddy->flags, AST_FLAGS_ALL);
02254          if(ast_test_flag(&client->flags, AJI_AUTOPRUNE)) {
02255             ast_set_flag(&buddy->flags, AJI_AUTOPRUNE);
02256             ASTOBJ_MARK(buddy);
02257          } else if (!iks_strcmp(iks_find_attrib(x, "subscription"), "none") || !iks_strcmp(iks_find_attrib(x, "subscription"), "from")) {
02258             /* subscribe to buddy's presence only 
02259                if we really need to */
02260             ast_set_flag(&buddy->flags, AJI_AUTOREGISTER);
02261          }
02262          ASTOBJ_UNLOCK(buddy);
02263          if (buddy) {
02264             ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
02265             ASTOBJ_UNREF(buddy, aji_buddy_destroy);
02266          }
02267       }
02268       x = iks_next(x);
02269    }
02270 
02271    iks_delete(x);
02272    aji_pruneregister(client);
02273 
02274    ASTOBJ_UNREF(client, aji_client_destroy);
02275    return IKS_FILTER_EAT;
02276 }

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

Find the aji_resource we want.

Parameters:
buddy aji_buddy A buddy
name 
Returns:
aji_resource object

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

00371 {
00372    struct aji_resource *res = NULL;
00373    if (!buddy || !name)
00374       return res;
00375    res = buddy->resources;
00376    while (res) {
00377       if (!strcasecmp(res->resource, name)) {
00378          break;
00379       }
00380       res = res->next;
00381    }
00382    return res;
00383 }

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

Find version in XML stream and populate our capabilities list.

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

Definition at line 303 of file res_jabber.c.

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

Referenced by aji_handle_presence().

00304 {
00305    struct aji_capabilities *list = NULL;
00306    struct aji_version *res = NULL;
00307 
00308    list = capabilities;
00309 
00310    if(!node)
00311       node = pak->from->full;
00312    if(!version)
00313       version = "none supplied.";
00314    while(list) {
00315       if(!strcasecmp(list->node, node)) {
00316          res = list->versions;
00317          while(res) {
00318              if(!strcasecmp(res->version, version))
00319                 return res;
00320              res = res->next;
00321          }
00322          /* Specified version not found. Let's add it to 
00323             this node in our capabilities list */
00324          if(!res) {
00325             res = ast_malloc(sizeof(*res));
00326             if(!res) {
00327                ast_log(LOG_ERROR, "Out of memory!\n");
00328                return NULL;
00329             }
00330             res->jingle = 0;
00331             res->parent = list;
00332             ast_copy_string(res->version, version, sizeof(res->version));
00333             res->next = list->versions;
00334             list->versions = res;
00335             return res;
00336          }
00337       }
00338       list = list->next;
00339    }
00340    /* Specified node not found. Let's add it our capabilities list */
00341    if(!list) {
00342       list = ast_malloc(sizeof(*list));
00343       if(!list) {
00344          ast_log(LOG_ERROR, "Out of memory!\n");
00345          return NULL;
00346       }
00347       res = ast_malloc(sizeof(*res));
00348       if(!res) {
00349          ast_log(LOG_ERROR, "Out of memory!\n");
00350          ast_free(list);
00351          return NULL;
00352       }
00353       ast_copy_string(list->node, node, sizeof(list->node));
00354       ast_copy_string(res->version, version, sizeof(res->version));
00355       res->jingle = 0;
00356       res->parent = list;
00357       res->next = NULL;
00358       list->versions = res;
00359       list->next = capabilities;
00360       capabilities = list;
00361    }
00362    return res;
00363 }

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

02306 {
02307    iks *roster = NULL;
02308    roster = iks_make_iq(IKS_TYPE_GET, IKS_NS_ROSTER);
02309 
02310    if(roster) {
02311       iks_insert_attrib(roster, "id", "roster");
02312       aji_set_presence(client, NULL, client->jid->full, client->status, client->statusmessage);
02313       ast_aji_send(client, roster);
02314    }
02315 
02316    iks_delete(roster);
02317    
02318    return 1;
02319 }

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

Referenced by aji_act_hook().

01555 {
01556    /*Nothing to see here */
01557 }

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

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

Referenced by aji_act_hook().

01565 {
01566    struct aji_message *insert, *tmp;
01567    int flag = 0;
01568    
01569    if (!(insert = ast_calloc(1, sizeof(*insert))))
01570       return;
01571    time(&insert->arrived);
01572    if (iks_find_cdata(pak->x, "body"))
01573       insert->message = ast_strdup(iks_find_cdata(pak->x, "body"));
01574    if (pak->id)
01575       ast_copy_string(insert->id, pak->id, sizeof(insert->message));
01576    if (pak->from)
01577       insert->from = ast_strdup(pak->from->full);
01578    AST_LIST_LOCK(&client->messages);
01579    AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, tmp, list) {
01580       if (flag) {
01581          AST_LIST_REMOVE_CURRENT(list);
01582          if (tmp->from)
01583             ast_free(tmp->from);
01584          if (tmp->message)
01585             ast_free(tmp->message);
01586       } else if (difftime(time(NULL), tmp->arrived) >= client->message_timeout) {
01587          flag = 1;
01588          AST_LIST_REMOVE_CURRENT(list);
01589          if (tmp->from)
01590             ast_free(tmp->from);
01591          if (tmp->message)
01592             ast_free(tmp->message);
01593       }
01594    }
01595    AST_LIST_TRAVERSE_SAFE_END;
01596    AST_LIST_INSERT_HEAD(&client->messages, insert, list);
01597    AST_LIST_UNLOCK(&client->messages);
01598 }

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

References aji_buddy_destroy(), AJI_CONNECTED, aji_create_buddy(), aji_find_version(), aji_set_presence(), ast_aji_increment_mid(), ast_aji_send(), ast_calloc, ast_copy_string(), ast_debug, ast_free, ast_log(), ast_strdup, ast_verbose, ASTOBJ_CONTAINER_FIND, ASTOBJ_UNLOCK, ASTOBJ_UNREF, ASTOBJ_WRLOCK, aji_client::buddies, aji_client::component, descrip, aji_resource::description, gtalk_yuck(), aji_client::jid, last, LOG_ERROR, LOG_NOTICE, aji_client::mid, aji_resource::next, option_debug, aji_resource::priority, aji_resource::resource, aji_buddy::resources, aji_client::state, aji_resource::status, aji_client::status, status, aji_client::statusmessage, type, and ver.

Referenced by aji_act_hook().

01605 {
01606    int status, priority;
01607    struct aji_buddy *buddy;
01608    struct aji_resource *tmp = NULL, *last = NULL, *found = NULL;
01609    char *ver, *node, *descrip, *type;
01610    
01611    if(client->state != AJI_CONNECTED)
01612       aji_create_buddy(pak->from->partial, client);
01613 
01614    buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01615    if (!buddy && pak->from->partial) {
01616       /* allow our jid to be used to log in with another resource */
01617       if (!strcmp((const char *)pak->from->partial, (const char *)client->jid->partial))
01618          aji_create_buddy(pak->from->partial, client);
01619       else
01620          ast_log(LOG_NOTICE, "Got presence packet from %s, someone not in our roster!!!!\n", pak->from->partial);
01621       return;
01622    }
01623    type = iks_find_attrib(pak->x, "type");
01624    if(client->component && type &&!strcasecmp("probe", type)) {
01625       aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), client->status, client->statusmessage);
01626       ast_verbose("what i was looking for \n");
01627    }
01628    ASTOBJ_WRLOCK(buddy);
01629    status = (pak->show) ? pak->show : 6;
01630    priority = atoi((iks_find_cdata(pak->x, "priority")) ? iks_find_cdata(pak->x, "priority") : "0");
01631    tmp = buddy->resources;
01632    descrip = ast_strdup(iks_find_cdata(pak->x,"status"));
01633 
01634    while (tmp && pak->from->resource) {
01635       if (!strcasecmp(tmp->resource, pak->from->resource)) {
01636          tmp->status = status;
01637          if (tmp->description) ast_free(tmp->description);
01638          tmp->description = descrip;
01639          found = tmp;
01640          if (status == 6) {   /* Sign off Destroy resource */
01641             if (last && found->next) {
01642                last->next = found->next;
01643             } else if (!last) {
01644                if (found->next)
01645                   buddy->resources = found->next;
01646                else
01647                   buddy->resources = NULL;
01648             } else if (!found->next) {
01649                if (last)
01650                   last->next = NULL;
01651                else
01652                   buddy->resources = NULL;
01653             }
01654             ast_free(found);
01655             found = NULL;
01656             break;
01657          }
01658          /* resource list is sorted by descending priority */
01659          if (tmp->priority != priority) {
01660             found->priority = priority;
01661             if (!last && !found->next)
01662                /* resource was found to be unique,
01663                   leave loop */
01664                break;
01665             /* search for resource in our list
01666                and take it out for the moment */
01667             if (last)
01668                last->next = found->next;
01669             else
01670                buddy->resources = found->next;
01671 
01672             last = NULL;
01673             tmp = buddy->resources;
01674             if (!buddy->resources)
01675                buddy->resources = found;
01676             /* priority processing */
01677             while (tmp) {
01678                /* insert resource back according to 
01679                   its priority value */
01680                if (found->priority > tmp->priority) {
01681                   if (last)
01682                      /* insert within list */
01683                      last->next = found;
01684                   found->next = tmp;
01685                   if (!last)
01686                      /* insert on top */
01687                      buddy->resources = found;
01688                   break;
01689                }
01690                if (!tmp->next) {
01691                   /* insert at the end of the list */
01692                   tmp->next = found;
01693                   found->next = NULL;
01694                   break;
01695                }
01696                last = tmp;
01697                tmp = tmp->next;
01698             }
01699          }
01700          break;
01701       }
01702       last = tmp;
01703       tmp = tmp->next;
01704    }
01705 
01706    /* resource not found in our list, create it */
01707    if (!found && status != 6 && pak->from->resource) {
01708       found = ast_calloc(1, sizeof(*found));
01709 
01710       if (!found) {
01711          ast_log(LOG_ERROR, "Out of memory!\n");
01712          return;
01713       }
01714       ast_copy_string(found->resource, pak->from->resource, sizeof(found->resource));
01715       found->status = status;
01716       found->description = descrip;
01717       found->priority = priority;
01718       found->next = NULL;
01719       last = NULL;
01720       tmp = buddy->resources;
01721       while (tmp) {
01722          if (found->priority > tmp->priority) {
01723             if (last)
01724                last->next = found;
01725             found->next = tmp;
01726             if (!last)
01727                buddy->resources = found;
01728             break;
01729          }
01730          if (!tmp->next) {
01731             tmp->next = found;
01732             break;
01733          }
01734          last = tmp;
01735          tmp = tmp->next;
01736       }
01737       if (!tmp)
01738          buddy->resources = found;
01739    }
01740    
01741    ASTOBJ_UNLOCK(buddy);
01742    ASTOBJ_UNREF(buddy, aji_buddy_destroy);
01743 
01744    node = iks_find_attrib(iks_find(pak->x, "c"), "node");
01745    ver = iks_find_attrib(iks_find(pak->x, "c"), "ver");
01746 
01747    /* handle gmail client's special caps:c tag */
01748    if (!node && !ver) {
01749       node = iks_find_attrib(iks_find(pak->x, "caps:c"), "node");
01750       ver = iks_find_attrib(iks_find(pak->x, "caps:c"), "ver");
01751    }
01752 
01753    /* retrieve capabilites of the new resource */
01754    if(status !=6 && found && !found->cap) {
01755       found->cap = aji_find_version(node, ver, pak);
01756       if(gtalk_yuck(pak->x)) /* gtalk should do discover */
01757          found->cap->jingle = 1;
01758       if(found->cap->jingle && option_debug > 4) {
01759          ast_debug(1,"Special case for google till they support discover.\n");
01760       }
01761       else {
01762          iks *iq, *query;
01763          iq = iks_new("iq");
01764          query = iks_new("query");
01765          if(query && iq)  {
01766             iks_insert_attrib(iq, "type", "get");
01767             iks_insert_attrib(iq, "to", pak->from->full);
01768             iks_insert_attrib(iq,"from", client->jid->full);
01769             iks_insert_attrib(iq, "id", client->mid);
01770             ast_aji_increment_mid(client->mid);
01771             iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01772             iks_insert_node(iq, query);
01773             ast_aji_send(client, iq);
01774             
01775          } else
01776             ast_log(LOG_ERROR, "Out of memory.\n");
01777          
01778          iks_delete(query);
01779          iks_delete(iq);
01780       }
01781    }
01782    switch (pak->subtype) {
01783    case IKS_TYPE_AVAILABLE:
01784       ast_debug(3, "JABBER: I am available ^_* %i\n", pak->subtype);
01785       break;
01786    case IKS_TYPE_UNAVAILABLE:
01787       ast_debug(3, "JABBER: I am unavailable ^_* %i\n", pak->subtype);
01788       break;
01789    default:
01790       ast_debug(3, "JABBER: Ohh sexy and the wrong type: %i\n", pak->subtype);
01791    }
01792    switch (pak->show) {
01793    case IKS_SHOW_UNAVAILABLE:
01794       ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01795       break;
01796    case IKS_SHOW_AVAILABLE:
01797       ast_debug(3, "JABBER: type is available\n");
01798       break;
01799    case IKS_SHOW_CHAT:
01800       ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01801       break;
01802    case IKS_SHOW_AWAY:
01803       ast_debug(3, "JABBER: type is away\n");
01804       break;
01805    case IKS_SHOW_XA:
01806       ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01807       break;
01808    case IKS_SHOW_DND:
01809       ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01810       break;
01811    default:
01812       ast_debug(3, "JABBER: Kinky! how did that happen %i\n", pak->show);
01813    }
01814 }

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

01823 {
01824    iks *presence = NULL, *status = NULL;
01825    struct aji_buddy* buddy = NULL;
01826 
01827    switch (pak->subtype) { 
01828    case IKS_TYPE_SUBSCRIBE:
01829       presence = iks_new("presence");
01830       status = iks_new("status");
01831       if (presence && status) {
01832          iks_insert_attrib(presence, "type", "subscribed");
01833          iks_insert_attrib(presence, "to", pak->from->full);
01834          iks_insert_attrib(presence, "from", client->jid->full);
01835          if (pak->id)
01836             iks_insert_attrib(presence, "id", pak->id);
01837          iks_insert_cdata(status, "Asterisk has approved subscription", 0);
01838          iks_insert_node(presence, status);
01839          ast_aji_send(client, presence);
01840       } else
01841          ast_log(LOG_ERROR, "Unable to allocate nodes\n");
01842 
01843       iks_delete(presence);
01844       iks_delete(status);
01845 
01846       if (client->component)
01847          aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), client->status, client->statusmessage);
01848    case IKS_TYPE_SUBSCRIBED:
01849       buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01850       if (!buddy && pak->from->partial) {
01851          aji_create_buddy(pak->from->partial, client);
01852       }
01853    default:
01854       if (option_verbose > 4) {
01855          ast_verbose(VERBOSE_PREFIX_3 "JABBER: This is a subcription of type %i\n", pak->subtype);
01856       }
01857    }
01858 }

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 2353 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, aji_client::stream_flags, and aji_client::user.

Referenced by aji_reconnect().

02354 {
02355    int connected = IKS_NET_NOCONN;
02356 
02357 #ifdef HAVE_OPENSSL  
02358    /* reset stream flags */
02359    client->stream_flags = 0;
02360 #endif
02361    /* If it's a component, connect to user, otherwise, connect to server */
02362    connected = iks_connect_via(client->p, S_OR(client->serverhost, client->jid->server), client->port, client->component ? client->user : client->jid->server);
02363 
02364    if (connected == IKS_NET_NOCONN) {
02365       ast_log(LOG_ERROR, "JABBER ERROR: No Connection\n");
02366       return IKS_HOOK;
02367    } else   if (connected == IKS_NET_NODNS) {
02368       ast_log(LOG_ERROR, "JABBER ERROR: No DNS %s for client to  %s\n", client->name, S_OR(client->serverhost, client->jid->server));
02369       return IKS_HOOK;
02370    }
02371 
02372    return IKS_OK;
02373 }

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

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

Referenced by aji_recv().

00670 {
00671    int sock;
00672    fd_set fds;
00673    struct timeval tv, *tvptr = NULL;
00674    int len, res;
00675 
00676 #ifdef HAVE_OPENSSL
00677    if (aji_is_secure(client)) {
00678       sock = SSL_get_fd(client->ssl_session);
00679       if (sock < 0)
00680          return -1;     
00681    } else
00682 #endif /* HAVE_OPENSSL */
00683       sock = iks_fd(client->p);  
00684 
00685    memset(&tv, 0, sizeof(struct timeval));
00686    FD_ZERO(&fds);
00687    FD_SET(sock, &fds);
00688    tv.tv_sec = timeout;
00689 
00690    /* NULL value for tvptr makes ast_select wait indefinitely */
00691    tvptr = (timeout != -1) ? &tv : NULL;
00692 
00693    /* ast_select emulates linux behaviour in terms of timeout handling */
00694    res = ast_select(sock + 1, &fds, NULL, NULL, tvptr);
00695    if (res > 0) {
00696 #ifdef HAVE_OPENSSL
00697       if (aji_is_secure(client)) {
00698          len = SSL_read(client->ssl_session, buffer, buf_len);
00699       } else
00700 #endif /* HAVE_OPENSSL */
00701          len = recv(sock, buffer, buf_len, 0);
00702 
00703       if (len > 0) {
00704          return len;
00705       } else if (len <= 0) {
00706          return -1;
00707       }
00708    }
00709    return res;
00710 }

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

References SECURE, and aji_client::stream_flags.

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

00584 {
00585 #ifdef HAVE_OPENSSL
00586    return client->stream_flags & SECURE;
00587 #else
00588    return 0;
00589 #endif
00590 }

static int aji_load_config ( int  reload  )  [static]

Definition at line 2907 of file res_jabber.c.

References AJI_AUTOPRUNE, AJI_AUTOREGISTER, aji_create_client(), ast_category_browse(), ast_config_destroy(), ast_config_load, ast_false(), ast_log(), ast_set2_flag, ast_set_flag, ast_true(), ast_variable_browse(), ast_variable_retrieve(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, CONFIG_STATUS_FILEUNCHANGED, debug, JABBER_CONFIG, LOG_WARNING, ast_variable::name, ast_variable::next, ast_variable::value, and var.

Referenced by aji_reload().

02908 {
02909    char *cat = NULL;
02910    int debug = 1;
02911    struct ast_config *cfg = NULL;
02912    struct ast_variable *var = NULL;
02913    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
02914 
02915    if ((cfg = ast_config_load(JABBER_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
02916       return -1;
02917 
02918    /* Reset flags to default value */
02919    ast_set_flag(&globalflags, AJI_AUTOREGISTER);
02920 
02921    if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
02922       ast_log(LOG_WARNING, "No such configuration file %s\n", JABBER_CONFIG);
02923       return 0;
02924    }
02925 
02926    cat = ast_category_browse(cfg, NULL);
02927    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
02928       if (!strcasecmp(var->name, "debug")) {
02929          debug = (ast_false(ast_variable_retrieve(cfg, "general", "debug"))) ? 0 : 1;
02930       } else if (!strcasecmp(var->name, "autoprune")) {
02931          ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOPRUNE);
02932       } else if (!strcasecmp(var->name, "autoregister")) {
02933          ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOREGISTER);
02934       }
02935    }
02936 
02937    while (cat) {
02938       if (strcasecmp(cat, "general")) {
02939             var = ast_variable_browse(cfg, cat);
02940             aji_create_client(cat, var, debug);
02941       }
02942       cat = ast_category_browse(cfg, cat);
02943    }
02944    ast_config_destroy(cfg); /* or leak memory */
02945    return 1;
02946 }

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

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

Referenced by aji_recv(), and aji_send_raw().

00864 {
00865    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00866 
00867    if (!ast_strlen_zero(xmpp))
00868       manager_event(EVENT_FLAG_USER, "JabberEvent", "Account: %s\r\nPacket: %s\r\n", client->name, xmpp);
00869 
00870    if (client->debug) {
00871       if (is_incoming)
00872          ast_verbose("\nJABBER: %s INCOMING: %s\n", client->name, xmpp);
00873       else {
00874          if( strlen(xmpp) == 1) {
00875             if(option_debug > 2  && xmpp[0] == ' ') {
00876                ast_verbose("\nJABBER: Keep alive packet\n");
00877             }
00878          } else
00879             ast_verbose("\nJABBER: %s OUTGOING: %s\n", client->name, xmpp);
00880       }
00881 
00882    }
00883    ASTOBJ_UNREF(client, aji_client_destroy);
00884 }

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

02147 {
02148    int res = 0;
02149    iks *removeiq = iks_new("iq");
02150    iks *removequery = iks_new("query");
02151    iks *removeitem = iks_new("item");
02152    iks *send = iks_make_iq(IKS_TYPE_GET, "http://jabber.org/protocol/disco#items");
02153    if (!client || !removeiq || !removequery || !removeitem || !send) {
02154       ast_log(LOG_ERROR, "Out of memory.\n");
02155       goto safeout;
02156    }
02157 
02158    iks_insert_node(removeiq, removequery);
02159    iks_insert_node(removequery, removeitem);
02160    ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02161       ASTOBJ_RDLOCK(iterator);
02162       /* For an aji_buddy, both AUTOPRUNE and AUTOREGISTER will never
02163        * be called at the same time */
02164       if (ast_test_flag(&iterator->flags, AJI_AUTOPRUNE)) { /* If autoprune is set on jabber.conf */
02165          res = ast_aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBE, iterator->name,
02166                          "GoodBye. Your status is no longer needed by Asterisk the Open Source PBX"
02167                          " so I am no longer subscribing to your presence.\n"));
02168          res = ast_aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBED, iterator->name,
02169                          "GoodBye.  You are no longer in the Asterisk config file so I am removing"
02170                          " your access to my presence.\n"));
02171          iks_insert_attrib(removeiq, "from", client->jid->full); 
02172          iks_insert_attrib(removeiq, "type", "set"); 
02173          iks_insert_attrib(removequery, "xmlns", "jabber:iq:roster");
02174          iks_insert_attrib(removeitem, "jid", iterator->name);
02175          iks_insert_attrib(removeitem, "subscription", "remove");
02176          res = ast_aji_send(client, removeiq);
02177       } else if (ast_test_flag(&iterator->flags, AJI_AUTOREGISTER)) {
02178          res = ast_aji_send(client, iks_make_s10n(IKS_TYPE_SUBSCRIBE, iterator->name, 
02179                          "Greetings! I am the Asterisk Open Source PBX and I want to subscribe to your presence\n"));
02180          ast_clear_flag(&iterator->flags, AJI_AUTOREGISTER);
02181       }
02182       ASTOBJ_UNLOCK(iterator);
02183    });
02184 
02185  safeout:
02186    iks_delete(removeiq);
02187    iks_delete(removequery);
02188    iks_delete(removeitem);
02189    iks_delete(send);
02190    
02191    ASTOBJ_CONTAINER_PRUNE_MARKED(&client->buddies, aji_buddy_destroy);
02192 }

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

02284 {
02285    int res = 0;
02286 
02287    if (client->state)
02288       client->state = AJI_DISCONNECTED;
02289    client->timeout=50;
02290    if (client->p)
02291       iks_parser_reset(client->p);
02292    if (client->authorized)
02293       client->authorized = 0;
02294 
02295    res = aji_initialize(client);
02296 
02297    return res;
02298 }

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

00722 {
00723    int len, ret;
00724    char buf[NET_IO_BUF_SIZE - 1];
00725    char newbuf[NET_IO_BUF_SIZE - 1];
00726    int pos = 0;
00727    int newbufpos = 0;
00728    unsigned char c;
00729 
00730    memset(buf, 0, sizeof(buf));
00731    memset(newbuf, 0, sizeof(newbuf));
00732 
00733    while (1) {
00734       len = aji_io_recv(client, buf, NET_IO_BUF_SIZE - 2, timeout);
00735       if (len < 0) return IKS_NET_RWERR;
00736       if (len == 0) return IKS_NET_EXPIRED;
00737       buf[len] = '\0';
00738 
00739       /* our iksemel parser won't work as expected if we feed
00740          it with XML packets that contain multiple whitespace 
00741          characters between tags */
00742       while (pos < len) {
00743          c = buf[pos];
00744          /* if we stumble on the ending tag character,
00745             we skip any whitespace that follows it*/
00746          if (c == '>') {
00747             while (isspace(buf[pos+1])) {
00748                pos++;
00749             }
00750          }
00751          newbuf[newbufpos] = c;
00752          newbufpos ++;
00753          pos++;
00754       }
00755       pos = 0;
00756       newbufpos = 0;
00757 
00758       /* Log the message here, because iksemel's logHook is 
00759          unaccessible */
00760       aji_log_hook(client, buf, len, 1);
00761 
00762       /* let iksemel deal with the string length, 
00763          and reset our buffer */
00764       ret = iks_parse(client->p, newbuf, 0, 0);
00765       memset(newbuf, 0, sizeof(newbuf));
00766 
00767       switch (ret) {
00768       case IKS_NOMEM:
00769          ast_log(LOG_WARNING, "Parsing failure: Out of memory.\n");
00770          break;
00771       case IKS_BADXML:
00772          ast_log(LOG_WARNING, "Parsing failure: Invalid XML.\n");
00773          break;
00774       case IKS_HOOK:
00775          ast_log(LOG_WARNING, "Parsing failure: Hook returned an error.\n");
00776          break;
00777       }
00778       if (ret != IKS_OK) {
00779          return ret;
00780       }
00781       ast_debug(3, "XML parsing successful\n"); 
00782    }
00783    return IKS_OK;
00784 }

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

receive message loop.

Parameters:
data void
Returns:
void.

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

01986 {
01987    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01988    int res = IKS_HOOK;
01989 
01990    while(res != IKS_OK) {
01991       ast_debug(3, "JABBER: Connecting.\n");
01992       res = aji_reconnect(client);
01993       sleep(4);
01994    }
01995 
01996    do {
01997       if (res == IKS_NET_RWERR || client->timeout == 0) {
01998          while(res != IKS_OK) {
01999             ast_debug(3, "JABBER: reconnecting.\n");
02000             res = aji_reconnect(client);
02001             sleep(4);
02002          }
02003       }
02004 
02005       res = aji_recv(client, 1);
02006       
02007       if (client->state == AJI_DISCONNECTING) {
02008          ast_debug(2, "Ending our Jabber client's thread due to a disconnect\n");
02009          pthread_exit(NULL);
02010       }
02011 
02012       /* Decrease timeout if no data received */
02013       if (res == IKS_NET_EXPIRED)
02014          client->timeout--;
02015 
02016       if (res == IKS_HOOK) 
02017          ast_log(LOG_WARNING, "JABBER: Got hook event.\n");
02018       else if (res == IKS_NET_TLSFAIL)
02019          ast_log(LOG_ERROR, "JABBER:  Failure in TLS.\n");
02020       else if (client->timeout == 0 && client->state == AJI_CONNECTED) {
02021          res = client->keepalive ? aji_send_raw(client, " ") : IKS_OK;
02022          if(res == IKS_OK)
02023             client->timeout = 50;
02024          else
02025             ast_log(LOG_WARNING, "JABBER:  Network Timeout\n");
02026       } else if (res == IKS_NET_RWERR)
02027          ast_log(LOG_WARNING, "JABBER: socket read error\n");
02028    } while (client);
02029    ASTOBJ_UNREF(client, aji_client_destroy);
02030    return 0;
02031 }

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

Unknown.

Parameters:
data void
pak ikspak
Returns:
IKS_FILTER_EAT.

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

01145 {
01146    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01147    iks *iq = NULL, *presence = NULL, *x = NULL;
01148 
01149    iq = iks_new("iq");
01150    presence = iks_new("presence");
01151    x = iks_new("x");
01152    if (client && iq && presence && x) {
01153       if (!iks_find(pak->query, "remove")) {
01154          iks_insert_attrib(iq, "from", client->jid->full);
01155          iks_insert_attrib(iq, "to", pak->from->full);
01156          iks_insert_attrib(iq, "id", pak->id);
01157          iks_insert_attrib(iq, "type", "result");
01158          ast_aji_send(client, iq);
01159 
01160          iks_insert_attrib(presence, "from", client->jid->full);
01161          iks_insert_attrib(presence, "to", pak->from->partial);
01162          iks_insert_attrib(presence, "id", client->mid);
01163          ast_aji_increment_mid(client->mid);
01164          iks_insert_attrib(presence, "type", "subscribe");
01165          iks_insert_attrib(x, "xmlns", "vcard-temp:x:update");
01166          iks_insert_node(presence, x);
01167          ast_aji_send(client, presence); 
01168       }
01169    } else {
01170       ast_log(LOG_ERROR, "Out of memory.\n");
01171    }
01172 
01173 
01174    iks_delete(iq);
01175    iks_delete(presence);
01176    iks_delete(x);
01177    
01178    ASTOBJ_UNREF(client, aji_client_destroy);
01179    return IKS_FILTER_EAT;
01180 }

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

01188 {
01189    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01190    struct aji_buddy *buddy = NULL; 
01191    char *node = NULL;
01192    iks *iq = NULL, *query = NULL;
01193 
01194    client = (struct aji_client *) data;
01195 
01196    buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01197    if (!buddy) {
01198       iks  *error = NULL, *notacceptable = NULL;
01199 
01200       ast_log(LOG_ERROR, "Someone.... %s tried to register but they aren't allowed\n", pak->from->partial);
01201       iq = iks_new("iq");
01202       query = iks_new("query");
01203       error = iks_new("error");
01204       notacceptable = iks_new("not-acceptable");
01205       if(iq && query && error && notacceptable) {
01206          iks_insert_attrib(iq, "type", "error");
01207          iks_insert_attrib(iq, "from", client->user);
01208          iks_insert_attrib(iq, "to", pak->from->full);
01209          iks_insert_attrib(iq, "id", pak->id);
01210          iks_insert_attrib(query, "xmlns", "jabber:iq:register");
01211          iks_insert_attrib(error, "code" , "406");
01212          iks_insert_attrib(error, "type", "modify");
01213          iks_insert_attrib(notacceptable, "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas");
01214          iks_insert_node(iq, query);
01215          iks_insert_node(iq, error);
01216          iks_insert_node(error, notacceptable);
01217          ast_aji_send(client, iq);
01218       } else {
01219          ast_log(LOG_ERROR, "Out of memory.\n");
01220       }
01221 
01222       iks_delete(error);
01223       iks_delete(notacceptable);
01224    } else   if (!(node = iks_find_attrib(pak->query, "node"))) {
01225       iks *instructions = NULL;
01226       char *explain = "Welcome to Asterisk - the Open Source PBX.\n";
01227       iq = iks_new("iq");
01228       query = iks_new("query");
01229       instructions = iks_new("instructions");
01230       if (iq && query && instructions && client) {
01231          iks_insert_attrib(iq, "from", client->user);
01232          iks_insert_attrib(iq, "to", pak->from->full);
01233          iks_insert_attrib(iq, "id", pak->id);
01234          iks_insert_attrib(iq, "type", "result");
01235          iks_insert_attrib(query, "xmlns", "jabber:iq:register");
01236          iks_insert_cdata(instructions, explain, 0);
01237          iks_insert_node(iq, query);
01238          iks_insert_node(query, instructions);
01239          ast_aji_send(client, iq);
01240       } else {
01241          ast_log(LOG_ERROR, "Out of memory.\n");
01242       }
01243 
01244       iks_delete(instructions);
01245    }
01246    iks_delete(iq);
01247    iks_delete(query);
01248    ASTOBJ_UNREF(client, aji_client_destroy);
01249    return IKS_FILTER_EAT;
01250 }

static int aji_reload ( int  reload  )  [static]

Reload the jabber module.

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

03036 {
03037    int res;
03038 
03039    ASTOBJ_CONTAINER_MARKALL(&clients);
03040    if (!(res = aji_load_config(reload))) {
03041       ast_log(LOG_ERROR, "JABBER: Failed to load config.\n");
03042       return 0;
03043    } else if (res == -1)
03044       return 1;
03045 
03046    ASTOBJ_CONTAINER_PRUNE_MARKED(&clients, aji_client_destroy);
03047    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
03048       ASTOBJ_RDLOCK(iterator);
03049       if(iterator->state == AJI_DISCONNECTED) {
03050          if (!iterator->thread)
03051             ast_pthread_create_background(&iterator->thread, NULL, aji_recv_loop, iterator);
03052       } else if (iterator->state == AJI_CONNECTING)
03053          aji_get_roster(iterator);
03054       ASTOBJ_UNLOCK(iterator);
03055    });
03056    
03057    return 1;
03058 }

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

Dial plan function to send a message.

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

Definition at line 548 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_strlen_zero(), LOG_ERROR, LOG_WARNING, and s.

Referenced by load_module().

00549 {
00550    struct aji_client *client = NULL;
00551    char *s;
00552    AST_DECLARE_APP_ARGS(args,
00553       AST_APP_ARG(sender);
00554       AST_APP_ARG(recipient);
00555       AST_APP_ARG(message);
00556    );
00557 
00558    if (!data) {
00559       ast_log(LOG_ERROR, "Usage:  JabberSend(<sender>,<recipient>,<message>)\n");
00560       return 0;
00561    }
00562    s = ast_strdupa(data);
00563 
00564    AST_STANDARD_APP_ARGS(args, s);
00565    if (args.argc < 3) {
00566       ast_log(LOG_ERROR, "JabberSend requires 3 arguments: '%s'\n", (char *) data);
00567       return -1;
00568    }
00569 
00570    if (!(client = ast_aji_get_client(args.sender))) {
00571       ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
00572       return -1;
00573    }
00574    if (strchr(args.recipient, '@') && !ast_strlen_zero(args.message))
00575       ast_aji_send_chat(client, args.recipient, args.message);
00576    return 0;
00577 }

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

00793 {
00794    char *msg;
00795    int len, err;
00796 
00797    len = 91 + strlen(client->name_space) + 6 + strlen(to) + 16 + 1;
00798    msg = iks_malloc(len);
00799    if (!msg)
00800       return IKS_NOMEM;
00801    sprintf(msg, "<?xml version='1.0'?>"
00802       "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='"
00803       "%s' to='%s' version='1.0'>", client->name_space, to);
00804    err = aji_send_raw(client, msg);
00805    iks_free(msg);
00806    if (err != IKS_OK)
00807       return err;
00808 
00809    return IKS_OK;
00810 }

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

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

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

00832 {
00833    int ret;
00834 #ifdef HAVE_OPENSSL
00835    int len = strlen(xmlstr);
00836 
00837    if (aji_is_secure(client)) {
00838       ret = SSL_write(client->ssl_session, xmlstr, len);
00839       if (ret) {
00840          /* Log the message here, because iksemel's logHook is 
00841             unaccessible */
00842          aji_log_hook(client, xmlstr, len, 0);
00843          return IKS_OK;
00844       }
00845    }
00846 #endif
00847    /* If needed, data will be sent unencrypted, and logHook will 
00848       be called inside iks_send_raw */
00849    ret = iks_send_raw(client->p, xmlstr);
00850    if (ret != IKS_OK)
00851       return ret; 
00852 
00853    return IKS_OK;
00854 }

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

02409 {
02410    int res = 0;
02411    iks *presence = iks_make_pres(level, desc);
02412    iks *cnode = iks_new("c");
02413    iks *priority = iks_new("priority");
02414    char priorityS[10];
02415 
02416    if (presence && cnode && client && priority) {
02417       if(to)
02418          iks_insert_attrib(presence, "to", to);
02419       if(from)
02420          iks_insert_attrib(presence, "from", from);
02421       snprintf(priorityS, sizeof(priorityS), "%d", client->priority);
02422       iks_insert_cdata(priority, priorityS, strlen(priorityS));
02423       iks_insert_node(presence, priority);
02424       iks_insert_attrib(cnode, "node", "http://www.asterisk.org/xmpp/client/caps");
02425       iks_insert_attrib(cnode, "ver", "asterisk-xmpp");
02426       iks_insert_attrib(cnode, "ext", "voice-v1");
02427       iks_insert_attrib(cnode, "xmlns", "http://jabber.org/protocol/caps");
02428       iks_insert_node(presence, cnode);
02429       res = ast_aji_send(client, presence);
02430    } else
02431       ast_log(LOG_ERROR, "Out of memory.\n");
02432 
02433    iks_delete(cnode);
02434    iks_delete(presence);
02435    iks_delete(priority);
02436 }

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

02550 {
02551    struct aji_resource *resource;
02552    struct aji_client *client;
02553 
02554    switch (cmd) {
02555    case CLI_INIT:
02556       e->command = "jabber show buddies";
02557       e->usage =
02558          "Usage: jabber show buddies\n"
02559          "       Shows buddy lists of our clients\n";
02560       return NULL;
02561    case CLI_GENERATE:
02562       return NULL;
02563    }
02564 
02565    ast_cli(a->fd, "Jabber buddy lists\n");
02566    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02567       ast_cli(a->fd,"Client: %s\n", iterator->user);
02568       client = iterator;
02569       ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02570          ASTOBJ_RDLOCK(iterator);
02571          ast_cli(a->fd,"\tBuddy:\t%s\n", iterator->name);
02572          if (!iterator->resources)
02573             ast_cli(a->fd,"\t\tResource: None\n"); 
02574          for (resource = iterator->resources; resource; resource = resource->next) {
02575             ast_cli(a->fd,"\t\tResource: %s\n", resource->resource);
02576             if(resource->cap) {
02577                ast_cli(a->fd,"\t\t\tnode: %s\n", resource->cap->parent->node);
02578                ast_cli(a->fd,"\t\t\tversion: %s\n", resource->cap->version);
02579                ast_cli(a->fd,"\t\t\tJingle capable: %s\n", resource->cap->jingle ? "yes" : "no");
02580             }
02581             ast_cli(a->fd,"\t\tStatus: %d\n", resource->status);
02582             ast_cli(a->fd,"\t\tPriority: %d\n", resource->priority);
02583          }
02584          ASTOBJ_UNLOCK(iterator);
02585       });
02586       iterator = client;
02587    });
02588    return CLI_SUCCESS;
02589 }

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

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

02505 {
02506    char *status;
02507    int count = 0;
02508    
02509    switch (cmd) {
02510    case CLI_INIT:
02511       e->command = "jabber show connected";
02512       e->usage =
02513          "Usage: jabber show connected\n"
02514          "       Shows state of clients and components\n";
02515       return NULL;
02516    case CLI_GENERATE:
02517       return NULL;
02518    }
02519 
02520    ast_cli(a->fd, "Jabber Users and their status:\n");
02521    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02522       ASTOBJ_RDLOCK(iterator);
02523       count++;
02524       switch (iterator->state) {
02525       case AJI_DISCONNECTED:
02526          status = "Disconnected";
02527          break;
02528       case AJI_CONNECTING:
02529          status = "Connecting";
02530          break;
02531       case AJI_CONNECTED:
02532          status = "Connected";
02533          break;
02534       default:
02535          status = "Unknown";
02536       }
02537       ast_cli(a->fd, "       User: %s     - %s\n", iterator->user, status);
02538       ASTOBJ_UNLOCK(iterator);
02539    });
02540    ast_cli(a->fd, "----\n");
02541    ast_cli(a->fd, "   Number of users: %d\n", count);
02542    return CLI_SUCCESS;
02543 }

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

00896 {
00897    iks *x = NULL;
00898    int len;
00899    char *s;
00900    char *base64;
00901 
00902    /* trigger SASL DIGEST-MD5 only over an unsecured connection.
00903       iks_start_sasl is an iksemel API function and relies on GnuTLS,
00904       whereas we use OpenSSL */
00905    if ((type & IKS_STREAM_SASL_MD5) && !aji_is_secure(client))
00906       return iks_start_sasl(client->p, IKS_SASL_DIGEST_MD5, username, pass); 
00907    if (!(type & IKS_STREAM_SASL_PLAIN)) {
00908       ast_log(LOG_ERROR, "Server does not support SASL PLAIN authentication\n");
00909       return IKS_NET_NOTSUPP;
00910    }
00911 
00912    x = iks_new("auth"); 
00913    if (!x) {
00914       ast_log(LOG_ERROR, "Out of memory.\n");
00915       return IKS_NET_NOTSUPP;
00916    }
00917 
00918    iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_SASL);
00919    len = strlen(username) + strlen(pass) + 3;
00920    s = alloca(len);
00921    base64 = alloca((len + 2) * 4 / 3);
00922    iks_insert_attrib(x, "mechanism", "PLAIN");
00923    snprintf(s, len, "%c%s%c%s", 0, username, 0, pass);
00924 
00925    /* exclude the NULL training byte from the base64 encoding operation
00926       as some XMPP servers will refuse it.
00927       The format for authentication is [authzid]\0authcid\0password
00928       not [authzid]\0authcid\0password\0 */
00929    ast_base64encode(base64, (const unsigned char *) s, len - 1, (len + 2) * 4 / 3);
00930    iks_insert_cdata(x, base64, 0);
00931    ast_aji_send(client, x);
00932    iks_delete(x);
00933 
00934    return IKS_OK;
00935 }

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

References aji_client::p, aji_client::stream_flags, and TRY_SECURE.

Referenced by aji_act_hook().

00600 {
00601    int ret;
00602 
00603    /* This is sent not encrypted */
00604    ret = iks_send_raw(client->p, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
00605    if (ret)
00606       return ret;
00607 
00608    client->stream_flags |= TRY_SECURE;
00609    return IKS_OK;
00610 }

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 432 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, pbx_builtin_setvar_helper(), aji_resource::resource, aji_buddy::resources, s, aji_resource::status, and status.

Referenced by load_module().

00433 {
00434    struct aji_client *client = NULL;
00435    struct aji_buddy *buddy = NULL;
00436    struct aji_resource *r = NULL;
00437    char *s = NULL;
00438    int stat = 7;
00439    char status[2];
00440    static int deprecation_warning = 0;
00441    AST_DECLARE_APP_ARGS(args,
00442       AST_APP_ARG(sender);
00443       AST_APP_ARG(jid);
00444       AST_APP_ARG(variable);
00445    );
00446    AST_DECLARE_APP_ARGS(jid,
00447       AST_APP_ARG(screenname);
00448       AST_APP_ARG(resource);
00449    );
00450 
00451    if (deprecation_warning++ % 10 == 0)
00452       ast_log(LOG_WARNING, "JabberStatus is deprecated.  Please use the JABBER_STATUS dialplan function in the future.\n");
00453 
00454    if (!data) {
00455       ast_log(LOG_ERROR, "Usage: JabberStatus(<sender>,<jid>[/<resource>],<varname>\n");
00456       return 0;
00457    }
00458    s = ast_strdupa(data);
00459    AST_STANDARD_APP_ARGS(args, s);
00460 
00461    if (args.argc != 3) {
00462       ast_log(LOG_ERROR, "JabberStatus() requires 3 arguments.\n");
00463       return -1;
00464    }
00465 
00466    AST_NONSTANDARD_APP_ARGS(jid, args.jid, '/');
00467 
00468    if (!(client = ast_aji_get_client(args.sender))) {
00469       ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
00470       return -1;
00471    }
00472    buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, jid.screenname);
00473    if (!buddy) {
00474       ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
00475       return -1;
00476    }
00477    r = aji_find_resource(buddy, jid.resource);
00478    if (!r && buddy->resources) 
00479       r = buddy->resources;
00480    if (!r)
00481       ast_log(LOG_NOTICE, "Resource '%s' of buddy '%s' was not found\n", jid.resource, jid.screenname);
00482    else
00483       stat = r->status;
00484    snprintf(status, sizeof(status), "%d", stat);
00485    pbx_builtin_setvar_helper(chan, args.variable, status);
00486    return 0;
00487 }

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

02596 {
02597    struct aji_client *client;
02598    struct aji_resource *resource;
02599    const char *name = "asterisk";
02600    struct aji_message *tmp;
02601 
02602    switch (cmd) {
02603    case CLI_INIT:
02604       e->command = "jabber test";
02605       e->usage =
02606          "Usage: jabber test [client]\n"
02607          "       Sends test message for debugging purposes.  A specific client\n"
02608          "       as configured in jabber.conf can be optionally specified.\n";
02609       return NULL;
02610    case CLI_GENERATE:
02611       return NULL;
02612    }
02613 
02614    if (a->argc > 3)
02615       return CLI_SHOWUSAGE;
02616    else if (a->argc == 3)
02617       name = a->argv[2];
02618 
02619    if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
02620       ast_cli(a->fd, "Unable to find client '%s'!\n", name);
02621       return CLI_FAILURE;
02622    }
02623 
02624    /* XXX Does Matt really want everyone to use his personal address for tests? */ /* XXX yes he does */
02625    ast_aji_send_chat(client, "mogorman@astjab.org", "blahblah");
02626    ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02627       ASTOBJ_RDLOCK(iterator);
02628       ast_verbose("User: %s\n", iterator->name);
02629       for (resource = iterator->resources; resource; resource = resource->next) {
02630          ast_verbose("Resource: %s\n", resource->resource);
02631          if(resource->cap) {
02632             ast_verbose("   client: %s\n", resource->cap->parent->node);
02633             ast_verbose("   version: %s\n", resource->cap->version);
02634             ast_verbose("   Jingle Capable: %d\n", resource->cap->jingle);
02635          }
02636          ast_verbose("  Priority: %d\n", resource->priority);
02637          ast_verbose("  Status: %d\n", resource->status); 
02638          ast_verbose("  Message: %s\n", S_OR(resource->description,"")); 
02639       }
02640       ASTOBJ_UNLOCK(iterator);
02641    });
02642    ast_verbose("\nOooh a working message stack!\n");
02643    AST_LIST_LOCK(&client->messages);
02644    AST_LIST_TRAVERSE(&client->messages, tmp, list) {
02645       ast_verbose("  Message from: %s with id %s @ %s %s\n",tmp->from, S_OR(tmp->id,""), ctime(&tmp->arrived), S_OR(tmp->message, ""));
02646    }
02647    AST_LIST_UNLOCK(&client->messages);
02648    ASTOBJ_UNREF(client, aji_client_destroy);
02649 
02650    return CLI_SUCCESS;
02651 }

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

References aji_send_header(), ast_debug, aji_client::jid, aji_client::p, SECURE, aji_client::ssl_context, aji_client::ssl_method, aji_client::ssl_session, aji_client::stream_flags, and TRY_SECURE.

Referenced by aji_act_hook().

00618 {
00619    int ret;
00620    int sock;
00621    
00622    ast_debug(1, "Starting TLS handshake\n"); 
00623 
00624    /* Choose an SSL/TLS protocol version, create SSL_CTX */
00625    client->ssl_method = SSLv3_method();
00626    client->ssl_context = SSL_CTX_new(client->ssl_method);                
00627    if (!client->ssl_context)
00628       return IKS_NET_TLSFAIL;
00629 
00630    /* Create new SSL session */
00631    client->ssl_session = SSL_new(client->ssl_context);
00632    if (!client->ssl_session)
00633       return IKS_NET_TLSFAIL;
00634 
00635    /* Enforce TLS on our XMPP connection */
00636    sock = iks_fd(client->p);
00637    ret = SSL_set_fd(client->ssl_session, sock);
00638    if (!ret)
00639       return IKS_NET_TLSFAIL;
00640 
00641    /* Perform SSL handshake */
00642    ret = SSL_connect(client->ssl_session);
00643    if (!ret)
00644       return IKS_NET_TLSFAIL;
00645 
00646    client->stream_flags &= (~TRY_SECURE);
00647    client->stream_flags |= SECURE;
00648 
00649    /* Sent over the established TLS connection */
00650    ret = aji_send_header(client, client->jid->server);
00651    if (ret != IKS_OK)
00652       return IKS_NET_TLSFAIL;
00653 
00654    ast_debug(1, "TLS started with server\n"); 
00655 
00656    return IKS_OK;
00657 }

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

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

01895 {
01896    int res = 0;
01897    iks *iq = NULL;
01898    iq = iks_new("iq");
01899 
01900    if (iq && client) {
01901       iks_insert_attrib(iq, "type", "get");
01902       iks_insert_attrib(iq, "to", server);
01903       iks_insert_attrib(iq, "id", client->mid);
01904       ast_aji_increment_mid(client->mid);
01905       ast_aji_send(client, iq);
01906    } else 
01907       ast_log(LOG_ERROR, "Out of memory.\n");
01908 
01909    iks_delete(iq);
01910 
01911    return res;
01912 }

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

References aji_client_destroy(), ast_verb, ASTOBJ_UNREF, aji_client::p, SECURE, aji_client::ssl_context, aji_client::ssl_session, and aji_client::stream_flags.

Referenced by unload_module().

02381 {
02382    if (client) {
02383       ast_verb(4, "JABBER: Disconnecting\n");
02384 #ifdef HAVE_OPENSSL
02385       if (client->stream_flags & SECURE) {
02386          SSL_shutdown(client->ssl_session);
02387          SSL_CTX_free(client->ssl_context);
02388          SSL_free(client->ssl_session);
02389       }
02390 #endif
02391       iks_disconnect(client->p);
02392       iks_parser_delete(client->p);
02393       ASTOBJ_UNREF(client, aji_client_destroy);
02394    }
02395 
02396    return 1;
02397 }

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

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

Parameters:
name label or JID
Returns:
aji_client.

Definition at line 2954 of file res_jabber.c.

References ASTOBJ_CONTAINER_FIND, ASTOBJ_CONTAINER_TRAVERSE, and clients.

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

02955 {
02956    struct aji_client *client = NULL;
02957    char *aux = NULL;
02958 
02959    client = ASTOBJ_CONTAINER_FIND(&clients, name);
02960    if (!client && strchr(name, '@')) {
02961       ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02962          aux = ast_strdupa(iterator->user);
02963          if (strchr(aux, '/')) {
02964             /* strip resource for comparison */
02965             aux = strsep(&aux, "/");
02966          }
02967          if (!strncasecmp(aux, name, strlen(aux))) {
02968             client = iterator;
02969          }           
02970       });
02971    }
02972 
02973    return client;
02974 }

struct aji_client_container* ast_aji_get_clients ( void   )  [read]

Definition at line 2976 of file res_jabber.c.

References clients.

Referenced by gtalk_load_config(), and jingle_load_config().

02977 {
02978    return &clients;
02979 }

void ast_aji_increment_mid ( char *  mid  ) 

increments the mid field for messages and other events.

Parameters:
mid char.
Returns:
void.

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

02039 {
02040    int i = 0;
02041 
02042    for (i = strlen(mid) - 1; i >= 0; i--) {
02043       if (mid[i] != 'z') {
02044          mid[i] = mid[i] + 1;
02045          i = 0;
02046       } else
02047          mid[i] = 'a';
02048    }
02049 }

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

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

01952 {
01953    int res = 0;
01954    iks *invite, *body, *namespace;
01955 
01956    invite = iks_new("message");
01957    body = iks_new("body");
01958    namespace = iks_new("x");
01959    if (client && invite && body && namespace) {
01960       iks_insert_attrib(invite, "to", user);
01961       iks_insert_attrib(invite, "id", client->mid);
01962       ast_aji_increment_mid(client->mid);
01963       iks_insert_cdata(body, message, 0);
01964       iks_insert_attrib(namespace, "xmlns", "jabber:x:conference");
01965       iks_insert_attrib(namespace, "jid", room);
01966       iks_insert_node(invite, body);
01967       iks_insert_node(invite, namespace);
01968       res = ast_aji_send(client, invite);
01969    } else 
01970       ast_log(LOG_ERROR, "Out of memory.\n");
01971 
01972    iks_delete(body);
01973    iks_delete(namespace);
01974    iks_delete(invite);
01975    
01976    return res;
01977 }

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

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

01921 {
01922    int res = 0;
01923    iks *presence = NULL, *priority = NULL;
01924    presence = iks_new("presence");
01925    priority = iks_new("priority");
01926    if (presence && priority && client) {
01927       iks_insert_cdata(priority, "0", 1);
01928       iks_insert_attrib(presence, "to", room);
01929       iks_insert_node(presence, priority);
01930       res = ast_aji_send(client, presence);
01931       iks_insert_cdata(priority, "5", 1);
01932       iks_insert_attrib(presence, "to", room);
01933       res = ast_aji_send(client, presence);
01934    } else 
01935       ast_log(LOG_ERROR, "Out of memory.\n");
01936    
01937    iks_delete(presence);
01938    iks_delete(priority);
01939    
01940    return res;
01941 }

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

sends messages.

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

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

01868 {
01869    int res = 0;
01870    iks *message_packet = NULL;
01871    if (client->state == AJI_CONNECTED) {
01872       message_packet = iks_make_msg(IKS_TYPE_CHAT, address, message);
01873       if (message_packet) {
01874          iks_insert_attrib(message_packet, "from", client->jid->full);
01875          res = ast_aji_send(client, message_packet);
01876       } else {
01877          ast_log(LOG_ERROR, "Out of memory.\n");
01878       }
01879 
01880       iks_delete(message_packet);
01881    } else
01882       ast_log(LOG_WARNING, "JABBER: Not connected can't send\n");
01883    return 1;
01884 }

static int gtalk_yuck ( iks *  node  )  [static]

Jabber GTalk function.

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

Definition at line 390 of file res_jabber.c.

Referenced by aji_handle_presence().

00391 {
00392    if (iks_find_with_attrib(node, "c", "node", "http://www.google.com/xmpp/client/caps"))
00393       return 1;
00394    return 0;
00395 }

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

References ast_sha1_hash(), and buf.

Referenced by aji_act_hook().

00405 {
00406    iks *x, *y;
00407    x = iks_new("iq");
00408    iks_insert_attrib(x, "type", "set");
00409    y = iks_insert(x, "query");
00410    iks_insert_attrib(y, "xmlns", IKS_NS_AUTH);
00411    iks_insert_cdata(iks_insert(y, "username"), id->user, 0);
00412    iks_insert_cdata(iks_insert(y, "resource"), id->resource, 0);
00413    if (sid) {
00414       char buf[41];
00415       char sidpass[100];
00416       snprintf(sidpass, sizeof(sidpass), "%s%s", sid, pass);
00417       ast_sha1_hash(buf, sidpass);
00418       iks_insert_cdata(iks_insert(y, "digest"), buf, 0);
00419    } else {
00420       iks_insert_cdata(iks_insert(y, "password"), pass, 0);
00421    }
00422    return x;
00423 }

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

Send a Jabber Message via call from the Manager.

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

Definition at line 2994 of file res_jabber.c.

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

Referenced by load_module().

02995 {
02996    struct aji_client *client = NULL;
02997    const char *id = astman_get_header(m,"ActionID");
02998    const char *jabber = astman_get_header(m,"Jabber");
02999    const char *screenname = astman_get_header(m,"ScreenName");
03000    const char *message = astman_get_header(m,"Message");
03001 
03002    if (ast_strlen_zero(jabber)) {
03003       astman_send_error(s, m, "No transport specified");
03004       return 0;
03005    }
03006    if (ast_strlen_zero(screenname)) {
03007       astman_send_error(s, m, "No ScreenName specified");
03008       return 0;
03009    }
03010    if (ast_strlen_zero(message)) {
03011       astman_send_error(s, m, "No Message specified");
03012       return 0;
03013    }
03014 
03015    astman_send_ack(s, m, "Attempting to send Jabber Message");
03016    client = ast_aji_get_client(jabber);
03017    if (!client) {
03018       astman_send_error(s, m, "Could not find Sender");
03019       return 0;
03020    }
03021    if (strchr(screenname, '@') && message) {
03022       ast_aji_send_chat(client, screenname, message);
03023       astman_append(s, "Response: Success\r\n");
03024    } else {
03025       astman_append(s, "Response: Error\r\n");
03026    }
03027    if (!ast_strlen_zero(id)) {
03028       astman_append(s, "ActionID: %s\r\n",id);
03029    }
03030    astman_append(s, "\r\n");
03031    return 0;
03032 }

static int reload ( void   )  [static]

Wrapper for aji_reload.

Definition at line 3101 of file res_jabber.c.

References aji_reload().

03102 {
03103    aji_reload(1);
03104    return 0;
03105 }

static int unload_module ( void   )  [static]

Unload the jabber module.

Definition at line 3061 of file res_jabber.c.

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

03062 {
03063 
03064    ast_cli_unregister_multiple(aji_cli, ARRAY_LEN(aji_cli));
03065    ast_unregister_application(app_ajisend);
03066    ast_unregister_application(app_ajistatus);
03067    ast_manager_unregister("JabberSend");
03068    ast_custom_function_unregister(&jabberstatus_function);
03069    
03070    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
03071       ASTOBJ_RDLOCK(iterator);
03072       ast_debug(3, "JABBER: Releasing and disconnecting client: %s\n", iterator->name);
03073       iterator->state = AJI_DISCONNECTING;
03074       ast_aji_disconnect(iterator);
03075       pthread_join(iterator->thread, NULL);
03076       ASTOBJ_UNLOCK(iterator);
03077    });
03078 
03079    ASTOBJ_CONTAINER_DESTROYALL(&clients, aji_client_destroy);
03080    ASTOBJ_CONTAINER_DESTROY(&clients);
03081    return 0;
03082 }


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

Definition at line 3111 of file res_jabber.c.

struct ast_cli_entry aji_cli[] [static]

Definition at line 234 of file res_jabber.c.

char* app_ajisend = "JabberSend" [static]

Definition at line 242 of file res_jabber.c.

char* app_ajistatus = "JabberStatus" [static]

Definition at line 244 of file res_jabber.c.

Definition at line 3111 of file res_jabber.c.

Definition at line 247 of file res_jabber.c.

Referenced by ast_request().

struct ast_flags globalflags = { AJI_AUTOREGISTER } [static]

Global flags, initialized to default values.

Definition at line 250 of file res_jabber.c.

Initial value:
 {
   .name = "JABBER_STATUS",
   .read = acf_jabberstatus_read,
}

Definition at line 537 of file res_jabber.c.

char mandescr_jabber_send[] [static]

Definition at line 2981 of file res_jabber.c.


Generated by  doxygen 1.6.2