Wed Oct 28 13:33:29 2009

Asterisk developer's documentation


res_jabber.c File Reference

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

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

Include dependency graph for res_jabber.c:

Go to the source code of this file.

Defines

#define JABBER_CONFIG   "jabber.conf"

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int acf_jabberreceive_read (struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
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)
static void aji_buddy_destroy (struct aji_buddy *obj)
static int aji_client_connect (void *data, ikspak *pak)
static void aji_client_destroy (struct aji_client *obj)
static int aji_client_info_handler (void *data, ikspak *pak)
static int aji_create_buddy (char *label, struct aji_client *client)
static int aji_create_client (char *label, struct ast_variable *var, int debug)
static int aji_dinfo_handler (void *data, ikspak *pak)
static int aji_ditems_handler (void *data, ikspak *pak)
static char * aji_do_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * aji_do_set_debug (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int aji_filter_roster (void *data, ikspak *pak)
static struct aji_resourceaji_find_resource (struct aji_buddy *buddy, char *name)
static struct aji_versionaji_find_version (char *node, char *version, ikspak *pak)
static int aji_get_roster (struct aji_client *client)
static void aji_handle_iq (struct aji_client *client, iks *node)
static void aji_handle_message (struct aji_client *client, ikspak *pak)
static void aji_handle_presence (struct aji_client *client, ikspak *pak)
static void aji_handle_subscribe (struct aji_client *client, ikspak *pak)
static int aji_initialize (struct aji_client *client)
static int aji_io_recv (struct aji_client *client, char *buffer, size_t buf_len, int timeout)
static int aji_is_secure (struct aji_client *client)
static int aji_load_config (int reload)
static void aji_log_hook (void *data, const char *xmpp, size_t size, int is_incoming)
static void aji_message_destroy (struct aji_message *obj)
static void aji_pruneregister (struct aji_client *client)
static int aji_reconnect (struct aji_client *client)
static int aji_recv (struct aji_client *client, int timeout)
static void * aji_recv_loop (void *data)
static int aji_register_approve_handler (void *data, ikspak *pak)
static int aji_register_query_handler (void *data, ikspak *pak)
static int aji_reload (int reload)
static int aji_send_exec (struct ast_channel *chan, const char *data)
static int aji_send_header (struct aji_client *client, const char *to)
static int aji_send_raw (struct aji_client *client, const char *xmlstr)
static void aji_set_presence (struct aji_client *client, char *to, char *from, int level, char *desc)
static char * aji_show_buddies (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * aji_show_clients (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int aji_start_sasl (struct aji_client *client, enum ikssasltype type, char *username, char *pass)
static int aji_status_exec (struct ast_channel *chan, const char *data)
static char * aji_test (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
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 delete_old_messages (struct aji_client *client, char *from)
static int delete_old_messages_all (struct aji_client *client)
static int gtalk_yuck (iks *node)
static iks * jabber_make_auth (iksid *id, const char *pass, const char *sid)
static int load_module (void)
static int manager_jabber_send (struct mansession *s, const struct message *m)
static int reload (void)
static int unload_module (void)

Variables

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


Detailed Description

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

References:

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

Definition in file res_jabber.c.


Define Documentation

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

Referenced by aji_load_config().


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 3552 of file res_jabber.c.

static void __unreg_module ( void   )  [static]

Definition at line 3552 of file res_jabber.c.

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

Definition at line 695 of file res_jabber.c.

References aji_client_destroy(), AJI_MAX_JIDLEN, aji_message_destroy(), aji_message::arrived, ast_aji_get_client(), AST_APP_ARG, ast_autoservice_start(), ast_autoservice_stop(), ast_cond_timedwait(), ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), AST_NONSTANDARD_APP_ARGS, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_tv(), ast_tvadd(), ast_tvdiff_ms(), ast_tvdiff_sec(), ast_tvnow(), ASTOBJ_UNREF, aji_message::from, LOG_NOTICE, LOG_WARNING, aji_message::message, aji_client::message_timeout, aji_client::messages, ast_channel::name, and parse().

00696 {
00697    char *aux = NULL, *parse = NULL;
00698    int timeout;
00699    int jidlen, resourcelen;
00700    struct timeval start;
00701    long diff = 0;
00702    struct aji_client *client = NULL;
00703    int found = 0;
00704    struct aji_message *tmp = NULL;
00705    AST_DECLARE_APP_ARGS(args,
00706          AST_APP_ARG(account);
00707          AST_APP_ARG(jid);
00708          AST_APP_ARG(timeout);
00709          );
00710    AST_DECLARE_APP_ARGS(jid,
00711          AST_APP_ARG(screenname);
00712          AST_APP_ARG(resource);
00713    );
00714 
00715    if (ast_strlen_zero(data)) {
00716       ast_log(LOG_WARNING, "%s requires arguments (account,jid[,timeout])\n", name);
00717       return -1;
00718    }
00719 
00720    parse = ast_strdupa(data);
00721    AST_STANDARD_APP_ARGS(args, parse);
00722 
00723    if (args.argc < 2 || args.argc > 3) {
00724                 ast_log(LOG_WARNING, "%s requires arguments (account,jid[,timeout])\n", name);
00725       return -1;
00726    }
00727 
00728    client = ast_aji_get_client(args.account);
00729    if (!client) {
00730       ast_log(LOG_WARNING, "Could not find client %s, exiting\n", args.account);
00731       return -1;
00732    }
00733 
00734    parse = ast_strdupa(args.jid);
00735    AST_NONSTANDARD_APP_ARGS(jid, parse, '/');
00736    if (jid.argc < 1 || jid.argc > 2 || strlen(args.jid) > AJI_MAX_JIDLEN) {
00737       ast_log(LOG_WARNING, "Invalid JID : %s\n", parse);
00738       ASTOBJ_UNREF(client, aji_client_destroy);
00739       return -1;
00740    }
00741 
00742    if (ast_strlen_zero(args.timeout)) {
00743       timeout = 20;
00744    } else {
00745       sscanf(args.timeout, "%d", &timeout);
00746       if (timeout <= 0) {
00747          ast_log(LOG_WARNING, "Invalid timeout specified: '%s'\n", args.timeout);
00748          ASTOBJ_UNREF(client, aji_client_destroy);
00749          return -1;
00750       }
00751    }
00752 
00753    jidlen = strlen(jid.screenname);
00754    resourcelen = ast_strlen_zero(jid.resource) ? 0 : strlen(jid.resource);
00755 
00756    ast_debug(3, "Waiting for an XMPP message from %s\n", args.jid);
00757 
00758    start = ast_tvnow();
00759 
00760    if (ast_autoservice_start(chan) < 0) {
00761       ast_log(LOG_WARNING, "Cannot start autoservice for channel %s\n", chan->name);
00762       return -1;
00763    }
00764 
00765    /* search the messages list, grab the first message that matches with
00766     * the from JID we're expecting, and remove it from the messages list */
00767    while (diff < timeout) {
00768       struct timespec ts = { 0, };
00769       struct timeval wait;
00770       int res;
00771 
00772                 wait = ast_tvadd(start, ast_tv(timeout, 0));
00773       ts.tv_sec = wait.tv_sec;
00774       ts.tv_nsec = wait.tv_usec * 1000;
00775 
00776       /* wait up to timeout seconds for an incoming message */
00777       ast_mutex_lock(&messagelock);
00778       res = ast_cond_timedwait(&message_received_condition, &messagelock, &ts);
00779       ast_mutex_unlock(&messagelock);
00780       if (res == ETIMEDOUT) {
00781          ast_debug(3, "No message received from %s in %d seconds\n", args.jid, timeout);
00782          break;
00783       };
00784 
00785       AST_LIST_LOCK(&client->messages);
00786       AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, tmp, list) {
00787          if (jid.argc == 1) {
00788             /* no resource provided, compare bare JIDs */
00789             if (strncasecmp(jid.screenname, tmp->from, jidlen)) {
00790                continue;
00791             }
00792          } else {
00793             /* resource appended, compare bare JIDs and resources */
00794             char *resource = strchr(tmp->from, '/');
00795             if (!resource || strlen(resource) == 0) {
00796                ast_log(LOG_WARNING, "Remote JID has no resource : %s\n", tmp->from);
00797                if (strncasecmp(jid.screenname, tmp->from, jidlen)) {
00798                   continue;
00799                }
00800             } else {
00801                resource ++;
00802                if (strncasecmp(jid.screenname, tmp->from, jidlen) || strncmp(jid.resource, resource, resourcelen)) {
00803                   continue;
00804                }
00805             }
00806          }
00807          /* check if the message is not too old */
00808          if (ast_tvdiff_sec(ast_tvnow(), tmp->arrived) >= client->message_timeout) {
00809             ast_debug(3, "Found old message from %s, deleting it\n", tmp->from);
00810             AST_LIST_REMOVE_CURRENT(list);
00811             aji_message_destroy(tmp);
00812             continue;
00813          }
00814          found = 1;
00815          aux = ast_strdupa(tmp->message);
00816          AST_LIST_REMOVE_CURRENT(list);
00817          aji_message_destroy(tmp);
00818          break;
00819       }
00820       AST_LIST_TRAVERSE_SAFE_END;
00821       AST_LIST_UNLOCK(&client->messages);
00822       if (found) {
00823          break;
00824       }
00825 
00826       /* check timeout */
00827       diff = ast_tvdiff_ms(ast_tvnow(), start);
00828    }
00829 
00830    ASTOBJ_UNREF(client, aji_client_destroy);
00831    if (ast_autoservice_stop(chan) < 0) {
00832       ast_log(LOG_WARNING, "Cannot stop autoservice for channel %s\n", chan->name);
00833    }
00834 
00835    /* return if we timed out */
00836    if (!found) {
00837       ast_log(LOG_NOTICE, "Timed out : no message received from %s\n", args.jid);
00838       return -1;
00839    }
00840    ast_copy_string(buf, aux, buflen);
00841 
00842    return 0;
00843 }

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

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

00630 {
00631    struct aji_client *client = NULL;
00632    struct aji_buddy *buddy = NULL;
00633    struct aji_resource *r = NULL;
00634    int stat = 7;
00635    AST_DECLARE_APP_ARGS(args,
00636       AST_APP_ARG(sender);
00637       AST_APP_ARG(jid);
00638    );
00639    AST_DECLARE_APP_ARGS(jid,
00640       AST_APP_ARG(screenname);
00641       AST_APP_ARG(resource);
00642    );
00643 
00644    if (!data) {
00645       ast_log(LOG_ERROR, "Usage: JABBER_STATUS(<sender>,<jid>[/<resource>])\n");
00646       return 0;
00647    }
00648    AST_STANDARD_APP_ARGS(args, data);
00649 
00650    if (args.argc != 2) {
00651       ast_log(LOG_ERROR, "JABBER_STATUS requires 2 arguments: sender and jid.\n");
00652       return -1;
00653    }
00654 
00655    AST_NONSTANDARD_APP_ARGS(jid, args.jid, '/');
00656    if (jid.argc < 1 || jid.argc > 2) {
00657       ast_log(LOG_WARNING, "Wrong JID %s, exiting\n", args.jid);
00658       return -1;
00659    }
00660 
00661    if (!(client = ast_aji_get_client(args.sender))) {
00662       ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
00663       return -1;
00664    }
00665    buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, jid.screenname);
00666    if (!buddy) {
00667       ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
00668       return -1;
00669    }
00670    r = aji_find_resource(buddy, jid.resource);
00671    if (!r && buddy->resources) 
00672       r = buddy->resources;
00673    if (!r)
00674       ast_log(LOG_NOTICE, "Resource %s of buddy %s was not found.\n", jid.resource, jid.screenname);
00675    else
00676       stat = r->status;
00677    snprintf(buf, buflen, "%d", stat);
00678    return 0;
00679 }

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

Definition at line 1329 of file res_jabber.c.

References aji_client_connect(), aji_client_destroy(), AJI_CONNECTED, AJI_CONNECTING, AJI_DISCONNECTED, AJI_DISCONNECTING, aji_handle_iq(), aji_handle_message(), aji_handle_presence(), aji_handle_subscribe(), aji_is_secure(), aji_recv(), aji_send_header(), aji_send_raw(), aji_start_sasl(), asprintf, ast_aji_increment_mid(), ast_aji_send(), ast_debug, ast_free, ast_log(), ast_sha1_hash(), ASTOBJ_REF, ASTOBJ_UNREF, aji_client::authorized, aji_client::component, aji_client::f, jabber_make_auth(), aji_client::jid, LOG_ERROR, LOG_WARNING, aji_client::mid, aji_client::password, secret, aji_client::state, aji_client::usesasl, and aji_client::usetls.

01330 {
01331    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01332    ikspak *pak = NULL;
01333    iks *auth = NULL;
01334    int features = 0;
01335 
01336    if (!node) {
01337       ast_log(LOG_ERROR, "aji_act_hook was called with out a packet\n"); /* most likely cause type is IKS_NODE_ERROR lost connection */
01338       ASTOBJ_UNREF(client, aji_client_destroy);
01339       return IKS_HOOK;
01340    }
01341 
01342    if (client->state == AJI_DISCONNECTING) {
01343       ASTOBJ_UNREF(client, aji_client_destroy);
01344       return IKS_HOOK;
01345    }
01346 
01347    pak = iks_packet(node);
01348 
01349    if (!client->component) { /*client */
01350       switch (type) {
01351       case IKS_NODE_START:
01352          if (client->usetls && !aji_is_secure(client)) {
01353 #ifndef HAVE_OPENSSL
01354             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");
01355             ASTOBJ_UNREF(client, aji_client_destroy);
01356             return IKS_HOOK;
01357 #else
01358             if (aji_start_tls(client) == IKS_NET_TLSFAIL) {
01359                ast_log(LOG_ERROR, "Could not start TLS\n");
01360                ASTOBJ_UNREF(client, aji_client_destroy);
01361                return IKS_HOOK;     
01362             }
01363 #endif
01364             break;
01365          }
01366          if (!client->usesasl) {
01367             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);
01368             auth = jabber_make_auth(client->jid, client->password, iks_find_attrib(node, "id"));
01369             if (auth) {
01370                iks_insert_attrib(auth, "id", client->mid);
01371                iks_insert_attrib(auth, "to", client->jid->server);
01372                ast_aji_increment_mid(client->mid);
01373                ast_aji_send(client, auth);
01374                iks_delete(auth);
01375             } else
01376                ast_log(LOG_ERROR, "Out of memory.\n");
01377          }
01378          break;
01379 
01380       case IKS_NODE_NORMAL:
01381 #ifdef HAVE_OPENSSL
01382          if (client->stream_flags & TRY_SECURE) {
01383             if (!strcmp("proceed", iks_name(node))) {
01384                return aji_tls_handshake(client);
01385             }
01386          }
01387 #endif
01388          if (!strcmp("stream:features", iks_name(node))) {
01389             features = iks_stream_features(node);
01390             if (client->usesasl) {
01391                if (client->usetls && !aji_is_secure(client))
01392                   break;
01393                if (client->authorized) {
01394                   if (features & IKS_STREAM_BIND) {
01395                      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);
01396                      auth = iks_make_resource_bind(client->jid);
01397                      if (auth) {
01398                         iks_insert_attrib(auth, "id", client->mid);
01399                         ast_aji_increment_mid(client->mid);
01400                         ast_aji_send(client, auth);
01401                         iks_delete(auth);
01402                      } else {
01403                         ast_log(LOG_ERROR, "Out of memory.\n");
01404                         break;
01405                      }
01406                   }
01407                   if (features & IKS_STREAM_SESSION) {
01408                      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);
01409                      auth = iks_make_session();
01410                      if (auth) {
01411                         iks_insert_attrib(auth, "id", "auth");
01412                         ast_aji_increment_mid(client->mid);
01413                         ast_aji_send(client, auth);
01414                         iks_delete(auth);
01415                      } else {
01416                         ast_log(LOG_ERROR, "Out of memory.\n");
01417                      }
01418                   }
01419                } else {
01420                   int ret;
01421                   if (!client->jid->user) {
01422                      ast_log(LOG_ERROR, "Malformed Jabber ID : %s (domain missing?)\n", client->jid->full);
01423                      break;
01424                   }
01425 
01426                   ret = aji_start_sasl(client, features, client->jid->user, client->password);
01427                   if (ret != IKS_OK) {
01428                      ASTOBJ_UNREF(client, aji_client_destroy);
01429                      return IKS_HOOK;
01430                   }
01431                   break;
01432                }
01433             }
01434          } else if (!strcmp("failure", iks_name(node))) {
01435             ast_log(LOG_ERROR, "JABBER: encryption failure. possible bad password.\n");
01436          } else if (!strcmp("success", iks_name(node))) {
01437             client->authorized = 1;
01438             aji_send_header(client, client->jid->server);
01439          }
01440          break;
01441       case IKS_NODE_ERROR: 
01442             ast_log(LOG_ERROR, "JABBER: Node Error\n");
01443             ASTOBJ_UNREF(client, aji_client_destroy);
01444             return IKS_HOOK;
01445             break;
01446       case IKS_NODE_STOP: 
01447             ast_log(LOG_WARNING, "JABBER: Disconnected\n");
01448             ASTOBJ_UNREF(client, aji_client_destroy);
01449             return IKS_HOOK;
01450             break;
01451       }
01452    } else if (client->state != AJI_CONNECTED && client->component) {
01453       switch (type) {
01454       case IKS_NODE_START:
01455          if (client->state == AJI_DISCONNECTED) {
01456             char secret[160], shasum[320], *handshake;
01457 
01458             sprintf(secret, "%s%s", pak->id, client->password);
01459             ast_sha1_hash(shasum, secret);
01460             handshake = NULL;
01461             if (asprintf(&handshake, "<handshake>%s</handshake>", shasum) >= 0) {
01462                aji_send_raw(client, handshake);
01463                ast_free(handshake);
01464                handshake = NULL;
01465             }
01466             client->state = AJI_CONNECTING;
01467             if (aji_recv(client, 1) == 2) /*XXX proper result for iksemel library on iks_recv of <handshake/> XXX*/
01468                client->state = AJI_CONNECTED;
01469             else
01470                ast_log(LOG_WARNING, "Jabber didn't seem to handshake, failed to authenticate.\n");
01471             break;
01472          }
01473          break;
01474 
01475       case IKS_NODE_NORMAL:
01476          break;
01477 
01478       case IKS_NODE_ERROR:
01479          ast_log(LOG_ERROR, "JABBER: Node Error\n");
01480          ASTOBJ_UNREF(client, aji_client_destroy);
01481          return IKS_HOOK;
01482 
01483       case IKS_NODE_STOP:
01484          ast_log(LOG_WARNING, "JABBER: Disconnected\n");
01485          ASTOBJ_UNREF(client, aji_client_destroy);
01486          return IKS_HOOK;
01487       }
01488    }
01489 
01490    switch (pak->type) {
01491    case IKS_PAK_NONE:
01492       ast_debug(1, "JABBER: I don't know what to do with paktype NONE.\n");
01493       break;
01494    case IKS_PAK_MESSAGE:
01495       aji_handle_message(client, pak);
01496       ast_debug(1, "JABBER: Handling paktype MESSAGE.\n");
01497       break;
01498    case IKS_PAK_PRESENCE:
01499       aji_handle_presence(client, pak);
01500       ast_debug(1, "JABBER: Handling paktype PRESENCE\n");
01501       break;
01502    case IKS_PAK_S10N:
01503       aji_handle_subscribe(client, pak);
01504       ast_debug(1, "JABBER: Handling paktype S10N\n");
01505       break;
01506    case IKS_PAK_IQ:
01507       ast_debug(1, "JABBER: Handling paktype IQ\n");
01508       aji_handle_iq(client, node);
01509       break;
01510    default:
01511       ast_debug(1, "JABBER: I don't know anything about paktype '%d'\n", pak->type);
01512       break;
01513    }
01514    
01515    iks_filter_packet(client->f, pak);
01516 
01517    if (node)
01518       iks_delete(node);
01519 
01520    ASTOBJ_UNREF(client, aji_client_destroy);
01521    return IKS_OK;
01522 }

static void aji_buddy_destroy ( struct aji_buddy obj  )  [static]

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

00385 {
00386    struct aji_resource *tmp;
00387 
00388    while ((tmp = obj->resources)) {
00389       obj->resources = obj->resources->next;
00390       ast_free(tmp->description);
00391       ast_free(tmp);
00392    }
00393 
00394    ast_free(obj);
00395 }

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

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

02747 {
02748    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
02749    int res = 0;
02750 
02751    if (client) {
02752       if (client->state == AJI_DISCONNECTED) {
02753          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);
02754          client->state = AJI_CONNECTING;
02755          client->jid = (iks_find_cdata(pak->query, "jid")) ? iks_id_new(client->stack, iks_find_cdata(pak->query, "jid")) : client->jid;
02756          iks_filter_remove_hook(client->f, aji_client_connect);
02757          if (!client->component) /*client*/
02758             aji_get_roster(client);
02759       }
02760    } else
02761       ast_log(LOG_ERROR, "Out of memory.\n");
02762 
02763    ASTOBJ_UNREF(client, aji_client_destroy);
02764    return res;
02765 }

static void aji_client_destroy ( struct aji_client obj  )  [static]

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

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

01744 {
01745    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01746    struct aji_resource *resource = NULL;
01747    struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01748 
01749    resource = aji_find_resource(buddy, pak->from->resource);
01750    if (pak->subtype == IKS_TYPE_RESULT) {
01751       if (!resource) {
01752          ast_log(LOG_NOTICE, "JABBER: Received client info from %s when not requested.\n", pak->from->full);
01753          ASTOBJ_UNREF(client, aji_client_destroy);
01754          return IKS_FILTER_EAT;
01755       }
01756       if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
01757          resource->cap->jingle = 1;
01758       } else
01759          resource->cap->jingle = 0;
01760    } else if (pak->subtype == IKS_TYPE_GET) {
01761       iks *iq, *disco, *ident, *google, *query;
01762       iq = iks_new("iq");
01763       query = iks_new("query");
01764       ident = iks_new("identity");
01765       disco = iks_new("feature");
01766       google = iks_new("feature");
01767       if (iq && ident && disco && google) {
01768          iks_insert_attrib(iq, "from", client->jid->full);
01769          iks_insert_attrib(iq, "to", pak->from->full);
01770          iks_insert_attrib(iq, "type", "result");
01771          iks_insert_attrib(iq, "id", pak->id);
01772          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01773          iks_insert_attrib(ident, "category", "client");
01774          iks_insert_attrib(ident, "type", "pc");
01775          iks_insert_attrib(ident, "name", "asterisk");
01776          iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco#info");
01777          iks_insert_attrib(google, "var", "http://www.google.com/xmpp/protocol/voice/v1");
01778          iks_insert_node(iq, query);
01779          iks_insert_node(query, ident);
01780          iks_insert_node(query, google);
01781          iks_insert_node(query, disco);
01782          ast_aji_send(client, iq);
01783       } else
01784          ast_log(LOG_ERROR, "Out of Memory.\n");
01785 
01786       iks_delete(iq);
01787       iks_delete(query);
01788       iks_delete(ident);
01789       iks_delete(google);
01790       iks_delete(disco);
01791    } else if (pak->subtype == IKS_TYPE_ERROR) {
01792       ast_log(LOG_NOTICE, "User %s does not support discovery.\n", pak->from->full);
01793    }
01794    ASTOBJ_UNREF(client, aji_client_destroy);
01795    return IKS_FILTER_EAT;
01796 }

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

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

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

03088 {
03089    char *resource;
03090    struct aji_client *client = NULL;
03091    int flag = 0;
03092 
03093    client = ASTOBJ_CONTAINER_FIND(&clients,label);
03094    if (!client) {
03095       flag = 1;
03096       client = ast_calloc(1, sizeof(*client));
03097       if (!client) {
03098          ast_log(LOG_ERROR, "Out of memory!\n");
03099          return 0;
03100       }
03101       ASTOBJ_INIT(client);
03102       ASTOBJ_WRLOCK(client);
03103       ASTOBJ_CONTAINER_INIT(&client->buddies);
03104    } else {
03105       ASTOBJ_WRLOCK(client);
03106       ASTOBJ_UNMARK(client);
03107    }
03108    ASTOBJ_CONTAINER_MARKALL(&client->buddies);
03109    ast_copy_string(client->name, label, sizeof(client->name));
03110    ast_copy_string(client->mid, "aaaaa", sizeof(client->mid));
03111 
03112    /* Set default values for the client object */
03113    client->debug = debug;
03114    ast_copy_flags(&client->flags, &globalflags, AST_FLAGS_ALL);
03115    client->port = 5222;
03116    client->usetls = 1;
03117    client->usesasl = 1;
03118    client->forcessl = 0;
03119    client->keepalive = 1;
03120    client->timeout = 50;
03121    client->message_timeout = 5;
03122    AST_LIST_HEAD_INIT(&client->messages);
03123    client->component = 0;
03124    ast_copy_string(client->statusmessage, "Online and Available", sizeof(client->statusmessage));
03125    client->priority = 0;
03126    client->status = IKS_SHOW_AVAILABLE;
03127 
03128    if (flag) {
03129       client->authorized = 0;
03130       client->state = AJI_DISCONNECTED;
03131    }
03132    while (var) {
03133       if (!strcasecmp(var->name, "username"))
03134          ast_copy_string(client->user, var->value, sizeof(client->user));
03135       else if (!strcasecmp(var->name, "serverhost"))
03136          ast_copy_string(client->serverhost, var->value, sizeof(client->serverhost));
03137       else if (!strcasecmp(var->name, "secret"))
03138          ast_copy_string(client->password, var->value, sizeof(client->password));
03139       else if (!strcasecmp(var->name, "statusmessage"))
03140          ast_copy_string(client->statusmessage, var->value, sizeof(client->statusmessage));
03141       else if (!strcasecmp(var->name, "port"))
03142          client->port = atoi(var->value);
03143       else if (!strcasecmp(var->name, "timeout"))
03144          client->message_timeout = atoi(var->value);
03145       else if (!strcasecmp(var->name, "debug"))
03146          client->debug = (ast_false(var->value)) ? 0 : 1;
03147       else if (!strcasecmp(var->name, "type")) {
03148          if (!strcasecmp(var->value, "component"))
03149             client->component = 1;
03150       } else if (!strcasecmp(var->name, "usetls")) {
03151          client->usetls = (ast_false(var->value)) ? 0 : 1;
03152       } else if (!strcasecmp(var->name, "usesasl")) {
03153          client->usesasl = (ast_false(var->value)) ? 0 : 1;
03154       } else if (!strcasecmp(var->name, "forceoldssl"))
03155          client->forcessl = (ast_false(var->value)) ? 0 : 1;
03156       else if (!strcasecmp(var->name, "keepalive"))
03157          client->keepalive = (ast_false(var->value)) ? 0 : 1;
03158       else if (!strcasecmp(var->name, "autoprune"))
03159          ast_set2_flag(&client->flags, ast_true(var->value), AJI_AUTOPRUNE);
03160       else if (!strcasecmp(var->name, "autoregister"))
03161          ast_set2_flag(&client->flags, ast_true(var->value), AJI_AUTOREGISTER);
03162       else if (!strcasecmp(var->name, "buddy"))
03163          aji_create_buddy((char *)var->value, client);
03164       else if (!strcasecmp(var->name, "priority"))
03165          client->priority = atoi(var->value);
03166       else if (!strcasecmp(var->name, "status")) {
03167          if (!strcasecmp(var->value, "unavailable"))
03168             client->status = IKS_SHOW_UNAVAILABLE;
03169          else
03170          if (!strcasecmp(var->value, "available")
03171           || !strcasecmp(var->value, "online"))
03172             client->status = IKS_SHOW_AVAILABLE;
03173          else
03174          if (!strcasecmp(var->value, "chat")
03175           || !strcasecmp(var->value, "chatty"))
03176             client->status = IKS_SHOW_CHAT;
03177          else
03178          if (!strcasecmp(var->value, "away"))
03179             client->status = IKS_SHOW_AWAY;
03180          else
03181          if (!strcasecmp(var->value, "xa")
03182           || !strcasecmp(var->value, "xaway"))
03183             client->status = IKS_SHOW_XA;
03184          else
03185          if (!strcasecmp(var->value, "dnd"))
03186             client->status = IKS_SHOW_DND;
03187          else
03188          if (!strcasecmp(var->value, "invisible"))
03189          #ifdef IKS_SHOW_INVISIBLE
03190             client->status = IKS_SHOW_INVISIBLE;
03191          #else
03192          {
03193             ast_log(LOG_WARNING, "Your iksemel doesn't support invisible status: falling back to DND\n");
03194             client->status = IKS_SHOW_DND;
03195          }
03196          #endif
03197          else
03198             ast_log(LOG_WARNING, "Unknown presence status: %s\n", var->value);
03199       }
03200    /* no transport support in this version */
03201    /* else if (!strcasecmp(var->name, "transport"))
03202             aji_create_transport(var->value, client);
03203    */
03204       var = var->next;
03205    }
03206    if (!flag) {
03207       ASTOBJ_UNLOCK(client);
03208       ASTOBJ_UNREF(client, aji_client_destroy);
03209       return 1;
03210    }
03211 
03212    ast_copy_string(client->name_space, (client->component) ? "jabber:component:accept" : "jabber:client", sizeof(client->name_space));
03213    client->p = iks_stream_new(client->name_space, client, aji_act_hook);
03214    if (!client->p) {
03215       ast_log(LOG_ERROR, "Failed to create stream for client '%s'!\n", client->name);
03216       return 0;
03217    }
03218    client->stack = iks_stack_new(8192, 8192);
03219    if (!client->stack) {
03220       ast_log(LOG_ERROR, "Failed to allocate stack for client '%s'\n", client->name);
03221       return 0;
03222    }
03223    client->f = iks_filter_new();
03224    if (!client->f) {
03225       ast_log(LOG_ERROR, "Failed to create filter for client '%s'\n", client->name);
03226       return 0;
03227    }
03228    if (!strchr(client->user, '/') && !client->component) { /*client */
03229       resource = NULL;
03230       if (asprintf(&resource, "%s/asterisk", client->user) >= 0) {
03231          client->jid = iks_id_new(client->stack, resource);
03232          ast_free(resource);
03233       }
03234    } else
03235       client->jid = iks_id_new(client->stack, client->user);
03236    if (client->component) {
03237       iks_filter_add_rule(client->f, aji_dinfo_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
03238       iks_filter_add_rule(client->f, aji_ditems_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#items", IKS_RULE_DONE);
03239       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);
03240       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);
03241    } else {
03242       iks_filter_add_rule(client->f, aji_client_info_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
03243    }
03244    iks_set_log_hook(client->p, aji_log_hook);
03245    ASTOBJ_UNLOCK(client);
03246    ASTOBJ_CONTAINER_LINK(&clients,client);
03247    return 1;
03248 }

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

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

01806 {
01807    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01808    char *node = NULL;
01809    struct aji_resource *resource = NULL;
01810    struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01811 
01812    resource = aji_find_resource(buddy, pak->from->resource);
01813    if (pak->subtype == IKS_TYPE_ERROR) {
01814       ast_log(LOG_WARNING, "Received error from a client, turn on jabber debug!\n");
01815       return IKS_FILTER_EAT;
01816    }
01817    if (pak->subtype == IKS_TYPE_RESULT) {
01818       if (!resource) {
01819          ast_log(LOG_NOTICE,"JABBER: Received client info from %s when not requested.\n", pak->from->full);
01820          ASTOBJ_UNREF(client, aji_client_destroy);
01821          return IKS_FILTER_EAT;
01822       }
01823       if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
01824          resource->cap->jingle = 1;
01825       } else
01826          resource->cap->jingle = 0;
01827    } else if (pak->subtype == IKS_TYPE_GET && !(node = iks_find_attrib(pak->query, "node"))) {
01828       iks *iq, *query, *identity, *disco, *reg, *commands, *gateway, *version, *vcard, *search;
01829 
01830       iq = iks_new("iq");
01831       query = iks_new("query");
01832       identity = iks_new("identity");
01833       disco = iks_new("feature");
01834       reg = iks_new("feature");
01835       commands = iks_new("feature");
01836       gateway = iks_new("feature");
01837       version = iks_new("feature");
01838       vcard = iks_new("feature");
01839       search = iks_new("feature");
01840 
01841       if (iq && query && identity && disco && reg && commands && gateway && version && vcard && search && client) {
01842          iks_insert_attrib(iq, "from", client->user);
01843          iks_insert_attrib(iq, "to", pak->from->full);
01844          iks_insert_attrib(iq, "id", pak->id);
01845          iks_insert_attrib(iq, "type", "result");
01846          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01847          iks_insert_attrib(identity, "category", "gateway");
01848          iks_insert_attrib(identity, "type", "pstn");
01849          iks_insert_attrib(identity, "name", "Asterisk The Open Source PBX");
01850          iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco");
01851          iks_insert_attrib(reg, "var", "jabber:iq:register");
01852          iks_insert_attrib(commands, "var", "http://jabber.org/protocol/commands");
01853          iks_insert_attrib(gateway, "var", "jabber:iq:gateway");
01854          iks_insert_attrib(version, "var", "jabber:iq:version");
01855          iks_insert_attrib(vcard, "var", "vcard-temp");
01856          iks_insert_attrib(search, "var", "jabber:iq:search");
01857 
01858          iks_insert_node(iq, query);
01859          iks_insert_node(query, identity);
01860          iks_insert_node(query, disco);
01861          iks_insert_node(query, reg);
01862          iks_insert_node(query, commands);
01863          iks_insert_node(query, gateway);
01864          iks_insert_node(query, version);
01865          iks_insert_node(query, vcard);
01866          iks_insert_node(query, search);
01867          ast_aji_send(client, iq);
01868       } else {
01869          ast_log(LOG_ERROR, "Out of memory.\n");
01870       }
01871 
01872       iks_delete(iq);
01873       iks_delete(query);
01874       iks_delete(identity);
01875       iks_delete(disco);
01876       iks_delete(reg);
01877       iks_delete(commands);
01878       iks_delete(gateway);
01879       iks_delete(version);
01880       iks_delete(vcard);
01881       iks_delete(search);
01882 
01883    } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "http://jabber.org/protocol/commands")) {
01884       iks *iq, *query, *confirm;
01885       iq = iks_new("iq");
01886       query = iks_new("query");
01887       confirm = iks_new("item");
01888 
01889       if (iq && query && confirm && client) {
01890          iks_insert_attrib(iq, "from", client->user);
01891          iks_insert_attrib(iq, "to", pak->from->full);
01892          iks_insert_attrib(iq, "id", pak->id);
01893          iks_insert_attrib(iq, "type", "result");
01894          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01895          iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
01896          iks_insert_attrib(confirm, "node", "confirmaccount");
01897          iks_insert_attrib(confirm, "name", "Confirm AIM account");
01898          iks_insert_attrib(confirm, "jid", client->user);
01899          iks_insert_node(iq, query);
01900          iks_insert_node(query, confirm);
01901          ast_aji_send(client, iq);
01902       } else {
01903          ast_log(LOG_ERROR, "Out of memory.\n");
01904       }
01905 
01906       iks_delete(iq);
01907       iks_delete(query);
01908       iks_delete(confirm);
01909 
01910    } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "confirmaccount")) {
01911       iks *iq, *query, *feature;
01912 
01913       iq = iks_new("iq");
01914       query = iks_new("query");
01915       feature = iks_new("feature");
01916 
01917       if (iq && query && feature && client) {
01918          iks_insert_attrib(iq, "from", client->user);
01919          iks_insert_attrib(iq, "to", pak->from->full);
01920          iks_insert_attrib(iq, "id", pak->id);
01921          iks_insert_attrib(iq, "type", "result");
01922          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01923          iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
01924          iks_insert_node(iq, query);
01925          iks_insert_node(query, feature);
01926          ast_aji_send(client, iq);
01927       } else {
01928          ast_log(LOG_ERROR, "Out of memory.\n");
01929       }
01930 
01931       iks_delete(iq);
01932       iks_delete(query);
01933       iks_delete(feature);
01934    }
01935 
01936    ASTOBJ_UNREF(client, aji_client_destroy);
01937    return IKS_FILTER_EAT;
01938 }

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

Definition at line 1646 of file res_jabber.c.

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

01647 {
01648    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01649    char *node = NULL;
01650 
01651    if (!(node = iks_find_attrib(pak->query, "node"))) {
01652       iks *iq = NULL, *query = NULL, *item = NULL;
01653       iq = iks_new("iq");
01654       query = iks_new("query");
01655       item = iks_new("item");
01656 
01657       if (iq && query && item) {
01658          iks_insert_attrib(iq, "from", client->user);
01659          iks_insert_attrib(iq, "to", pak->from->full);
01660          iks_insert_attrib(iq, "id", pak->id);
01661          iks_insert_attrib(iq, "type", "result");
01662          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01663          iks_insert_attrib(item, "node", "http://jabber.org/protocol/commands");
01664          iks_insert_attrib(item, "name", "Million Dollar Asterisk Commands");
01665          iks_insert_attrib(item, "jid", client->user);
01666 
01667          iks_insert_node(iq, query);
01668          iks_insert_node(query, item);
01669          ast_aji_send(client, iq);
01670       } else {
01671          ast_log(LOG_ERROR, "Out of memory.\n");
01672       }
01673 
01674       iks_delete(iq);
01675       iks_delete(query);
01676       iks_delete(item);
01677 
01678    } else if (!strcasecmp(node, "http://jabber.org/protocol/commands")) {
01679       iks *iq, *query, *confirm;
01680       iq = iks_new("iq");
01681       query = iks_new("query");
01682       confirm = iks_new("item");
01683       if (iq && query && confirm && client) {
01684          iks_insert_attrib(iq, "from", client->user);
01685          iks_insert_attrib(iq, "to", pak->from->full);
01686          iks_insert_attrib(iq, "id", pak->id);
01687          iks_insert_attrib(iq, "type", "result");
01688          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01689          iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
01690          iks_insert_attrib(confirm, "node", "confirmaccount");
01691          iks_insert_attrib(confirm, "name", "Confirm AIM account");
01692          iks_insert_attrib(confirm, "jid", "blog.astjab.org");
01693 
01694          iks_insert_node(iq, query);
01695          iks_insert_node(query, confirm);
01696          ast_aji_send(client, iq);
01697       } else {
01698          ast_log(LOG_ERROR, "Out of memory.\n");
01699       }
01700 
01701       iks_delete(iq);
01702       iks_delete(query);
01703       iks_delete(confirm);
01704 
01705    } else if (!strcasecmp(node, "confirmaccount")) {
01706       iks *iq = NULL, *query = NULL, *feature = NULL;
01707 
01708       iq = iks_new("iq");
01709       query = iks_new("query");
01710       feature = iks_new("feature");
01711 
01712       if (iq && query && feature && client) {
01713          iks_insert_attrib(iq, "from", client->user);
01714          iks_insert_attrib(iq, "to", pak->from->full);
01715          iks_insert_attrib(iq, "id", pak->id);
01716          iks_insert_attrib(iq, "type", "result");
01717          iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01718          iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
01719          iks_insert_node(iq, query);
01720          iks_insert_node(query, feature);
01721          ast_aji_send(client, iq);
01722       } else {
01723          ast_log(LOG_ERROR, "Out of memory.\n");
01724       }
01725 
01726       iks_delete(iq);
01727       iks_delete(query);
01728       iks_delete(feature);
01729    }
01730 
01731    ASTOBJ_UNREF(client, aji_client_destroy);
01732    return IKS_FILTER_EAT;
01733 
01734 }

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

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

02906 {
02907    switch (cmd) {
02908    case CLI_INIT:
02909       e->command = "jabber reload";
02910       e->usage =
02911          "Usage: jabber reload\n"
02912          "       Reloads the Jabber module.\n";
02913       return NULL;
02914    case CLI_GENERATE:
02915       return NULL;
02916    }
02917 
02918    aji_reload(1);
02919    ast_cli(a->fd, "Jabber Reloaded.\n");
02920    return CLI_SUCCESS;
02921 }

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

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

02865 {
02866    switch (cmd) {
02867    case CLI_INIT:
02868       e->command = "jabber set debug {on|off}";
02869       e->usage =
02870          "Usage: jabber set debug {on|off}\n"
02871          "       Enables/disables dumping of XMPP/Jabber packets for debugging purposes.\n";
02872       return NULL;
02873    case CLI_GENERATE:
02874       return NULL;
02875    }
02876 
02877    if (a->argc != e->args)
02878       return CLI_SHOWUSAGE;
02879 
02880    if (!strncasecmp(a->argv[e->args - 1], "on", 2)) {
02881       ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02882          ASTOBJ_RDLOCK(iterator); 
02883          iterator->debug = 1;
02884          ASTOBJ_UNLOCK(iterator);
02885       });
02886       ast_cli(a->fd, "Jabber Debugging Enabled.\n");
02887       return CLI_SUCCESS;
02888    } else if (!strncasecmp(a->argv[e->args - 1], "off", 3)) {
02889       ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02890          ASTOBJ_RDLOCK(iterator); 
02891          iterator->debug = 0;
02892          ASTOBJ_UNLOCK(iterator);
02893       });
02894       ast_cli(a->fd, "Jabber Debugging Disabled.\n");
02895       return CLI_SUCCESS;
02896    }
02897    return CLI_SHOWUSAGE; /* defaults to invalid */
02898 }

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

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

02617 {
02618    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
02619    int flag = 0;
02620    iks *x = NULL;
02621    struct aji_buddy *buddy;
02622    
02623    client->state = AJI_CONNECTED;
02624    ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02625       ASTOBJ_RDLOCK(iterator);
02626       x = iks_child(pak->query);
02627       flag = 0;
02628       while (x) {
02629          if (!iks_strcmp(iks_name(x), "item")) {
02630             if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid"))) {
02631                flag = 1;
02632                ast_clear_flag(&iterator->flags, AJI_AUTOPRUNE | AJI_AUTOREGISTER);
02633             }
02634          }
02635          x = iks_next(x);
02636       }
02637       if (!flag)
02638          ast_copy_flags(&iterator->flags, &client->flags, AJI_AUTOREGISTER);
02639       iks_delete(x);
02640       
02641       ASTOBJ_UNLOCK(iterator);
02642    });
02643 
02644    x = iks_child(pak->query);
02645    while (x) {
02646       flag = 0;
02647       if (iks_strcmp(iks_name(x), "item") == 0) {
02648          ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02649             ASTOBJ_RDLOCK(iterator);
02650             if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid")))
02651                flag = 1;
02652             ASTOBJ_UNLOCK(iterator);
02653          });
02654 
02655          if (flag) {
02656             /* found buddy, don't create a new one */
02657             x = iks_next(x);
02658             continue;
02659          }
02660          
02661          buddy = ast_calloc(1, sizeof(*buddy));
02662          if (!buddy) {
02663             ast_log(LOG_WARNING, "Out of memory\n");
02664             return 0;
02665          }
02666          ASTOBJ_INIT(buddy);
02667          ASTOBJ_WRLOCK(buddy);
02668          ast_copy_string(buddy->name, iks_find_attrib(x, "jid"), sizeof(buddy->name));
02669          ast_clear_flag(&buddy->flags, AST_FLAGS_ALL);
02670          if (ast_test_flag(&client->flags, AJI_AUTOPRUNE)) {
02671             ast_set_flag(&buddy->flags, AJI_AUTOPRUNE);
02672             ASTOBJ_MARK(buddy);
02673          } else if (!iks_strcmp(iks_find_attrib(x, "subscription"), "none") || !iks_strcmp(iks_find_attrib(x, "subscription"), "from")) {
02674             /* subscribe to buddy's presence only
02675                if we really need to */
02676             ast_set_flag(&buddy->flags, AJI_AUTOREGISTER);
02677          }
02678          ASTOBJ_UNLOCK(buddy);
02679          if (buddy) {
02680             ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
02681             ASTOBJ_UNREF(buddy, aji_buddy_destroy);
02682          }
02683       }
02684       x = iks_next(x);
02685    }
02686 
02687    iks_delete(x);
02688    aji_pruneregister(client);
02689 
02690    ASTOBJ_UNREF(client, aji_client_destroy);
02691    return IKS_FILTER_EAT;
02692 }

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

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

00494 {
00495    struct aji_resource *res = NULL;
00496    if (!buddy || !name)
00497       return res;
00498    res = buddy->resources;
00499    while (res) {
00500       if (!strcasecmp(res->resource, name)) {
00501          break;
00502       }
00503       res = res->next;
00504    }
00505    return res;
00506 }

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

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

00425 {
00426    struct aji_capabilities *list = NULL;
00427    struct aji_version *res = NULL;
00428 
00429    list = capabilities;
00430 
00431    if (!node)
00432       node = pak->from->full;
00433    if (!version)
00434       version = "none supplied.";
00435    while(list) {
00436       if (!strcasecmp(list->node, node)) {
00437          res = list->versions;
00438          while(res) {
00439              if (!strcasecmp(res->version, version))
00440                 return res;
00441              res = res->next;
00442          }
00443          /* Specified version not found. Let's add it to
00444             this node in our capabilities list */
00445          if (!res) {
00446             res = ast_malloc(sizeof(*res));
00447             if (!res) {
00448                ast_log(LOG_ERROR, "Out of memory!\n");
00449                return NULL;
00450             }
00451             res->jingle = 0;
00452             res->parent = list;
00453             ast_copy_string(res->version, version, sizeof(res->version));
00454             res->next = list->versions;
00455             list->versions = res;
00456             return res;
00457          }
00458       }
00459       list = list->next;
00460    }
00461    /* Specified node not found. Let's add it our capabilities list */
00462    if (!list) {
00463       list = ast_malloc(sizeof(*list));
00464       if (!list) {
00465          ast_log(LOG_ERROR, "Out of memory!\n");
00466          return NULL;
00467       }
00468       res = ast_malloc(sizeof(*res));
00469       if (!res) {
00470          ast_log(LOG_ERROR, "Out of memory!\n");
00471          ast_free(list);
00472          return NULL;
00473       }
00474       ast_copy_string(list->node, node, sizeof(list->node));
00475       ast_copy_string(res->version, version, sizeof(res->version));
00476       res->jingle = 0;
00477       res->parent = list;
00478       res->next = NULL;
00479       list->versions = res;
00480       list->next = capabilities;
00481       capabilities = list;
00482    }
00483    return res;
00484 }

static int aji_get_roster ( struct aji_client client  )  [static]

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

02724 {
02725    iks *roster = NULL;
02726    roster = iks_make_iq(IKS_TYPE_GET, IKS_NS_ROSTER);
02727 
02728    if (roster) {
02729       iks_insert_attrib(roster, "id", "roster");
02730       aji_set_presence(client, NULL, client->jid->full, client->status, client->statusmessage);
02731       ast_aji_send(client, roster);
02732    }
02733 
02734    iks_delete(roster);
02735    
02736    return 1;
02737 }

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

Definition at line 1947 of file res_jabber.c.

Referenced by aji_act_hook().

01948 {
01949    /*Nothing to see here */
01950 }

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

Definition at line 1959 of file res_jabber.c.

References aji_message::arrived, ast_calloc, ast_cond_broadcast(), ast_copy_string(), ast_debug, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_strdup, ast_tvnow(), delete_old_messages(), aji_message::from, aji_message::id, aji_message::list, LOG_ERROR, aji_message::message, aji_client::messages, and aji_client::name.

Referenced by aji_act_hook().

01960 {
01961    struct aji_message *insert;
01962    int deleted = 0;
01963 
01964    ast_debug(3, "client %s received a message\n", client->name);
01965 
01966    if (!(insert = ast_calloc(1, sizeof(*insert)))) {
01967       return;
01968    }
01969 
01970    insert->arrived = ast_tvnow();
01971 
01972    /* wake up threads waiting for messages */
01973    ast_mutex_lock(&messagelock);
01974    ast_cond_broadcast(&message_received_condition);
01975    ast_mutex_unlock(&messagelock);
01976 
01977    if (iks_find_cdata(pak->x, "body")) {
01978       insert->message = ast_strdup(iks_find_cdata(pak->x, "body"));
01979    }
01980    if (pak->id) {
01981       ast_copy_string(insert->id, pak->id, sizeof(insert->id));
01982    }
01983    if (pak->from){
01984       /* insert will furtherly be added to message list */
01985       insert->from = ast_strdup(pak->from->full);
01986       if (!insert->from) {
01987          ast_log(LOG_ERROR, "Memory allocation failure\n");
01988          return;
01989       }
01990       ast_debug(3, "message comes from %s\n", insert->from);
01991    }
01992 
01993    /* remove old messages received from this JID
01994     * and insert received message */
01995    deleted = delete_old_messages(client, pak->from->partial);
01996    ast_debug(3, "Deleted %d messages for client %s from JID %s\n", deleted, client->name, pak->from->partial);
01997    AST_LIST_LOCK(&client->messages);
01998    AST_LIST_INSERT_HEAD(&client->messages, insert, list);
01999    AST_LIST_UNLOCK(&client->messages);
02000 }

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

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

02009 {
02010    int status, priority;
02011    struct aji_buddy *buddy;
02012    struct aji_resource *tmp = NULL, *last = NULL, *found = NULL;
02013    char *ver, *node, *descrip, *type;
02014 
02015    if (client->state != AJI_CONNECTED)
02016       aji_create_buddy(pak->from->partial, client);
02017 
02018    buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
02019    if (!buddy && pak->from->partial) {
02020       /* allow our jid to be used to log in with another resource */
02021       if (!strcmp((const char *)pak->from->partial, (const char *)client->jid->partial))
02022          aji_create_buddy(pak->from->partial, client);
02023       else
02024          ast_log(LOG_NOTICE, "Got presence packet from %s, someone not in our roster!!!!\n", pak->from->partial);
02025       return;
02026    }
02027    type = iks_find_attrib(pak->x, "type");
02028    if (client->component && type &&!strcasecmp("probe", type)) {
02029       aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), client->status, client->statusmessage);
02030       ast_verbose("what i was looking for \n");
02031    }
02032    ASTOBJ_WRLOCK(buddy);
02033    status = (pak->show) ? pak->show : 6;
02034    priority = atoi((iks_find_cdata(pak->x, "priority")) ? iks_find_cdata(pak->x, "priority") : "0");
02035    tmp = buddy->resources;
02036    descrip = ast_strdup(iks_find_cdata(pak->x,"status"));
02037 
02038    while (tmp && pak->from->resource) {
02039       if (!strcasecmp(tmp->resource, pak->from->resource)) {
02040          tmp->status = status;
02041          if (tmp->description) ast_free(tmp->description);
02042          tmp->description = descrip;
02043          found = tmp;
02044          if (status == 6) {   /* Sign off Destroy resource */
02045             if (last && found->next) {
02046                last->next = found->next;
02047             } else if (!last) {
02048                if (found->next)
02049                   buddy->resources = found->next;
02050                else
02051                   buddy->resources = NULL;
02052             } else if (!found->next) {
02053                if (last)
02054                   last->next = NULL;
02055                else
02056                   buddy->resources = NULL;
02057             }
02058             ast_free(found);
02059             found = NULL;
02060             break;
02061          }
02062          /* resource list is sorted by descending priority */
02063          if (tmp->priority != priority) {
02064             found->priority = priority;
02065             if (!last && !found->next)
02066                /* resource was found to be unique,
02067                   leave loop */
02068                break;
02069             /* search for resource in our list
02070                and take it out for the moment */
02071             if (last)
02072                last->next = found->next;
02073             else
02074                buddy->resources = found->next;
02075 
02076             last = NULL;
02077             tmp = buddy->resources;
02078             if (!buddy->resources)
02079                buddy->resources = found;
02080             /* priority processing */
02081             while (tmp) {
02082                /* insert resource back according to 
02083                   its priority value */
02084                if (found->priority > tmp->priority) {
02085                   if (last)
02086                      /* insert within list */
02087                      last->next = found;
02088                   found->next = tmp;
02089                   if (!last)
02090                      /* insert on top */
02091                      buddy->resources = found;
02092                   break;
02093                }
02094                if (!tmp->next) {
02095                   /* insert at the end of the list */
02096                   tmp->next = found;
02097                   found->next = NULL;
02098                   break;
02099                }
02100                last = tmp;
02101                tmp = tmp->next;
02102             }
02103          }
02104          break;
02105       }
02106       last = tmp;
02107       tmp = tmp->next;
02108    }
02109 
02110    /* resource not found in our list, create it */
02111    if (!found && status != 6 && pak->from->resource) {
02112       found = ast_calloc(1, sizeof(*found));
02113 
02114       if (!found) {
02115          ast_log(LOG_ERROR, "Out of memory!\n");
02116          return;
02117       }
02118       ast_copy_string(found->resource, pak->from->resource, sizeof(found->resource));
02119       found->status = status;
02120       found->description = descrip;
02121       found->priority = priority;
02122       found->next = NULL;
02123       last = NULL;
02124       tmp = buddy->resources;
02125       while (tmp) {
02126          if (found->priority > tmp->priority) {
02127             if (last)
02128                last->next = found;
02129             found->next = tmp;
02130             if (!last)
02131                buddy->resources = found;
02132             break;
02133          }
02134          if (!tmp->next) {
02135             tmp->next = found;
02136             break;
02137          }
02138          last = tmp;
02139          tmp = tmp->next;
02140       }
02141       if (!tmp)
02142          buddy->resources = found;
02143    }
02144    
02145    ASTOBJ_UNLOCK(buddy);
02146    ASTOBJ_UNREF(buddy, aji_buddy_destroy);
02147 
02148    node = iks_find_attrib(iks_find(pak->x, "c"), "node");
02149    ver = iks_find_attrib(iks_find(pak->x, "c"), "ver");
02150 
02151    /* handle gmail client's special caps:c tag */
02152    if (!node && !ver) {
02153       node = iks_find_attrib(iks_find(pak->x, "caps:c"), "node");
02154       ver = iks_find_attrib(iks_find(pak->x, "caps:c"), "ver");
02155    }
02156 
02157    /* retrieve capabilites of the new resource */
02158    if (status != 6 && found && !found->cap) {
02159       found->cap = aji_find_version(node, ver, pak);
02160       if (gtalk_yuck(pak->x)) /* gtalk should do discover */
02161          found->cap->jingle = 1;
02162       if (found->cap->jingle && option_debug > 4) {
02163          ast_debug(1,"Special case for google till they support discover.\n");
02164       }
02165       else {
02166          iks *iq, *query;
02167          iq = iks_new("iq");
02168          query = iks_new("query");
02169          if (query && iq)  {
02170             iks_insert_attrib(iq, "type", "get");
02171             iks_insert_attrib(iq, "to", pak->from->full);
02172             iks_insert_attrib(iq,"from", client->jid->full);
02173             iks_insert_attrib(iq, "id", client->mid);
02174             ast_aji_increment_mid(client->mid);
02175             iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
02176             iks_insert_node(iq, query);
02177             ast_aji_send(client, iq);
02178             
02179          } else
02180             ast_log(LOG_ERROR, "Out of memory.\n");
02181          
02182          iks_delete(query);
02183          iks_delete(iq);
02184       }
02185    }
02186    switch (pak->subtype) {
02187    case IKS_TYPE_AVAILABLE:
02188       ast_debug(3, "JABBER: I am available ^_* %i\n", pak->subtype);
02189       break;
02190    case IKS_TYPE_UNAVAILABLE:
02191       ast_debug(3, "JABBER: I am unavailable ^_* %i\n", pak->subtype);
02192       break;
02193    default:
02194       ast_debug(3, "JABBER: Ohh sexy and the wrong type: %i\n", pak->subtype);
02195    }
02196    switch (pak->show) {
02197    case IKS_SHOW_UNAVAILABLE:
02198       ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
02199       break;
02200    case IKS_SHOW_AVAILABLE:
02201       ast_debug(3, "JABBER: type is available\n");
02202       break;
02203    case IKS_SHOW_CHAT:
02204       ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
02205       break;
02206    case IKS_SHOW_AWAY:
02207       ast_debug(3, "JABBER: type is away\n");
02208       break;
02209    case IKS_SHOW_XA:
02210       ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
02211       break;
02212    case IKS_SHOW_DND:
02213       ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
02214       break;
02215    default:
02216       ast_debug(3, "JABBER: Kinky! how did that happen %i\n", pak->show);
02217    }
02218 }

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

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

02228 {
02229    iks *presence = NULL, *status = NULL;
02230    struct aji_buddy* buddy = NULL;
02231 
02232    switch (pak->subtype) { 
02233    case IKS_TYPE_SUBSCRIBE:
02234       presence = iks_new("presence");
02235       status = iks_new("status");
02236       if (presence && status) {
02237          iks_insert_attrib(presence, "type", "subscribed");
02238          iks_insert_attrib(presence, "to", pak->from->full);
02239          iks_insert_attrib(presence, "from", client->jid->full);
02240          if (pak->id)
02241             iks_insert_attrib(presence, "id", pak->id);
02242          iks_insert_cdata(status, "Asterisk has approved subscription", 0);
02243          iks_insert_node(presence, status);
02244          ast_aji_send(client, presence);
02245       } else
02246          ast_log(LOG_ERROR, "Unable to allocate nodes\n");
02247 
02248       iks_delete(presence);
02249       iks_delete(status);
02250 
02251       if (client->component)
02252          aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), client->status, client->statusmessage);
02253    case IKS_TYPE_SUBSCRIBED:
02254       buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
02255       if (!buddy && pak->from->partial) {
02256          aji_create_buddy(pak->from->partial, client);
02257       }
02258    default:
02259       if (option_verbose > 4) {
02260          ast_verbose(VERBOSE_PREFIX_3 "JABBER: This is a subcription of type %i\n", pak->subtype);
02261       }
02262    }
02263 }

static int aji_initialize ( struct aji_client client  )  [static]

Definition at line 2773 of file res_jabber.c.

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

Referenced by aji_reconnect().

02774 {
02775    int connected = IKS_NET_NOCONN;
02776 
02777 #ifdef HAVE_OPENSSL  
02778    /* reset stream flags */
02779    client->stream_flags = 0;
02780 #endif
02781    /* If it's a component, connect to user, otherwise, connect to server */
02782    connected = iks_connect_via(client->p, S_OR(client->serverhost, client->jid->server), client->port, client->component ? client->user : client->jid->server);
02783 
02784    if (connected == IKS_NET_NOCONN) {
02785       ast_log(LOG_ERROR, "JABBER ERROR: No Connection\n");
02786       return IKS_HOOK;
02787    } else   if (connected == IKS_NET_NODNS) {
02788       ast_log(LOG_ERROR, "JABBER ERROR: No DNS %s for client to  %s\n", client->name, S_OR(client->serverhost, client->jid->server));
02789       return IKS_HOOK;
02790    }
02791 
02792    return IKS_OK;
02793 }

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

Definition at line 1046 of file res_jabber.c.

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

Referenced by aji_recv().

01047 {
01048    int sock;
01049    fd_set fds;
01050    struct timeval tv, *tvptr = NULL;
01051    int len, res;
01052 
01053 #ifdef HAVE_OPENSSL
01054    if (aji_is_secure(client)) {
01055       sock = SSL_get_fd(client->ssl_session);
01056       if (sock < 0)
01057          return -1;     
01058    } else
01059 #endif /* HAVE_OPENSSL */
01060       sock = iks_fd(client->p);  
01061 
01062    memset(&tv, 0, sizeof(struct timeval));
01063    FD_ZERO(&fds);
01064    FD_SET(sock, &fds);
01065    tv.tv_sec = timeout;
01066 
01067    /* NULL value for tvptr makes ast_select wait indefinitely */
01068    tvptr = (timeout != -1) ? &tv : NULL;
01069 
01070    /* ast_select emulates linux behaviour in terms of timeout handling */
01071    res = ast_select(sock + 1, &fds, NULL, NULL, tvptr);
01072    if (res > 0) {
01073 #ifdef HAVE_OPENSSL
01074       if (aji_is_secure(client)) {
01075          len = SSL_read(client->ssl_session, buffer, buf_len);
01076       } else
01077 #endif /* HAVE_OPENSSL */
01078          len = recv(sock, buffer, buf_len, 0);
01079 
01080       if (len > 0) {
01081          return len;
01082       } else if (len <= 0) {
01083          return -1;
01084       }
01085    }
01086    return res;
01087 }

static int aji_is_secure ( struct aji_client client  )  [static]

Definition at line 956 of file res_jabber.c.

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

00957 {
00958 #ifdef HAVE_OPENSSL
00959    return client->stream_flags & SECURE;
00960 #else
00961    return 0;
00962 #endif
00963 }

static int aji_load_config ( int  reload  )  [static]

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

03336 {
03337    char *cat = NULL;
03338    int debug = 1;
03339    struct ast_config *cfg = NULL;
03340    struct ast_variable *var = NULL;
03341    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
03342 
03343    if ((cfg = ast_config_load(JABBER_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
03344       return -1;
03345 
03346    /* Reset flags to default value */
03347    ast_set_flag(&globalflags, AJI_AUTOREGISTER);
03348 
03349    if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
03350       ast_log(LOG_WARNING, "No such configuration file %s\n", JABBER_CONFIG);
03351       return 0;
03352    }
03353 
03354    cat = ast_category_browse(cfg, NULL);
03355    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
03356       if (!strcasecmp(var->name, "debug")) {
03357          debug = (ast_false(ast_variable_retrieve(cfg, "general", "debug"))) ? 0 : 1;
03358       } else if (!strcasecmp(var->name, "autoprune")) {
03359          ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOPRUNE);
03360       } else if (!strcasecmp(var->name, "autoregister")) {
03361          ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOREGISTER);
03362       }
03363    }
03364 
03365    while (cat) {
03366       if (strcasecmp(cat, "general")) {
03367             var = ast_variable_browse(cfg, cat);
03368             aji_create_client(cat, var, debug);
03369       }
03370       cat = ast_category_browse(cfg, cat);
03371    }
03372    ast_config_destroy(cfg); /* or leak memory */
03373    return 1;
03374 }

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

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

01247 {
01248    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01249 
01250    if (!ast_strlen_zero(xmpp))
01251       manager_event(EVENT_FLAG_USER, "JabberEvent", "Account: %s\r\nPacket: %s\r\n", client->name, xmpp);
01252 
01253    if (client->debug) {
01254       if (is_incoming)
01255          ast_verbose("\nJABBER: %s INCOMING: %s\n", client->name, xmpp);
01256       else {
01257          if (strlen(xmpp) == 1) {
01258             if (option_debug > 2  && xmpp[0] == ' ') {
01259                ast_verbose("\nJABBER: Keep alive packet\n");
01260             }
01261          } else
01262             ast_verbose("\nJABBER: %s OUTGOING: %s\n", client->name, xmpp);
01263       }
01264 
01265    }
01266    ASTOBJ_UNREF(client, aji_client_destroy);
01267 }

static void aji_message_destroy ( struct aji_message obj  )  [static]

Definition at line 403 of file res_jabber.c.

References ast_free, aji_message::from, and aji_message::message.

Referenced by acf_jabberreceive_read(), aji_client_destroy(), and delete_old_messages().

00404 {
00405    if (obj->from) {
00406       ast_free(obj->from);
00407    }
00408    if (obj->message) {
00409       ast_free(obj->message);
00410    }
00411    ast_free(obj);
00412 }

static void aji_pruneregister ( struct aji_client client  )  [static]

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

02562 {
02563    int res = 0;
02564    iks *removeiq = iks_new("iq");
02565    iks *removequery = iks_new("query");
02566    iks *removeitem = iks_new("item");
02567    iks *send = iks_make_iq(IKS_TYPE_GET, "http://jabber.org/protocol/disco#items");
02568    if (!client || !removeiq || !removequery || !removeitem || !send) {
02569       ast_log(LOG_ERROR, "Out of memory.\n");
02570       goto safeout;
02571    }
02572 
02573    iks_insert_node(removeiq, removequery);
02574    iks_insert_node(removequery, removeitem);
02575    ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02576       ASTOBJ_RDLOCK(iterator);
02577       /* For an aji_buddy, both AUTOPRUNE and AUTOREGISTER will never
02578        * be called at the same time */
02579       if (ast_test_flag(&iterator->flags, AJI_AUTOPRUNE)) { /* If autoprune is set on jabber.conf */
02580          res = ast_aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBE, iterator->name,
02581                          "GoodBye. Your status is no longer needed by Asterisk the Open Source PBX"
02582                          " so I am no longer subscribing to your presence.\n"));
02583          res = ast_aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBED, iterator->name,
02584                          "GoodBye.  You are no longer in the Asterisk config file so I am removing"
02585                          " your access to my presence.\n"));
02586          iks_insert_attrib(removeiq, "from", client->jid->full); 
02587          iks_insert_attrib(removeiq, "type", "set"); 
02588          iks_insert_attrib(removequery, "xmlns", "jabber:iq:roster");
02589          iks_insert_attrib(removeitem, "jid", iterator->name);
02590          iks_insert_attrib(removeitem, "subscription", "remove");
02591          res = ast_aji_send(client, removeiq);
02592       } else if (ast_test_flag(&iterator->flags, AJI_AUTOREGISTER)) {
02593          res = ast_aji_send(client, iks_make_s10n(IKS_TYPE_SUBSCRIBE, iterator->name, 
02594                          "Greetings! I am the Asterisk Open Source PBX and I want to subscribe to your presence\n"));
02595          ast_clear_flag(&iterator->flags, AJI_AUTOREGISTER);
02596       }
02597       ASTOBJ_UNLOCK(iterator);
02598    });
02599 
02600  safeout:
02601    iks_delete(removeiq);
02602    iks_delete(removequery);
02603    iks_delete(removeitem);
02604    iks_delete(send);
02605    
02606    ASTOBJ_CONTAINER_PRUNE_MARKED(&client->buddies, aji_buddy_destroy);
02607 }

static int aji_reconnect ( struct aji_client client  )  [static]

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

02701 {
02702    int res = 0;
02703 
02704    if (client->state)
02705       client->state = AJI_DISCONNECTED;
02706    client->timeout=50;
02707    if (client->p)
02708       iks_parser_reset(client->p);
02709    if (client->authorized)
02710       client->authorized = 0;
02711 
02712    res = aji_initialize(client);
02713 
02714    return res;
02715 }

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

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

01102 {
01103    int len, ret;
01104    char buf[NET_IO_BUF_SIZE - 1];
01105    char newbuf[NET_IO_BUF_SIZE - 1];
01106    int pos = 0;
01107    int newbufpos = 0;
01108    unsigned char c;
01109 
01110    memset(buf, 0, sizeof(buf));
01111    memset(newbuf, 0, sizeof(newbuf));
01112 
01113    while (1) {
01114       len = aji_io_recv(client, buf, NET_IO_BUF_SIZE - 2, timeout);
01115       if (len < 0) return IKS_NET_RWERR;
01116       if (len == 0) return IKS_NET_EXPIRED;
01117       buf[len] = '\0';
01118 
01119       /* our iksemel parser won't work as expected if we feed
01120          it with XML packets that contain multiple whitespace 
01121          characters between tags */
01122       while (pos < len) {
01123          c = buf[pos];
01124          /* if we stumble on the ending tag character,
01125             we skip any whitespace that follows it*/
01126          if (c == '>') {
01127             while (isspace(buf[pos+1])) {
01128                pos++;
01129             }
01130          }
01131          newbuf[newbufpos] = c;
01132          newbufpos ++;
01133          pos++;
01134       }
01135       pos = 0;
01136       newbufpos = 0;
01137 
01138       /* Log the message here, because iksemel's logHook is 
01139          unaccessible */
01140       aji_log_hook(client, buf, len, 1);
01141 
01142       /* let iksemel deal with the string length, 
01143          and reset our buffer */
01144       ret = iks_parse(client->p, newbuf, 0, 0);
01145       memset(newbuf, 0, sizeof(newbuf));
01146 
01147       switch (ret) {
01148       case IKS_NOMEM:
01149          ast_log(LOG_WARNING, "Parsing failure: Out of memory.\n");
01150          break;
01151       case IKS_BADXML:
01152          ast_log(LOG_WARNING, "Parsing failure: Invalid XML.\n");
01153          break;
01154       case IKS_HOOK:
01155          ast_log(LOG_WARNING, "Parsing failure: Hook returned an error.\n");
01156          break;
01157       }
01158       if (ret != IKS_OK) {
01159          return ret;
01160       }
01161       ast_debug(3, "XML parsing successful\n"); 
01162    }
01163    return IKS_OK;
01164 }

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

Definition at line 2395 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, delete_old_messages_all(), IKS_NET_EXPIRED, aji_client::keepalive, LOG_ERROR, LOG_WARNING, aji_client::state, and aji_client::timeout.

Referenced by aji_reload().

02396 {
02397    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
02398    int res = IKS_HOOK;
02399 
02400    while(res != IKS_OK) {
02401       ast_debug(3, "JABBER: Connecting.\n");
02402       res = aji_reconnect(client);
02403       sleep(4);
02404    }
02405 
02406    do {
02407       if (res == IKS_NET_RWERR || client->timeout == 0) {
02408          while(res != IKS_OK) {
02409             ast_debug(3, "JABBER: reconnecting.\n");
02410             res = aji_reconnect(client);
02411             sleep(4);
02412          }
02413       }
02414 
02415       res = aji_recv(client, 1);
02416       
02417       if (client->state == AJI_DISCONNECTING) {
02418          ast_debug(2, "Ending our Jabber client's thread due to a disconnect\n");
02419          pthread_exit(NULL);
02420       }
02421 
02422       /* Decrease timeout if no data received, and delete
02423        * old messages globally */
02424       if (res == IKS_NET_EXPIRED) {
02425          client->timeout--;
02426          delete_old_messages_all(client);
02427       }
02428       if (res == IKS_HOOK) {
02429          ast_log(LOG_WARNING, "JABBER: Got hook event.\n");
02430       } else if (res == IKS_NET_TLSFAIL) {
02431          ast_log(LOG_ERROR, "JABBER:  Failure in TLS.\n");
02432       } else if (client->timeout == 0 && client->state == AJI_CONNECTED) {
02433          res = client->keepalive ? aji_send_raw(client, " ") : IKS_OK;
02434          if (res == IKS_OK) {
02435             client->timeout = 50;
02436          } else {
02437             ast_log(LOG_WARNING, "JABBER:  Network Timeout\n");
02438          }
02439       } else if (res == IKS_NET_RWERR) {
02440          ast_log(LOG_WARNING, "JABBER: socket read error\n");
02441       }
02442    } while (client);
02443    ASTOBJ_UNREF(client, aji_client_destroy);
02444    return 0;
02445 }

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

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

01531 {
01532    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01533    iks *iq = NULL, *presence = NULL, *x = NULL;
01534 
01535    iq = iks_new("iq");
01536    presence = iks_new("presence");
01537    x = iks_new("x");
01538    if (client && iq && presence && x) {
01539       if (!iks_find(pak->query, "remove")) {
01540          iks_insert_attrib(iq, "from", client->jid->full);
01541          iks_insert_attrib(iq, "to", pak->from->full);
01542          iks_insert_attrib(iq, "id", pak->id);
01543          iks_insert_attrib(iq, "type", "result");
01544          ast_aji_send(client, iq);
01545 
01546          iks_insert_attrib(presence, "from", client->jid->full);
01547          iks_insert_attrib(presence, "to", pak->from->partial);
01548          iks_insert_attrib(presence, "id", client->mid);
01549          ast_aji_increment_mid(client->mid);
01550          iks_insert_attrib(presence, "type", "subscribe");
01551          iks_insert_attrib(x, "xmlns", "vcard-temp:x:update");
01552          iks_insert_node(presence, x);
01553          ast_aji_send(client, presence); 
01554       }
01555    } else {
01556       ast_log(LOG_ERROR, "Out of memory.\n");
01557    }
01558 
01559 
01560    iks_delete(iq);
01561    iks_delete(presence);
01562    iks_delete(x);
01563    
01564    ASTOBJ_UNREF(client, aji_client_destroy);
01565    return IKS_FILTER_EAT;
01566 }

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

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

01575 {
01576    struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01577    struct aji_buddy *buddy = NULL; 
01578    char *node = NULL;
01579    iks *iq = NULL, *query = NULL;
01580 
01581    client = (struct aji_client *) data;
01582 
01583    buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01584    if (!buddy) {
01585       iks  *error = NULL, *notacceptable = NULL;
01586 
01587       ast_log(LOG_ERROR, "Someone.... %s tried to register but they aren't allowed\n", pak->from->partial);
01588       iq = iks_new("iq");
01589       query = iks_new("query");
01590       error = iks_new("error");
01591       notacceptable = iks_new("not-acceptable");
01592       if (iq && query && error && notacceptable) {
01593          iks_insert_attrib(iq, "type", "error");
01594          iks_insert_attrib(iq, "from", client->user);
01595          iks_insert_attrib(iq, "to", pak->from->full);
01596          iks_insert_attrib(iq, "id", pak->id);
01597          iks_insert_attrib(query, "xmlns", "jabber:iq:register");
01598          iks_insert_attrib(error, "code" , "406");
01599          iks_insert_attrib(error, "type", "modify");
01600          iks_insert_attrib(notacceptable, "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas");
01601          iks_insert_node(iq, query);
01602          iks_insert_node(iq, error);
01603          iks_insert_node(error, notacceptable);
01604          ast_aji_send(client, iq);
01605       } else {
01606          ast_log(LOG_ERROR, "Out of memory.\n");
01607       }
01608 
01609       iks_delete(error);
01610       iks_delete(notacceptable);
01611    } else   if (!(node = iks_find_attrib(pak->query, "node"))) {
01612       iks *instructions = NULL;
01613       char *explain = "Welcome to Asterisk - the Open Source PBX.\n";
01614       iq = iks_new("iq");
01615       query = iks_new("query");
01616       instructions = iks_new("instructions");
01617       if (iq && query && instructions && client) {
01618          iks_insert_attrib(iq, "from", client->user);
01619          iks_insert_attrib(iq, "to", pak->from->full);
01620          iks_insert_attrib(iq, "id", pak->id);
01621          iks_insert_attrib(iq, "type", "result");
01622          iks_insert_attrib(query, "xmlns", "jabber:iq:register");
01623          iks_insert_cdata(instructions, explain, 0);
01624          iks_insert_node(iq, query);
01625          iks_insert_node(query, instructions);
01626          ast_aji_send(client, iq);
01627       } else {
01628          ast_log(LOG_ERROR, "Out of memory.\n");
01629       }
01630 
01631       iks_delete(instructions);
01632    }
01633    iks_delete(iq);
01634    iks_delete(query);
01635    ASTOBJ_UNREF(client, aji_client_destroy);
01636    return IKS_FILTER_EAT;
01637 }

static int aji_reload ( int  reload  )  [static]

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

03461 {
03462    int res;
03463 
03464    ASTOBJ_CONTAINER_MARKALL(&clients);
03465    if (!(res = aji_load_config(reload))) {
03466       ast_log(LOG_ERROR, "JABBER: Failed to load config.\n");
03467       return 0;
03468    } else if (res == -1)
03469       return 1;
03470 
03471    ASTOBJ_CONTAINER_PRUNE_MARKED(&clients, aji_client_destroy);
03472    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
03473       ASTOBJ_RDLOCK(iterator);
03474       if (iterator->state == AJI_DISCONNECTED) {
03475          if (!iterator->thread)
03476             ast_pthread_create_background(&iterator->thread, NULL, aji_recv_loop, iterator);
03477       } else if (iterator->state == AJI_CONNECTING)
03478          aji_get_roster(iterator);
03479       ASTOBJ_UNLOCK(iterator);
03480    });
03481    
03482    return 1;
03483 }

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

Definition at line 919 of file res_jabber.c.

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

Referenced by load_module().

00920 {
00921    struct aji_client *client = NULL;
00922    char *s;
00923    AST_DECLARE_APP_ARGS(args,
00924       AST_APP_ARG(sender);
00925       AST_APP_ARG(recipient);
00926       AST_APP_ARG(message);
00927    );
00928 
00929    if (!data) {
00930       ast_log(LOG_WARNING, "%s requires arguments (account,jid,message)\n", app_ajisend);
00931       return -1;
00932    }
00933    s = ast_strdupa(data);
00934 
00935    AST_STANDARD_APP_ARGS(args, s);
00936    if (args.argc < 3) {
00937       ast_log(LOG_WARNING, "%s requires arguments (account,jid,message)\n", app_ajisend);
00938       return -1;
00939    }
00940 
00941    if (!(client = ast_aji_get_client(args.sender))) {
00942       ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
00943       return -1;
00944    }
00945    if (strchr(args.recipient, '@') && !ast_strlen_zero(args.message)) {
00946       ast_aji_send_chat(client, args.recipient, args.message);
00947    }
00948    return 0;
00949 }

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

Definition at line 1173 of file res_jabber.c.

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

Referenced by aji_act_hook().

01174 {
01175    char *msg;
01176    int len, err;
01177 
01178    len = 91 + strlen(client->name_space) + 6 + strlen(to) + 16 + 1;
01179    msg = iks_malloc(len);
01180    if (!msg)
01181       return IKS_NOMEM;
01182    sprintf(msg, "<?xml version='1.0'?>"
01183       "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='"
01184       "%s' to='%s' version='1.0'>", client->name_space, to);
01185    err = aji_send_raw(client, msg);
01186    iks_free(msg);
01187    if (err != IKS_OK)
01188       return err;
01189 
01190    return IKS_OK;
01191 }

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

Definition at line 1213 of file res_jabber.c.

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

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

01214 {
01215    int ret;
01216 #ifdef HAVE_OPENSSL
01217    int len = strlen(xmlstr);
01218 
01219    if (aji_is_secure(client)) {
01220       ret = SSL_write(client->ssl_session, xmlstr, len);
01221       if (ret) {
01222          /* Log the message here, because iksemel's logHook is 
01223             unaccessible */
01224          aji_log_hook(client, xmlstr, len, 0);
01225          return IKS_OK;
01226       }
01227    }
01228 #endif
01229    /* If needed, data will be sent unencrypted, and logHook will 
01230       be called inside iks_send_raw */
01231    ret = iks_send_raw(client->p, xmlstr);
01232    if (ret != IKS_OK)
01233       return ret; 
01234 
01235    return IKS_OK;
01236 }

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

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

02830 {
02831    int res = 0;
02832    iks *presence = iks_make_pres(level, desc);
02833    iks *cnode = iks_new("c");
02834    iks *priority = iks_new("priority");
02835    char priorityS[10];
02836 
02837    if (presence && cnode && client && priority) {
02838       if (to)
02839          iks_insert_attrib(presence, "to", to);
02840       if (from)
02841          iks_insert_attrib(presence, "from", from);
02842       snprintf(priorityS, sizeof(priorityS), "%d", client->priority);
02843       iks_insert_cdata(priority, priorityS, strlen(priorityS));
02844       iks_insert_node(presence, priority);
02845       iks_insert_attrib(cnode, "node", "http://www.asterisk.org/xmpp/client/caps");
02846       iks_insert_attrib(cnode, "ver", "asterisk-xmpp");
02847       iks_insert_attrib(cnode, "ext", "voice-v1");
02848       iks_insert_attrib(cnode, "xmlns", "http://jabber.org/protocol/caps");
02849       iks_insert_node(presence, cnode);
02850       res = ast_aji_send(client, presence);
02851    } else
02852       ast_log(LOG_ERROR, "Out of memory.\n");
02853 
02854    iks_delete(cnode);
02855    iks_delete(presence);
02856    iks_delete(priority);
02857 }

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

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

02975 {
02976    struct aji_resource *resource;
02977    struct aji_client *client;
02978 
02979    switch (cmd) {
02980    case CLI_INIT:
02981       e->command = "jabber show buddies";
02982       e->usage =
02983          "Usage: jabber show buddies\n"
02984          "       Shows buddy lists of our clients\n";
02985       return NULL;
02986    case CLI_GENERATE:
02987       return NULL;
02988    }
02989 
02990    ast_cli(a->fd, "Jabber buddy lists\n");
02991    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02992       ast_cli(a->fd,"Client: %s\n", iterator->user);
02993       client = iterator;
02994       ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02995          ASTOBJ_RDLOCK(iterator);
02996          ast_cli(a->fd,"\tBuddy:\t%s\n", iterator->name);
02997          if (!iterator->resources)
02998             ast_cli(a->fd,"\t\tResource: None\n");
02999          for (resource = iterator->resources; resource; resource = resource->next) {
03000             ast_cli(a->fd,"\t\tResource: %s\n", resource->resource);
03001             if (resource->cap) {
03002                ast_cli(a->fd,"\t\t\tnode: %s\n", resource->cap->parent->node);
03003                ast_cli(a->fd,"\t\t\tversion: %s\n", resource->cap->version);
03004                ast_cli(a->fd,"\t\t\tJingle capable: %s\n", resource->cap->jingle ? "yes" : "no");
03005             }
03006             ast_cli(a->fd,"\t\tStatus: %d\n", resource->status);
03007             ast_cli(a->fd,"\t\tPriority: %d\n", resource->priority);
03008          }
03009          ASTOBJ_UNLOCK(iterator);
03010       });
03011       iterator = client;
03012    });
03013    return CLI_SUCCESS;
03014 }

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

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

02929 {
02930    char *status;
02931    int count = 0;
02932    
02933    switch (cmd) {
02934    case CLI_INIT:
02935       e->command = "jabber show connected";
02936       e->usage =
02937          "Usage: jabber show connected\n"
02938          "       Shows state of clients and components\n";
02939       return NULL;
02940    case CLI_GENERATE:
02941       return NULL;
02942    }
02943 
02944    ast_cli(a->fd, "Jabber Users and their status:\n");
02945    ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02946       ASTOBJ_RDLOCK(iterator);
02947       count++;
02948       switch (iterator->state) {
02949       case AJI_DISCONNECTED:
02950          status = "Disconnected";
02951          break;
02952       case AJI_CONNECTING:
02953          status = "Connecting";
02954          break;
02955       case AJI_CONNECTED:
02956          status = "Connected";
02957          break;
02958       default:
02959          status = "Unknown";
02960       }
02961       ast_cli(a->fd, "       User: %s     - %s\n", iterator->user, status);
02962       ASTOBJ_UNLOCK(iterator);
02963    });
02964    ast_cli(a->fd, "----\n");
02965    ast_cli(a->fd, "   Number of users: %d\n", count);
02966    return CLI_SUCCESS;
02967 }

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

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

01280 {
01281    iks *x = NULL;
01282    int len;
01283    char *s;
01284    char *base64;
01285 
01286    /* trigger SASL DIGEST-MD5 only over an unsecured connection.
01287       iks_start_sasl is an iksemel API function and relies on GnuTLS,
01288       whereas we use OpenSSL */
01289    if ((type & IKS_STREAM_SASL_MD5) && !aji_is_secure(client))
01290       return iks_start_sasl(client->p, IKS_SASL_DIGEST_MD5, username, pass); 
01291    if (!(type & IKS_STREAM_SASL_PLAIN)) {
01292       ast_log(LOG_ERROR, "Server does not support SASL PLAIN authentication\n");
01293       return IKS_NET_NOTSUPP;
01294    }
01295 
01296    x = iks_new("auth"); 
01297    if (!x) {
01298       ast_log(LOG_ERROR, "Out of memory.\n");
01299       return IKS_NET_NOTSUPP;
01300    }
01301 
01302    iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_SASL);
01303    len = strlen(username) + strlen(pass) + 3;
01304    s = alloca(len);
01305    base64 = alloca((len + 2) * 4 / 3);
01306    iks_insert_attrib(x, "mechanism", "PLAIN");
01307    snprintf(s, len, "%c%s%c%s", 0, username, 0, pass);
01308 
01309    /* exclude the NULL training byte from the base64 encoding operation
01310       as some XMPP servers will refuse it.
01311       The format for authentication is [authzid]\0authcid\0password
01312       not [authzid]\0authcid\0password\0 */
01313    ast_base64encode(base64, (const unsigned char *) s, len - 1, (len + 2) * 4 / 3);
01314    iks_insert_cdata(x, base64, 0);
01315    ast_aji_send(client, x);
01316    iks_delete(x);
01317 
01318    return IKS_OK;
01319 }

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

Definition at line 559 of file res_jabber.c.

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

Referenced by load_module().

00560 {
00561    struct aji_client *client = NULL;
00562    struct aji_buddy *buddy = NULL;
00563    struct aji_resource *r = NULL;
00564    char *s = NULL;
00565    int stat = 7;
00566    char status[2];
00567    static int deprecation_warning = 0;
00568    AST_DECLARE_APP_ARGS(args,
00569       AST_APP_ARG(sender);
00570       AST_APP_ARG(jid);
00571       AST_APP_ARG(variable);
00572    );
00573    AST_DECLARE_APP_ARGS(jid,
00574       AST_APP_ARG(screenname);
00575       AST_APP_ARG(resource);
00576    );
00577 
00578    if (deprecation_warning++ % 10 == 0)
00579       ast_log(LOG_WARNING, "JabberStatus is deprecated.  Please use the JABBER_STATUS dialplan function in the future.\n");
00580 
00581    if (!data) {
00582       ast_log(LOG_ERROR, "Usage: JabberStatus(<sender>,<jid>[/<resource>],<varname>\n");
00583       return 0;
00584    }
00585    s = ast_strdupa(data);
00586    AST_STANDARD_APP_ARGS(args, s);
00587 
00588    if (args.argc != 3) {
00589       ast_log(LOG_ERROR, "JabberStatus() requires 3 arguments.\n");
00590       return -1;
00591    }
00592 
00593    AST_NONSTANDARD_APP_ARGS(jid, args.jid, '/');
00594    if (jid.argc < 1 || jid.argc > 2) {
00595       ast_log(LOG_WARNING, "Wrong JID %s, exiting\n", args.jid);
00596       return -1;
00597    }
00598 
00599    if (!(client = ast_aji_get_client(args.sender))) {
00600       ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
00601       return -1;
00602    }
00603    buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, jid.screenname);
00604    if (!buddy) {
00605       ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
00606       return -1;
00607    }
00608    r = aji_find_resource(buddy, jid.resource);
00609    if (!r && buddy->resources) 
00610       r = buddy->resources;
00611    if (!r)
00612       ast_log(LOG_NOTICE, "Resource '%s' of buddy '%s' was not found\n", jid.resource, jid.screenname);
00613    else
00614       stat = r->status;
00615    snprintf(status, sizeof(status), "%d", stat);
00616    pbx_builtin_setvar_helper(chan, args.variable, status);
00617    return 0;
00618 }

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

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

03022 {
03023    struct aji_client *client;
03024    struct aji_resource *resource;
03025    const char *name = "asterisk";
03026    struct aji_message *tmp;
03027 
03028    switch (cmd) {
03029    case CLI_INIT:
03030       e->command = "jabber test";
03031       e->usage =
03032          "Usage: jabber test [client]\n"
03033          "       Sends test message for debugging purposes.  A specific client\n"
03034          "       as configured in jabber.conf can be optionally specified.\n";
03035       return NULL;
03036    case CLI_GENERATE:
03037       return NULL;
03038    }
03039 
03040    if (a->argc > 3)
03041       return CLI_SHOWUSAGE;
03042    else if (a->argc == 3)
03043       name = a->argv[2];
03044 
03045    if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
03046       ast_cli(a->fd, "Unable to find client '%s'!\n", name);
03047       return CLI_FAILURE;
03048    }
03049 
03050    /* XXX Does Matt really want everyone to use his personal address for tests? */ /* XXX yes he does */
03051    ast_aji_send_chat(client, "mogorman@astjab.org", "blahblah");
03052    ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
03053       ASTOBJ_RDLOCK(iterator);
03054       ast_verbose("User: %s\n", iterator->name);
03055       for (resource = iterator->resources; resource; resource = resource->next) {
03056          ast_verbose("Resource: %s\n", resource->resource);
03057          if (resource->cap) {
03058             ast_verbose("   client: %s\n", resource->cap->parent->node);
03059             ast_verbose("   version: %s\n", resource->cap->version);
03060             ast_verbose("   Jingle Capable: %d\n", resource->cap->jingle);
03061          }
03062          ast_verbose("  Priority: %d\n", resource->priority);
03063          ast_verbose("  Status: %d\n", resource->status);
03064          ast_verbose("  Message: %s\n", S_OR(resource->description,""));
03065       }
03066       ASTOBJ_UNLOCK(iterator);
03067    });
03068    ast_verbose("\nOooh a working message stack!\n");
03069    AST_LIST_LOCK(&client->messages);
03070    AST_LIST_TRAVERSE(&client->messages, tmp, list) {
03071       //ast_verbose("   Message from: %s with id %s @ %s %s\n",tmp->from, S_OR(tmp->id,""), ctime(&tmp->arrived), S_OR(tmp->message, ""));
03072    }
03073    AST_LIST_UNLOCK(&client->messages);
03074    ASTOBJ_UNREF(client, aji_client_destroy);
03075 
03076    return CLI_SUCCESS;
03077 }

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

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

02305 {
02306    int res = 0;
02307    iks *iq = NULL;
02308    iq = iks_new("iq");
02309 
02310    if (iq && client) {
02311       iks_insert_attrib(iq, "type", "get");
02312       iks_insert_attrib(iq, "to", server);
02313       iks_insert_attrib(iq, "id", client->mid);
02314       ast_aji_increment_mid(client->mid);
02315       ast_aji_send(client, iq);
02316    } else 
02317       ast_log(LOG_ERROR, "Out of memory.\n");
02318 
02319    iks_delete(iq);
02320 
02321    return res;
02322 }

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

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

Referenced by unload_module().

02801 {
02802    if (client) {
02803       ast_verb(4, "JABBER: Disconnecting\n");
02804 #ifdef HAVE_OPENSSL
02805       if (client->stream_flags & SECURE) {
02806          SSL_shutdown(client->ssl_session);
02807          SSL_CTX_free(client->ssl_context);
02808          SSL_free(client->ssl_session);
02809       }
02810 #endif
02811       iks_disconnect(client->p);
02812       iks_parser_delete(client->p);
02813       ASTOBJ_UNREF(client, aji_client_destroy);
02814    }
02815 
02816    return 1;
02817 }

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

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

Referenced by acf_jabberreceive_read(), 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().

03383 {
03384    struct aji_client *client = NULL;
03385    char *aux = NULL;
03386 
03387    client = ASTOBJ_CONTAINER_FIND(&clients, name);
03388    if (!client && strchr(name, '@')) {
03389       ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
03390          aux = ast_strdupa(iterator->user);
03391          if (strchr(aux, '/')) {
03392             /* strip resource for comparison */
03393             aux = strsep(&aux, "/");
03394          }
03395          if (!strncasecmp(aux, name, strlen(aux))) {
03396             client = iterator;
03397          }           
03398       });
03399    }
03400 
03401    return client;
03402 }

struct aji_client_container* ast_aji_get_clients ( void   )  [read]

Definition at line 3404 of file res_jabber.c.

References clients.

Referenced by gtalk_load_config(), and jingle_load_config().

03405 {
03406    return &clients;
03407 }

void ast_aji_increment_mid ( char *  mid  ) 

increments the mid field for messages and other events.

Parameters:
mid char.
Returns:
void.

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

02453 {
02454    int i = 0;
02455 
02456    for (i = strlen(mid) - 1; i >= 0; i--) {
02457       if (mid[i] != 'z') {
02458          mid[i] = mid[i] + 1;
02459          i = 0;
02460       } else
02461          mid[i] = 'a';
02462    }
02463 }

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

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

02362 {
02363    int res = 0;
02364    iks *invite, *body, *namespace;
02365 
02366    invite = iks_new("message");
02367    body = iks_new("body");
02368    namespace = iks_new("x");
02369    if (client && invite && body && namespace) {
02370       iks_insert_attrib(invite, "to", user);
02371       iks_insert_attrib(invite, "id", client->mid);
02372       ast_aji_increment_mid(client->mid);
02373       iks_insert_cdata(body, message, 0);
02374       iks_insert_attrib(namespace, "xmlns", "jabber:x:conference");
02375       iks_insert_attrib(namespace, "jid", room);
02376       iks_insert_node(invite, body);
02377       iks_insert_node(invite, namespace);
02378       res = ast_aji_send(client, invite);
02379    } else 
02380       ast_log(LOG_ERROR, "Out of memory.\n");
02381 
02382    iks_delete(body);
02383    iks_delete(namespace);
02384    iks_delete(invite);
02385    
02386    return res;
02387 }

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

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

02331 {
02332    int res = 0;
02333    iks *presence = NULL, *priority = NULL;
02334    presence = iks_new("presence");
02335    priority = iks_new("priority");
02336    if (presence && priority && client) {
02337       iks_insert_cdata(priority, "0", 1);
02338       iks_insert_attrib(presence, "to", room);
02339       iks_insert_node(presence, priority);
02340       res = ast_aji_send(client, presence);
02341       iks_insert_cdata(priority, "5", 1);
02342       iks_insert_attrib(presence, "to", room);
02343       res = ast_aji_send(client, presence);
02344    } else 
02345       ast_log(LOG_ERROR, "Out of memory.\n");
02346    
02347    iks_delete(presence);
02348    iks_delete(priority);
02349    
02350    return res;
02351 }

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 
Return values:
IKS_OK success
-1 failure

Definition at line 2273 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(), gtalk_sendtext(), jingle_sendtext(), and manager_jabber_send().

02274 {
02275    int res = 0;
02276    iks *message_packet = NULL;
02277 
02278    if (client->state != AJI_CONNECTED) {
02279       ast_log(LOG_WARNING, "JABBER: Not connected can't send\n");
02280       return -1;
02281    }
02282 
02283    message_packet = iks_make_msg(IKS_TYPE_CHAT, address, message);
02284    if (!message_packet) {
02285       ast_log(LOG_ERROR, "Out of memory.\n");
02286       return -1;
02287    }
02288 
02289    iks_insert_attrib(message_packet, "from", client->jid->full);
02290    res = ast_aji_send(client, message_packet);
02291    iks_delete(message_packet);
02292 
02293    return res;
02294 }

static int delete_old_messages ( struct aji_client client,
char *  from 
) [static]

Definition at line 859 of file res_jabber.c.

References aji_message_destroy(), aji_message::arrived, AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_tvdiff_sec(), ast_tvnow(), aji_message::from, aji_message::list, LOG_ERROR, aji_client::message_timeout, and aji_client::messages.

Referenced by aji_handle_message(), and delete_old_messages_all().

00860 {
00861    int deleted = 0;
00862    int isold = 0;
00863    struct aji_message *tmp = NULL;
00864    if (!client) {
00865       ast_log(LOG_ERROR, "Cannot find our XMPP client\n");
00866       return -1;
00867    }
00868 
00869    /* remove old messages */
00870    AST_LIST_LOCK(&client->messages);
00871    if (AST_LIST_EMPTY(&client->messages)) {
00872       AST_LIST_UNLOCK(&client->messages);
00873       return 0;
00874    }
00875 
00876    AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, tmp, list) {
00877       if (isold) {
00878          if (!from || !strncasecmp(from, tmp->from, strlen(from))) {
00879             AST_LIST_REMOVE_CURRENT(list);
00880             aji_message_destroy(tmp);
00881             deleted ++;
00882          }
00883       } else if (ast_tvdiff_sec(ast_tvnow(), tmp->arrived) >= client->message_timeout) {
00884          isold = 1;
00885          if (!from || !strncasecmp(from, tmp->from, strlen(from))) {
00886             AST_LIST_REMOVE_CURRENT(list);
00887             aji_message_destroy(tmp);
00888             deleted ++;
00889          }
00890       }
00891    }
00892    AST_LIST_TRAVERSE_SAFE_END;
00893    AST_LIST_UNLOCK(&client->messages);
00894 
00895    return deleted;
00896 }

static int delete_old_messages_all ( struct aji_client client  )  [static]

Definition at line 906 of file res_jabber.c.

References delete_old_messages().

Referenced by aji_recv_loop().

00907 {
00908    return delete_old_messages(client, NULL);
00909 }

static int gtalk_yuck ( iks *  node  )  [static]

Definition at line 514 of file res_jabber.c.

Referenced by aji_handle_presence().

00515 {
00516    if (iks_find_with_attrib(node, "c", "node", "http://www.google.com/xmpp/client/caps"))
00517       return 1;
00518    return 0;
00519 }

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

Definition at line 529 of file res_jabber.c.

References ast_sha1_hash(), and buf.

Referenced by aji_act_hook().

00530 {
00531    iks *x, *y;
00532    x = iks_new("iq");
00533    iks_insert_attrib(x, "type", "set");
00534    y = iks_insert(x, "query");
00535    iks_insert_attrib(y, "xmlns", IKS_NS_AUTH);
00536    iks_insert_cdata(iks_insert(y, "username"), id->user, 0);
00537    iks_insert_cdata(iks_insert(y, "resource"), id->resource, 0);
00538    if (sid) {
00539       char buf[41];
00540       char sidpass[100];
00541       snprintf(sidpass, sizeof(sidpass), "%s%s", sid, pass);
00542       ast_sha1_hash(buf, sidpass);
00543       iks_insert_cdata(iks_insert(y, "digest"), buf, 0);
00544    } else {
00545       iks_insert_cdata(iks_insert(y, "password"), pass, 0);
00546    }
00547    return x;
00548 }

static int load_module ( void   )  [static]

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

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

03417 {
03418    struct aji_client *client = NULL;
03419    const char *id = astman_get_header(m,"ActionID");
03420    const char *jabber = astman_get_header(m,"Jabber");
03421    const char *screenname = astman_get_header(m,"ScreenName");
03422    const char *message = astman_get_header(m,"Message");
03423 
03424    if (ast_strlen_zero(jabber)) {
03425       astman_send_error(s, m, "No transport specified");
03426       return 0;
03427    }
03428    if (ast_strlen_zero(screenname)) {
03429       astman_send_error(s, m, "No ScreenName specified");
03430       return 0;
03431    }
03432    if (ast_strlen_zero(message)) {
03433       astman_send_error(s, m, "No Message specified");
03434       return 0;
03435    }
03436 
03437    astman_send_ack(s, m, "Attempting to send Jabber Message");
03438    client = ast_aji_get_client(jabber);
03439    if (!client) {
03440       astman_send_error(s, m, "Could not find Sender");
03441       return 0;
03442    }
03443    if (strchr(screenname, '@') && message) {
03444       ast_aji_send_chat(client, screenname, message);
03445       astman_append(s, "Response: Success\r\n");
03446    } else {
03447       astman_append(s, "Response: Error\r\n");
03448    }
03449    if (!ast_strlen_zero(id)) {
03450       astman_append(s, "ActionID: %s\r\n",id);
03451    }
03452    astman_append(s, "\r\n");
03453    return 0;
03454 }

static int reload ( void   )  [static]

Definition at line 3542 of file res_jabber.c.

References aji_reload().

03543 {
03544    aji_reload(1);
03545    return 0;
03546 }

static int unload_module ( void   )  [static]


Variable Documentation

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

Definition at line 3552 of file res_jabber.c.

struct ast_cli_entry aji_cli[] [static]

Definition at line 336 of file res_jabber.c.

char* app_ajisend = "JabberSend" [static]

Definition at line 344 of file res_jabber.c.

char* app_ajistatus = "JabberStatus" [static]

Definition at line 346 of file res_jabber.c.

Definition at line 3552 of file res_jabber.c.

struct aji_capabilities* capabilities = NULL [static]

Definition at line 349 of file res_jabber.c.

Referenced by ast_request().

struct aji_client_container clients [static]

struct ast_flags globalflags = { AJI_AUTOREGISTER } [static]

Global flags, initialized to default values.

Definition at line 354 of file res_jabber.c.

Initial value:

 {
   .name = "JABBER_RECEIVE",
   .read = acf_jabberreceive_read,
}

Definition at line 845 of file res_jabber.c.

Initial value:

 {
   .name = "JABBER_STATUS",
   .read = acf_jabberstatus_read,
}

Definition at line 681 of file res_jabber.c.

Definition at line 350 of file res_jabber.c.

Definition at line 351 of file res_jabber.c.


Generated on Wed Oct 28 13:33:29 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6