00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include "asterisk.h"
00039
00040 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 153710 $")
00041
00042 #include <ctype.h>
00043 #include <iksemel.h>
00044
00045 #include "asterisk/channel.h"
00046 #include "asterisk/jabber.h"
00047 #include "asterisk/file.h"
00048 #include "asterisk/config.h"
00049 #include "asterisk/callerid.h"
00050 #include "asterisk/lock.h"
00051 #include "asterisk/cli.h"
00052 #include "asterisk/app.h"
00053 #include "asterisk/pbx.h"
00054 #include "asterisk/md5.h"
00055 #include "asterisk/acl.h"
00056 #include "asterisk/utils.h"
00057 #include "asterisk/module.h"
00058 #include "asterisk/astobj.h"
00059 #include "asterisk/astdb.h"
00060 #include "asterisk/manager.h"
00061
00062
00063
00064 #define JABBER_CONFIG "jabber.conf"
00065
00066 #ifndef FALSE
00067 #define FALSE 0
00068 #endif
00069
00070 #ifndef TRUE
00071 #define TRUE 1
00072 #endif
00073
00074
00075 static void aji_buddy_destroy(struct aji_buddy *obj);
00076 static void aji_client_destroy(struct aji_client *obj);
00077 static int aji_send_exec(struct ast_channel *chan, void *data);
00078 static int aji_status_exec(struct ast_channel *chan, void *data);
00079 static int aji_is_secure(struct aji_client *client);
00080 #ifdef HAVE_OPENSSL
00081 static int aji_start_tls(struct aji_client *client);
00082 static int aji_tls_handshake(struct aji_client *client);
00083 #endif
00084 static int aji_io_recv(struct aji_client *client, char *buffer, size_t buf_len, int timeout);
00085 static int aji_recv(struct aji_client *client, int timeout);
00086 static int aji_send_header(struct aji_client *client, const char *to);
00087 static int aji_send_raw(struct aji_client *client, const char *xmlstr);
00088 static void aji_log_hook(void *data, const char *xmpp, size_t size, int is_incoming);
00089 static int aji_start_sasl(struct aji_client *client, enum ikssasltype type, char *username, char *pass);
00090 static int aji_act_hook(void *data, int type, iks *node);
00091 static void aji_handle_iq(struct aji_client *client, iks *node);
00092 static void aji_handle_message(struct aji_client *client, ikspak *pak);
00093 static void aji_handle_presence(struct aji_client *client, ikspak *pak);
00094 static void aji_handle_subscribe(struct aji_client *client, ikspak *pak);
00095 static void *aji_recv_loop(void *data);
00096 static int aji_initialize(struct aji_client *client);
00097 static int aji_client_connect(void *data, ikspak *pak);
00098 static void aji_set_presence(struct aji_client *client, char *to, char *from, int level, char *desc);
00099 static char *aji_do_debug_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
00100 static char *aji_do_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
00101 static char *aji_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
00102 static char *aji_show_clients(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
00103 static char *aji_show_buddies(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
00104 static char *aji_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
00105 static int aji_create_client(char *label, struct ast_variable *var, int debug);
00106 static int aji_create_buddy(char *label, struct aji_client *client);
00107 static int aji_reload(int reload);
00108 static int aji_load_config(int reload);
00109 static void aji_pruneregister(struct aji_client *client);
00110 static int aji_filter_roster(void *data, ikspak *pak);
00111 static int aji_get_roster(struct aji_client *client);
00112 static int aji_client_info_handler(void *data, ikspak *pak);
00113 static int aji_dinfo_handler(void *data, ikspak *pak);
00114 static int aji_ditems_handler(void *data, ikspak *pak);
00115 static int aji_register_query_handler(void *data, ikspak *pak);
00116 static int aji_register_approve_handler(void *data, ikspak *pak);
00117 static int aji_reconnect(struct aji_client *client);
00118 static iks *jabber_make_auth(iksid * id, const char *pass, const char *sid);
00119
00120
00121
00122
00123
00124
00125
00126 static struct ast_cli_entry cli_aji_do_debug_deprecated = AST_CLI_DEFINE(aji_do_debug_deprecated, "Enable/disable jabber debugging");
00127 static struct ast_cli_entry aji_cli[] = {
00128 AST_CLI_DEFINE(aji_do_set_debug, "Enable/Disable Jabber debug", .deprecate_cmd = &cli_aji_do_debug_deprecated),
00129 AST_CLI_DEFINE(aji_do_reload, "Reload Jabber configuration"),
00130 AST_CLI_DEFINE(aji_show_clients, "Show state of clients and components"),
00131 AST_CLI_DEFINE(aji_show_buddies, "Show buddy lists of our clients"),
00132 AST_CLI_DEFINE(aji_test, "Shows roster, but is generally used for mog's debugging."),
00133 };
00134
00135 static char *app_ajisend = "JabberSend";
00136
00137 static char *ajisend_synopsis = "JabberSend(jabber,screenname,message)";
00138
00139 static char *ajisend_descrip =
00140 "JabberSend(Jabber,ScreenName,Message)\n"
00141 " Jabber - Client or transport Asterisk uses to connect to Jabber\n"
00142 " ScreenName - XMPP/Jabber JID (Name) of recipient\n"
00143 " Message - Message to be sent to the budd (UTF8)y\n";
00144
00145 static char *app_ajistatus = "JabberStatus";
00146
00147 static char *ajistatus_synopsis = "JabberStatus(Jabber,ScreenName,Variable)";
00148
00149 static char *ajistatus_descrip =
00150 "JabberStatus(Jabber,ScreenName,Variable)\n"
00151 " Jabber - Client or transport Asterisk uses to connect to Jabber\n"
00152 " ScreenName - User Name to retrieve status from.\n"
00153 " Variable - Variable to store presence in will be 1-6.\n"
00154 " In order, 1=Online, 2=Chatty, 3=Away, 4=XAway, 5=DND, 6=Offline\n"
00155 " If not in roster variable will be set to 7\n\n"
00156 "Note: This application is deprecated. Please use the JABBER_STATUS() function instead.\n";
00157
00158 struct aji_client_container clients;
00159 struct aji_capabilities *capabilities = NULL;
00160
00161
00162 static struct ast_flags globalflags = { AJI_AUTOPRUNE | AJI_AUTOREGISTER };
00163
00164
00165
00166
00167
00168
00169 static void aji_client_destroy(struct aji_client *obj)
00170 {
00171 struct aji_message *tmp;
00172 ASTOBJ_CONTAINER_DESTROYALL(&obj->buddies, aji_buddy_destroy);
00173 ASTOBJ_CONTAINER_DESTROY(&obj->buddies);
00174 iks_filter_delete(obj->f);
00175 iks_parser_delete(obj->p);
00176 iks_stack_delete(obj->stack);
00177 AST_LIST_LOCK(&obj->messages);
00178 while ((tmp = AST_LIST_REMOVE_HEAD(&obj->messages, list))) {
00179 if (tmp->from)
00180 ast_free(tmp->from);
00181 if (tmp->message)
00182 ast_free(tmp->message);
00183 }
00184 AST_LIST_HEAD_DESTROY(&obj->messages);
00185 ast_free(obj);
00186 }
00187
00188
00189
00190
00191
00192
00193 static void aji_buddy_destroy(struct aji_buddy *obj)
00194 {
00195 struct aji_resource *tmp;
00196
00197 while ((tmp = obj->resources)) {
00198 obj->resources = obj->resources->next;
00199 ast_free(tmp->description);
00200 ast_free(tmp);
00201 }
00202
00203 ast_free(obj);
00204 }
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215 static struct aji_version *aji_find_version(char *node, char *version, ikspak *pak)
00216 {
00217 struct aji_capabilities *list = NULL;
00218 struct aji_version *res = NULL;
00219
00220 list = capabilities;
00221
00222 if(!node)
00223 node = pak->from->full;
00224 if(!version)
00225 version = "none supplied.";
00226 while(list) {
00227 if(!strcasecmp(list->node, node)) {
00228 res = list->versions;
00229 while(res) {
00230 if(!strcasecmp(res->version, version))
00231 return res;
00232 res = res->next;
00233 }
00234
00235
00236 if(!res) {
00237 res = ast_malloc(sizeof(*res));
00238 if(!res) {
00239 ast_log(LOG_ERROR, "Out of memory!\n");
00240 return NULL;
00241 }
00242 res->jingle = 0;
00243 res->parent = list;
00244 ast_copy_string(res->version, version, sizeof(res->version));
00245 res->next = list->versions;
00246 list->versions = res;
00247 return res;
00248 }
00249 }
00250 list = list->next;
00251 }
00252
00253 if(!list) {
00254 list = ast_malloc(sizeof(*list));
00255 if(!list) {
00256 ast_log(LOG_ERROR, "Out of memory!\n");
00257 return NULL;
00258 }
00259 res = ast_malloc(sizeof(*res));
00260 if(!res) {
00261 ast_log(LOG_ERROR, "Out of memory!\n");
00262 ast_free(list);
00263 return NULL;
00264 }
00265 ast_copy_string(list->node, node, sizeof(list->node));
00266 ast_copy_string(res->version, version, sizeof(res->version));
00267 res->jingle = 0;
00268 res->parent = list;
00269 res->next = NULL;
00270 list->versions = res;
00271 list->next = capabilities;
00272 capabilities = list;
00273 }
00274 return res;
00275 }
00276
00277
00278
00279
00280
00281
00282 static struct aji_resource *aji_find_resource(struct aji_buddy *buddy, char *name)
00283 {
00284 struct aji_resource *res = NULL;
00285 if (!buddy || !name)
00286 return res;
00287 res = buddy->resources;
00288 while (res) {
00289 if (!strcasecmp(res->resource, name)) {
00290 break;
00291 }
00292 res = res->next;
00293 }
00294 return res;
00295 }
00296
00297
00298
00299
00300
00301
00302 static int gtalk_yuck(iks *node)
00303 {
00304 if (iks_find_with_attrib(node, "c", "node", "http://www.google.com/xmpp/client/caps"))
00305 return 1;
00306 return 0;
00307 }
00308
00309
00310
00311
00312
00313
00314
00315
00316 static iks *jabber_make_auth(iksid * id, const char *pass, const char *sid)
00317 {
00318 iks *x, *y;
00319 x = iks_new("iq");
00320 iks_insert_attrib(x, "type", "set");
00321 y = iks_insert(x, "query");
00322 iks_insert_attrib(y, "xmlns", IKS_NS_AUTH);
00323 iks_insert_cdata(iks_insert(y, "username"), id->user, 0);
00324 iks_insert_cdata(iks_insert(y, "resource"), id->resource, 0);
00325 if (sid) {
00326 char buf[41];
00327 char sidpass[100];
00328 snprintf(sidpass, sizeof(sidpass), "%s%s", sid, pass);
00329 ast_sha1_hash(buf, sidpass);
00330 iks_insert_cdata(iks_insert(y, "digest"), buf, 0);
00331 } else {
00332 iks_insert_cdata(iks_insert(y, "password"), pass, 0);
00333 }
00334 return x;
00335 }
00336
00337
00338
00339
00340
00341
00342
00343
00344 static int aji_status_exec(struct ast_channel *chan, void *data)
00345 {
00346 struct aji_client *client = NULL;
00347 struct aji_buddy *buddy = NULL;
00348 struct aji_resource *r = NULL;
00349 char *s = NULL;
00350 int stat = 7;
00351 char status[2];
00352 static int deprecation_warning = 0;
00353 AST_DECLARE_APP_ARGS(args,
00354 AST_APP_ARG(sender);
00355 AST_APP_ARG(jid);
00356 AST_APP_ARG(variable);
00357 );
00358 AST_DECLARE_APP_ARGS(jid,
00359 AST_APP_ARG(screenname);
00360 AST_APP_ARG(resource);
00361 );
00362
00363 if (deprecation_warning++ % 10 == 0)
00364 ast_log(LOG_WARNING, "JabberStatus is deprecated. Please use the JABBER_STATUS dialplan function in the future.\n");
00365
00366 if (!data) {
00367 ast_log(LOG_ERROR, "Usage: JabberStatus(<sender>,<screenname>[/<resource>],<varname>\n");
00368 return 0;
00369 }
00370 s = ast_strdupa(data);
00371 AST_STANDARD_APP_ARGS(args, s);
00372
00373 if (args.argc != 3) {
00374 ast_log(LOG_ERROR, "JabberStatus() requires 3 arguments.\n");
00375 return -1;
00376 }
00377
00378 AST_NONSTANDARD_APP_ARGS(jid, args.jid, '/');
00379
00380 if (!(client = ast_aji_get_client(args.sender))) {
00381 ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
00382 return -1;
00383 }
00384 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, jid.screenname);
00385 if (!buddy) {
00386 ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
00387 return -1;
00388 }
00389 r = aji_find_resource(buddy, jid.resource);
00390 if (!r && buddy->resources)
00391 r = buddy->resources;
00392 if (!r)
00393 ast_log(LOG_NOTICE, "Resource '%s' of buddy '%s' was not found\n", jid.resource, jid.screenname);
00394 else
00395 stat = r->status;
00396 snprintf(status, sizeof(status), "%d", stat);
00397 pbx_builtin_setvar_helper(chan, args.variable, status);
00398 return 0;
00399 }
00400
00401 static int acf_jabberstatus_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
00402 {
00403 struct aji_client *client = NULL;
00404 struct aji_buddy *buddy = NULL;
00405 struct aji_resource *r = NULL;
00406 int stat = 7;
00407 AST_DECLARE_APP_ARGS(args,
00408 AST_APP_ARG(sender);
00409 AST_APP_ARG(jid);
00410 );
00411 AST_DECLARE_APP_ARGS(jid,
00412 AST_APP_ARG(screenname);
00413 AST_APP_ARG(resource);
00414 );
00415
00416 if (!data) {
00417 ast_log(LOG_ERROR, "Usage: JABBER_STATUS(<sender>,<jid>[/<resource>])\n");
00418 return 0;
00419 }
00420 AST_STANDARD_APP_ARGS(args, data);
00421
00422 if (args.argc != 2) {
00423 ast_log(LOG_ERROR, "JABBER_STATUS requires 2 arguments: sender and jid.\n");
00424 return -1;
00425 }
00426
00427 AST_NONSTANDARD_APP_ARGS(jid, args.jid, '/');
00428
00429 if (!(client = ast_aji_get_client(args.sender))) {
00430 ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
00431 return -1;
00432 }
00433 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, jid.screenname);
00434 if (!buddy) {
00435 ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
00436 return -1;
00437 }
00438 r = aji_find_resource(buddy, jid.resource);
00439 if (!r && buddy->resources)
00440 r = buddy->resources;
00441 if (!r)
00442 ast_log(LOG_NOTICE, "Resource %s of buddy %s was not found.\n", jid.resource, jid.screenname);
00443 else
00444 stat = r->status;
00445 snprintf(buf, buflen, "%d", stat);
00446 return 0;
00447 }
00448
00449 static struct ast_custom_function jabberstatus_function = {
00450 .name = "JABBER_STATUS",
00451 .synopsis = "Retrieve buddy status",
00452 .syntax = "JABBER_STATUS(<sender>,<buddy>[/<resource>])",
00453 .read = acf_jabberstatus_read,
00454 .desc =
00455 "Retrieves the numeric status associated with the specified buddy (jid). If the\n"
00456 "buddy does not exist in the buddylist, returns 7.\n"
00457 "Status will be 1-7.\n"
00458 " 1=Online, 2=Chatty, 3=Away, 4=XAway, 5=DND, 6=Offline\n"
00459 " If not in roster variable will be set to 7\n\n",
00460 };
00461
00462
00463
00464
00465
00466
00467
00468 static int aji_send_exec(struct ast_channel *chan, void *data)
00469 {
00470 struct aji_client *client = NULL;
00471 char *s;
00472 AST_DECLARE_APP_ARGS(args,
00473 AST_APP_ARG(sender);
00474 AST_APP_ARG(recipient);
00475 AST_APP_ARG(message);
00476 );
00477
00478 if (!data) {
00479 ast_log(LOG_ERROR, "Usage: JabberSend(<sender>,<recipient>,<message>)\n");
00480 return 0;
00481 }
00482 s = ast_strdupa(data);
00483
00484 AST_STANDARD_APP_ARGS(args, s);
00485 if (args.argc < 3) {
00486 ast_log(LOG_ERROR, "JabberSend requires 3 arguments: '%s'\n", (char *) data);
00487 return -1;
00488 }
00489
00490 if (!(client = ast_aji_get_client(args.sender))) {
00491 ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
00492 return -1;
00493 }
00494 if (strchr(args.recipient, '@') && !ast_strlen_zero(args.message))
00495 ast_aji_send_chat(client, args.recipient, args.message);
00496 return 0;
00497 }
00498
00499
00500
00501
00502
00503 static int aji_is_secure(struct aji_client *client)
00504 {
00505 #ifdef HAVE_OPENSSL
00506 return client->stream_flags & SECURE;
00507 #else
00508 return 0;
00509 #endif
00510 }
00511
00512 #ifdef HAVE_OPENSSL
00513
00514
00515
00516
00517
00518
00519 static int aji_start_tls(struct aji_client *client)
00520 {
00521 int ret;
00522
00523
00524 ret = iks_send_raw(client->p, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
00525 if (ret)
00526 return ret;
00527
00528 client->stream_flags |= TRY_SECURE;
00529 return IKS_OK;
00530 }
00531
00532
00533
00534
00535
00536
00537 static int aji_tls_handshake(struct aji_client *client)
00538 {
00539 int ret;
00540 int sock;
00541
00542 ast_debug(1, "Starting TLS handshake\n");
00543
00544
00545 SSL_library_init();
00546 SSL_load_error_strings();
00547
00548
00549 client->ssl_method = SSLv3_method();
00550 client->ssl_context = SSL_CTX_new(client->ssl_method);
00551 if (!client->ssl_context)
00552 return IKS_NET_TLSFAIL;
00553
00554
00555 client->ssl_session = SSL_new(client->ssl_context);
00556 if (!client->ssl_session)
00557 return IKS_NET_TLSFAIL;
00558
00559
00560 sock = iks_fd(client->p);
00561 ret = SSL_set_fd(client->ssl_session, sock);
00562 if (!ret)
00563 return IKS_NET_TLSFAIL;
00564
00565
00566 ret = SSL_connect(client->ssl_session);
00567 if (!ret)
00568 return IKS_NET_TLSFAIL;
00569
00570 client->stream_flags &= (~TRY_SECURE);
00571 client->stream_flags |= SECURE;
00572
00573
00574 ret = aji_send_header(client, client->jid->server);
00575 if (ret != IKS_OK)
00576 return IKS_NET_TLSFAIL;
00577
00578 ast_debug(1, "TLS started with server\n");
00579
00580 return IKS_OK;
00581 }
00582 #endif
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593 static int aji_io_recv(struct aji_client *client, char *buffer, size_t buf_len, int timeout)
00594 {
00595 int sock;
00596 fd_set fds;
00597 struct timeval tv, *tvptr = NULL;
00598 int len, res;
00599
00600 #ifdef HAVE_OPENSSL
00601 if (aji_is_secure(client)) {
00602 sock = SSL_get_fd(client->ssl_session);
00603 if (sock < 0)
00604 return -1;
00605 } else
00606 #endif
00607 sock = iks_fd(client->p);
00608
00609 memset(&tv, 0, sizeof(struct timeval));
00610 FD_ZERO(&fds);
00611 FD_SET(sock, &fds);
00612 tv.tv_sec = timeout;
00613
00614
00615 tvptr = (timeout != -1) ? &tv : NULL;
00616
00617
00618 res = ast_select(sock + 1, &fds, NULL, NULL, tvptr);
00619 if (res > 0) {
00620 #ifdef HAVE_OPENSSL
00621 if (aji_is_secure(client)) {
00622 len = SSL_read(client->ssl_session, buffer, buf_len);
00623 } else
00624 #endif
00625 len = recv(sock, buffer, buf_len, 0);
00626
00627 if (len > 0) {
00628 return len;
00629 } else if (len <= 0) {
00630 return -1;
00631 }
00632 }
00633 return res;
00634 }
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645 static int aji_recv (struct aji_client *client, int timeout)
00646 {
00647 int len, ret;
00648 char buf[NET_IO_BUF_SIZE -1];
00649 char newbuf[NET_IO_BUF_SIZE -1];
00650 int pos = 0;
00651 int newbufpos = 0;
00652 unsigned char c;
00653
00654 memset(buf, 0, sizeof(buf));
00655 memset(newbuf, 0, sizeof(newbuf));
00656
00657 while (1) {
00658 len = aji_io_recv(client, buf, NET_IO_BUF_SIZE - 1, timeout);
00659 if (len < 0) return IKS_NET_RWERR;
00660 if (len == 0) return IKS_NET_EXPIRED;
00661 buf[len] = '\0';
00662
00663
00664
00665
00666 while (pos < len) {
00667 c = buf[pos];
00668
00669
00670 if (c == '>') {
00671 while (isspace(buf[pos+1])) {
00672 pos++;
00673 }
00674 }
00675 newbuf[newbufpos] = c;
00676 newbufpos ++;
00677 pos++;
00678 }
00679 pos = 0;
00680 newbufpos = 0;
00681
00682
00683
00684 aji_log_hook(client, buf, len, 1);
00685
00686
00687
00688 ret = iks_parse(client->p, newbuf, 0, 0);
00689 memset(newbuf, 0, sizeof(newbuf));
00690
00691 if (ret != IKS_OK) {
00692 ast_log(LOG_WARNING, "XML parsing failed\n");
00693 return ret;
00694 }
00695 ast_debug(3, "XML parsing successful\n");
00696 }
00697 return IKS_OK;
00698 }
00699
00700
00701
00702
00703
00704
00705
00706 static int aji_send_header(struct aji_client *client, const char *to)
00707 {
00708 char *msg;
00709 int len, err;
00710
00711 len = 91 + strlen(client->name_space) + 6 + strlen(to) + 16 + 1;
00712 msg = iks_malloc(len);
00713 if (!msg)
00714 return IKS_NOMEM;
00715 sprintf(msg, "<?xml version='1.0'?>"
00716 "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='"
00717 "%s' to='%s' version='1.0'>", client->name_space, to);
00718 err = aji_send_raw(client, msg);
00719 iks_free(msg);
00720 if (err != IKS_OK)
00721 return err;
00722
00723 return IKS_OK;
00724 }
00725
00726
00727
00728
00729
00730
00731
00732 int ast_aji_send(struct aji_client *client, iks *x)
00733 {
00734 return aji_send_raw(client, iks_string(iks_stack(x), x));
00735 }
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745 static int aji_send_raw(struct aji_client *client, const char *xmlstr)
00746 {
00747 int ret;
00748 #ifdef HAVE_OPENSSL
00749 int len = strlen(xmlstr);
00750
00751 if (aji_is_secure(client)) {
00752 ret = SSL_write(client->ssl_session, xmlstr, len);
00753 if (ret) {
00754
00755
00756 aji_log_hook(client, xmlstr, len, 0);
00757 return IKS_OK;
00758 }
00759 }
00760 #endif
00761
00762
00763 ret = iks_send_raw(client->p, xmlstr);
00764 if (ret != IKS_OK)
00765 return ret;
00766
00767 return IKS_OK;
00768 }
00769
00770
00771
00772
00773
00774
00775
00776
00777 static void aji_log_hook(void *data, const char *xmpp, size_t size, int is_incoming)
00778 {
00779 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00780
00781 if (!ast_strlen_zero(xmpp))
00782 manager_event(EVENT_FLAG_USER, "JabberEvent", "Account: %s\r\nPacket: %s\r\n", client->name, xmpp);
00783
00784 if (client->debug) {
00785 if (is_incoming)
00786 ast_verbose("\nJABBER: %s INCOMING: %s\n", client->name, xmpp);
00787 else {
00788 if( strlen(xmpp) == 1) {
00789 if(option_debug > 2 && xmpp[0] == ' ') {
00790 ast_verbose("\nJABBER: Keep alive packet\n");
00791 }
00792 } else
00793 ast_verbose("\nJABBER: %s OUTGOING: %s\n", client->name, xmpp);
00794 }
00795
00796 }
00797 ASTOBJ_UNREF(client, aji_client_destroy);
00798 }
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809 static int aji_start_sasl(struct aji_client *client, enum ikssasltype type, char *username, char *pass)
00810 {
00811 iks *x = NULL;
00812 int len;
00813 char *s;
00814 char *base64;
00815
00816
00817
00818
00819 if ((type & IKS_STREAM_SASL_MD5) && !aji_is_secure(client))
00820 return iks_start_sasl(client->p, IKS_SASL_DIGEST_MD5, username, pass);
00821 if (!(type & IKS_STREAM_SASL_PLAIN)) {
00822 ast_log(LOG_ERROR, "Server does not support SASL PLAIN authentication\n");
00823 return IKS_NET_NOTSUPP;
00824 }
00825
00826 x = iks_new("auth");
00827 if (!x) {
00828 ast_log(LOG_ERROR, "Out of memory.\n");
00829 return IKS_NET_NOTSUPP;
00830 }
00831
00832 iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_SASL);
00833 len = strlen(username) + strlen(pass) + 3;
00834 s = alloca(len);
00835 base64 = alloca((len + 2) * 4 / 3);
00836 iks_insert_attrib(x, "mechanism", "PLAIN");
00837 snprintf(s, len, "%c%s%c%s", 0, username, 0, pass);
00838
00839
00840
00841
00842
00843 ast_base64encode(base64, (const unsigned char *) s, len - 1, (len + 2) * 4 / 3);
00844 iks_insert_cdata(x, base64, 0);
00845 ast_aji_send(client, x);
00846 iks_delete(x);
00847
00848 return IKS_OK;
00849 }
00850
00851
00852
00853
00854
00855
00856
00857
00858 static int aji_act_hook(void *data, int type, iks *node)
00859 {
00860 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00861 ikspak *pak = NULL;
00862 iks *auth = NULL;
00863 int features = 0;
00864
00865 if(!node) {
00866 ast_log(LOG_ERROR, "aji_act_hook was called with out a packet\n");
00867 ASTOBJ_UNREF(client, aji_client_destroy);
00868 return IKS_HOOK;
00869 }
00870
00871 if (client->state == AJI_DISCONNECTING) {
00872 ASTOBJ_UNREF(client, aji_client_destroy);
00873 return IKS_HOOK;
00874 }
00875
00876 pak = iks_packet(node);
00877
00878 if (!client->component) {
00879 switch (type) {
00880 case IKS_NODE_START:
00881 if (client->usetls && !aji_is_secure(client)) {
00882 #ifndef HAVE_OPENSSL
00883 ast_log(LOG_ERROR, "OpenSSL not installed. You need to install OpenSSL on this system, or disable the TLS option in your configuration file\n");
00884 ASTOBJ_UNREF(client, aji_client_destroy);
00885 return IKS_HOOK;
00886 #else
00887 if (aji_start_tls(client) == IKS_NET_TLSFAIL) {
00888 ast_log(LOG_ERROR, "Could not start TLS\n");
00889 ASTOBJ_UNREF(client, aji_client_destroy);
00890 return IKS_HOOK;
00891 }
00892 #endif
00893 break;
00894 }
00895 if (!client->usesasl) {
00896 iks_filter_add_rule(client->f, aji_client_connect, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->mid, IKS_RULE_DONE);
00897 auth = jabber_make_auth(client->jid, client->password, iks_find_attrib(node, "id"));
00898 if (auth) {
00899 iks_insert_attrib(auth, "id", client->mid);
00900 iks_insert_attrib(auth, "to", client->jid->server);
00901 ast_aji_increment_mid(client->mid);
00902 ast_aji_send(client, auth);
00903 iks_delete(auth);
00904 } else
00905 ast_log(LOG_ERROR, "Out of memory.\n");
00906 }
00907 break;
00908
00909 case IKS_NODE_NORMAL:
00910 #ifdef HAVE_OPENSSL
00911 if (client->stream_flags & TRY_SECURE) {
00912 if (!strcmp("proceed", iks_name(node))) {
00913 return aji_tls_handshake(client);
00914 }
00915 }
00916 #endif
00917 if (!strcmp("stream:features", iks_name(node))) {
00918 features = iks_stream_features(node);
00919 if (client->usesasl) {
00920 if (client->usetls && !aji_is_secure(client))
00921 break;
00922 if (client->authorized) {
00923 if (features & IKS_STREAM_BIND) {
00924 iks_filter_add_rule(client->f, aji_client_connect, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_DONE);
00925 auth = iks_make_resource_bind(client->jid);
00926 if (auth) {
00927 iks_insert_attrib(auth, "id", client->mid);
00928 ast_aji_increment_mid(client->mid);
00929 ast_aji_send(client, auth);
00930 iks_delete(auth);
00931 } else {
00932 ast_log(LOG_ERROR, "Out of memory.\n");
00933 break;
00934 }
00935 }
00936 if (features & IKS_STREAM_SESSION) {
00937 iks_filter_add_rule (client->f, aji_client_connect, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, "auth", IKS_RULE_DONE);
00938 auth = iks_make_session();
00939 if (auth) {
00940 iks_insert_attrib(auth, "id", "auth");
00941 ast_aji_increment_mid(client->mid);
00942 ast_aji_send(client, auth);
00943 iks_delete(auth);
00944 } else {
00945 ast_log(LOG_ERROR, "Out of memory.\n");
00946 }
00947 }
00948 } else {
00949 int ret;
00950 if (!client->jid->user) {
00951 ast_log(LOG_ERROR, "Malformed Jabber ID : %s (domain missing?)\n", client->jid->full);
00952 break;
00953 }
00954
00955 ret = aji_start_sasl(client, features, client->jid->user, client->password);
00956 if (ret != IKS_OK) {
00957 ASTOBJ_UNREF(client, aji_client_destroy);
00958 return IKS_HOOK;
00959 }
00960 break;
00961 }
00962 }
00963 } else if (!strcmp("failure", iks_name(node))) {
00964 ast_log(LOG_ERROR, "JABBER: encryption failure. possible bad password.\n");
00965 } else if (!strcmp("success", iks_name(node))) {
00966 client->authorized = 1;
00967 aji_send_header(client, client->jid->server);
00968 }
00969 break;
00970 case IKS_NODE_ERROR:
00971 ast_log(LOG_ERROR, "JABBER: Node Error\n");
00972 ASTOBJ_UNREF(client, aji_client_destroy);
00973 return IKS_HOOK;
00974 break;
00975 case IKS_NODE_STOP:
00976 ast_log(LOG_WARNING, "JABBER: Disconnected\n");
00977 ASTOBJ_UNREF(client, aji_client_destroy);
00978 return IKS_HOOK;
00979 break;
00980 }
00981 } else if (client->state != AJI_CONNECTED && client->component) {
00982 switch (type) {
00983 case IKS_NODE_START:
00984 if (client->state == AJI_DISCONNECTED) {
00985 char secret[160], shasum[320], *handshake;
00986
00987 sprintf(secret, "%s%s", pak->id, client->password);
00988 ast_sha1_hash(shasum, secret);
00989 handshake = NULL;
00990 if (asprintf(&handshake, "<handshake>%s</handshake>", shasum) >= 0) {
00991 aji_send_raw(client, handshake);
00992 ast_free(handshake);
00993 handshake = NULL;
00994 }
00995 client->state = AJI_CONNECTING;
00996 if(aji_recv(client, 1) == 2)
00997 client->state = AJI_CONNECTED;
00998 else
00999 ast_log(LOG_WARNING, "Jabber didn't seem to handshake, failed to authenticate.\n");
01000 break;
01001 }
01002 break;
01003
01004 case IKS_NODE_NORMAL:
01005 break;
01006
01007 case IKS_NODE_ERROR:
01008 ast_log(LOG_ERROR, "JABBER: Node Error\n");
01009 ASTOBJ_UNREF(client, aji_client_destroy);
01010 return IKS_HOOK;
01011
01012 case IKS_NODE_STOP:
01013 ast_log(LOG_WARNING, "JABBER: Disconnected\n");
01014 ASTOBJ_UNREF(client, aji_client_destroy);
01015 return IKS_HOOK;
01016 }
01017 }
01018
01019 switch (pak->type) {
01020 case IKS_PAK_NONE:
01021 ast_debug(1, "JABBER: I don't know what to do with paktype NONE.\n");
01022 break;
01023 case IKS_PAK_MESSAGE:
01024 aji_handle_message(client, pak);
01025 ast_debug(1, "JABBER: Handling paktype MESSAGE.\n");
01026 break;
01027 case IKS_PAK_PRESENCE:
01028 aji_handle_presence(client, pak);
01029 ast_debug(1, "JABBER: Handling paktype PRESENCE\n");
01030 break;
01031 case IKS_PAK_S10N:
01032 aji_handle_subscribe(client, pak);
01033 ast_debug(1, "JABBER: Handling paktype S10N\n");
01034 break;
01035 case IKS_PAK_IQ:
01036 ast_debug(1, "JABBER: Handling paktype IQ\n");
01037 aji_handle_iq(client, node);
01038 break;
01039 default:
01040 ast_debug(1, "JABBER: I don't know anything about paktype '%d'\n", pak->type);
01041 break;
01042 }
01043
01044 iks_filter_packet(client->f, pak);
01045
01046 if (node)
01047 iks_delete(node);
01048
01049 ASTOBJ_UNREF(client, aji_client_destroy);
01050 return IKS_OK;
01051 }
01052
01053
01054
01055
01056
01057
01058 static int aji_register_approve_handler(void *data, ikspak *pak)
01059 {
01060 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01061 iks *iq = NULL, *presence = NULL, *x = NULL;
01062
01063 iq = iks_new("iq");
01064 presence = iks_new("presence");
01065 x = iks_new("x");
01066 if (client && iq && presence && x) {
01067 if (!iks_find(pak->query, "remove")) {
01068 iks_insert_attrib(iq, "from", client->jid->full);
01069 iks_insert_attrib(iq, "to", pak->from->full);
01070 iks_insert_attrib(iq, "id", pak->id);
01071 iks_insert_attrib(iq, "type", "result");
01072 ast_aji_send(client, iq);
01073
01074 iks_insert_attrib(presence, "from", client->jid->full);
01075 iks_insert_attrib(presence, "to", pak->from->partial);
01076 iks_insert_attrib(presence, "id", client->mid);
01077 ast_aji_increment_mid(client->mid);
01078 iks_insert_attrib(presence, "type", "subscribe");
01079 iks_insert_attrib(x, "xmlns", "vcard-temp:x:update");
01080 iks_insert_node(presence, x);
01081 ast_aji_send(client, presence);
01082 }
01083 } else {
01084 ast_log(LOG_ERROR, "Out of memory.\n");
01085 }
01086
01087
01088 iks_delete(iq);
01089 iks_delete(presence);
01090 iks_delete(x);
01091
01092 ASTOBJ_UNREF(client, aji_client_destroy);
01093 return IKS_FILTER_EAT;
01094 }
01095
01096
01097
01098
01099
01100
01101 static int aji_register_query_handler(void *data, ikspak *pak)
01102 {
01103 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01104 struct aji_buddy *buddy = NULL;
01105 char *node = NULL;
01106 iks *iq = NULL, *query = NULL;
01107
01108 client = (struct aji_client *) data;
01109
01110 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01111 if (!buddy) {
01112 iks *error = NULL, *notacceptable = NULL;
01113
01114 ast_log(LOG_ERROR, "Someone.... %s tried to register but they aren't allowed\n", pak->from->partial);
01115 iq = iks_new("iq");
01116 query = iks_new("query");
01117 error = iks_new("error");
01118 notacceptable = iks_new("not-acceptable");
01119 if(iq && query && error && notacceptable) {
01120 iks_insert_attrib(iq, "type", "error");
01121 iks_insert_attrib(iq, "from", client->user);
01122 iks_insert_attrib(iq, "to", pak->from->full);
01123 iks_insert_attrib(iq, "id", pak->id);
01124 iks_insert_attrib(query, "xmlns", "jabber:iq:register");
01125 iks_insert_attrib(error, "code" , "406");
01126 iks_insert_attrib(error, "type", "modify");
01127 iks_insert_attrib(notacceptable, "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas");
01128 iks_insert_node(iq, query);
01129 iks_insert_node(iq, error);
01130 iks_insert_node(error, notacceptable);
01131 ast_aji_send(client, iq);
01132 } else {
01133 ast_log(LOG_ERROR, "Out of memory.\n");
01134 }
01135
01136 iks_delete(error);
01137 iks_delete(notacceptable);
01138 } else if (!(node = iks_find_attrib(pak->query, "node"))) {
01139 iks *instructions = NULL;
01140 char *explain = "Welcome to Asterisk - the Open Source PBX.\n";
01141 iq = iks_new("iq");
01142 query = iks_new("query");
01143 instructions = iks_new("instructions");
01144 if (iq && query && instructions && client) {
01145 iks_insert_attrib(iq, "from", client->user);
01146 iks_insert_attrib(iq, "to", pak->from->full);
01147 iks_insert_attrib(iq, "id", pak->id);
01148 iks_insert_attrib(iq, "type", "result");
01149 iks_insert_attrib(query, "xmlns", "jabber:iq:register");
01150 iks_insert_cdata(instructions, explain, 0);
01151 iks_insert_node(iq, query);
01152 iks_insert_node(query, instructions);
01153 ast_aji_send(client, iq);
01154 } else {
01155 ast_log(LOG_ERROR, "Out of memory.\n");
01156 }
01157
01158 iks_delete(instructions);
01159 }
01160 iks_delete(iq);
01161 iks_delete(query);
01162 ASTOBJ_UNREF(client, aji_client_destroy);
01163 return IKS_FILTER_EAT;
01164 }
01165
01166
01167
01168
01169
01170
01171
01172 static int aji_ditems_handler(void *data, ikspak *pak)
01173 {
01174 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01175 char *node = NULL;
01176
01177 if (!(node = iks_find_attrib(pak->query, "node"))) {
01178 iks *iq = NULL, *query = NULL, *item = NULL;
01179 iq = iks_new("iq");
01180 query = iks_new("query");
01181 item = iks_new("item");
01182
01183 if (iq && query && item) {
01184 iks_insert_attrib(iq, "from", client->user);
01185 iks_insert_attrib(iq, "to", pak->from->full);
01186 iks_insert_attrib(iq, "id", pak->id);
01187 iks_insert_attrib(iq, "type", "result");
01188 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01189 iks_insert_attrib(item, "node", "http://jabber.org/protocol/commands");
01190 iks_insert_attrib(item, "name", "Million Dollar Asterisk Commands");
01191 iks_insert_attrib(item, "jid", client->user);
01192
01193 iks_insert_node(iq, query);
01194 iks_insert_node(query, item);
01195 ast_aji_send(client, iq);
01196 } else {
01197 ast_log(LOG_ERROR, "Out of memory.\n");
01198 }
01199
01200 iks_delete(iq);
01201 iks_delete(query);
01202 iks_delete(item);
01203
01204 } else if (!strcasecmp(node, "http://jabber.org/protocol/commands")) {
01205 iks *iq, *query, *confirm;
01206 iq = iks_new("iq");
01207 query = iks_new("query");
01208 confirm = iks_new("item");
01209 if (iq && query && confirm && client) {
01210 iks_insert_attrib(iq, "from", client->user);
01211 iks_insert_attrib(iq, "to", pak->from->full);
01212 iks_insert_attrib(iq, "id", pak->id);
01213 iks_insert_attrib(iq, "type", "result");
01214 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01215 iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
01216 iks_insert_attrib(confirm, "node", "confirmaccount");
01217 iks_insert_attrib(confirm, "name", "Confirm AIM account");
01218 iks_insert_attrib(confirm, "jid", "blog.astjab.org");
01219
01220 iks_insert_node(iq, query);
01221 iks_insert_node(query, confirm);
01222 ast_aji_send(client, iq);
01223 } else {
01224 ast_log(LOG_ERROR, "Out of memory.\n");
01225 }
01226
01227 iks_delete(iq);
01228 iks_delete(query);
01229 iks_delete(confirm);
01230
01231 } else if (!strcasecmp(node, "confirmaccount")) {
01232 iks *iq = NULL, *query = NULL, *feature = NULL;
01233
01234 iq = iks_new("iq");
01235 query = iks_new("query");
01236 feature = iks_new("feature");
01237
01238 if (iq && query && feature && client) {
01239 iks_insert_attrib(iq, "from", client->user);
01240 iks_insert_attrib(iq, "to", pak->from->full);
01241 iks_insert_attrib(iq, "id", pak->id);
01242 iks_insert_attrib(iq, "type", "result");
01243 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01244 iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
01245 iks_insert_node(iq, query);
01246 iks_insert_node(query, feature);
01247 ast_aji_send(client, iq);
01248 } else {
01249 ast_log(LOG_ERROR, "Out of memory.\n");
01250 }
01251
01252 iks_delete(iq);
01253 iks_delete(query);
01254 iks_delete(feature);
01255 }
01256
01257 ASTOBJ_UNREF(client, aji_client_destroy);
01258 return IKS_FILTER_EAT;
01259
01260 }
01261
01262
01263
01264
01265
01266
01267 static int aji_client_info_handler(void *data, ikspak *pak)
01268 {
01269 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01270 struct aji_resource *resource = NULL;
01271 struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01272
01273 resource = aji_find_resource(buddy, pak->from->resource);
01274 if (pak->subtype == IKS_TYPE_RESULT) {
01275 if (!resource) {
01276 ast_log(LOG_NOTICE, "JABBER: Received client info from %s when not requested.\n", pak->from->full);
01277 ASTOBJ_UNREF(client, aji_client_destroy);
01278 return IKS_FILTER_EAT;
01279 }
01280 if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
01281 resource->cap->jingle = 1;
01282 } else
01283 resource->cap->jingle = 0;
01284 } else if (pak->subtype == IKS_TYPE_GET) {
01285 iks *iq, *disco, *ident, *google, *query;
01286 iq = iks_new("iq");
01287 query = iks_new("query");
01288 ident = iks_new("identity");
01289 disco = iks_new("feature");
01290 google = iks_new("feature");
01291 if (iq && ident && disco && google) {
01292 iks_insert_attrib(iq, "from", client->jid->full);
01293 iks_insert_attrib(iq, "to", pak->from->full);
01294 iks_insert_attrib(iq, "type", "result");
01295 iks_insert_attrib(iq, "id", pak->id);
01296 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01297 iks_insert_attrib(ident, "category", "client");
01298 iks_insert_attrib(ident, "type", "pc");
01299 iks_insert_attrib(ident, "name", "asterisk");
01300 iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco#info");
01301 iks_insert_attrib(google, "var", "http://www.google.com/xmpp/protocol/voice/v1");
01302 iks_insert_node(iq, query);
01303 iks_insert_node(query, ident);
01304 iks_insert_node(query, google);
01305 iks_insert_node(query, disco);
01306 ast_aji_send(client, iq);
01307 } else
01308 ast_log(LOG_ERROR, "Out of Memory.\n");
01309
01310 iks_delete(iq);
01311 iks_delete(query);
01312 iks_delete(ident);
01313 iks_delete(google);
01314 iks_delete(disco);
01315 } else if (pak->subtype == IKS_TYPE_ERROR) {
01316 ast_log(LOG_NOTICE, "User %s does not support discovery.\n", pak->from->full);
01317 }
01318 ASTOBJ_UNREF(client, aji_client_destroy);
01319 return IKS_FILTER_EAT;
01320 }
01321
01322
01323
01324
01325
01326
01327 static int aji_dinfo_handler(void *data, ikspak *pak)
01328 {
01329 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01330 char *node = NULL;
01331 struct aji_resource *resource = NULL;
01332 struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01333
01334 resource = aji_find_resource(buddy, pak->from->resource);
01335 if (pak->subtype == IKS_TYPE_ERROR) {
01336 ast_log(LOG_WARNING, "Recieved error from a client, turn on jabber debug!\n");
01337 return IKS_FILTER_EAT;
01338 }
01339 if (pak->subtype == IKS_TYPE_RESULT) {
01340 if (!resource) {
01341 ast_log(LOG_NOTICE,"JABBER: Received client info from %s when not requested.\n", pak->from->full);
01342 ASTOBJ_UNREF(client, aji_client_destroy);
01343 return IKS_FILTER_EAT;
01344 }
01345 if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
01346 resource->cap->jingle = 1;
01347 } else
01348 resource->cap->jingle = 0;
01349 } else if (pak->subtype == IKS_TYPE_GET && !(node = iks_find_attrib(pak->query, "node"))) {
01350 iks *iq, *query, *identity, *disco, *reg, *commands, *gateway, *version, *vcard, *search;
01351
01352 iq = iks_new("iq");
01353 query = iks_new("query");
01354 identity = iks_new("identity");
01355 disco = iks_new("feature");
01356 reg = iks_new("feature");
01357 commands = iks_new("feature");
01358 gateway = iks_new("feature");
01359 version = iks_new("feature");
01360 vcard = iks_new("feature");
01361 search = iks_new("feature");
01362
01363 if (iq && query && identity && disco && reg && commands && gateway && version && vcard && search && client) {
01364 iks_insert_attrib(iq, "from", client->user);
01365 iks_insert_attrib(iq, "to", pak->from->full);
01366 iks_insert_attrib(iq, "id", pak->id);
01367 iks_insert_attrib(iq, "type", "result");
01368 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01369 iks_insert_attrib(identity, "category", "gateway");
01370 iks_insert_attrib(identity, "type", "pstn");
01371 iks_insert_attrib(identity, "name", "Asterisk The Open Source PBX");
01372 iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco");
01373 iks_insert_attrib(reg, "var", "jabber:iq:register");
01374 iks_insert_attrib(commands, "var", "http://jabber.org/protocol/commands");
01375 iks_insert_attrib(gateway, "var", "jabber:iq:gateway");
01376 iks_insert_attrib(version, "var", "jabber:iq:version");
01377 iks_insert_attrib(vcard, "var", "vcard-temp");
01378 iks_insert_attrib(search, "var", "jabber:iq:search");
01379
01380 iks_insert_node(iq, query);
01381 iks_insert_node(query, identity);
01382 iks_insert_node(query, disco);
01383 iks_insert_node(query, reg);
01384 iks_insert_node(query, commands);
01385 iks_insert_node(query, gateway);
01386 iks_insert_node(query, version);
01387 iks_insert_node(query, vcard);
01388 iks_insert_node(query, search);
01389 ast_aji_send(client, iq);
01390 } else {
01391 ast_log(LOG_ERROR, "Out of memory.\n");
01392 }
01393
01394 iks_delete(iq);
01395 iks_delete(query);
01396 iks_delete(identity);
01397 iks_delete(disco);
01398 iks_delete(reg);
01399 iks_delete(commands);
01400 iks_delete(gateway);
01401 iks_delete(version);
01402 iks_delete(vcard);
01403 iks_delete(search);
01404
01405 } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "http://jabber.org/protocol/commands")) {
01406 iks *iq, *query, *confirm;
01407 iq = iks_new("iq");
01408 query = iks_new("query");
01409 confirm = iks_new("item");
01410
01411 if (iq && query && confirm && client) {
01412 iks_insert_attrib(iq, "from", client->user);
01413 iks_insert_attrib(iq, "to", pak->from->full);
01414 iks_insert_attrib(iq, "id", pak->id);
01415 iks_insert_attrib(iq, "type", "result");
01416 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01417 iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
01418 iks_insert_attrib(confirm, "node", "confirmaccount");
01419 iks_insert_attrib(confirm, "name", "Confirm AIM account");
01420 iks_insert_attrib(confirm, "jid", client->user);
01421 iks_insert_node(iq, query);
01422 iks_insert_node(query, confirm);
01423 ast_aji_send(client, iq);
01424 } else {
01425 ast_log(LOG_ERROR, "Out of memory.\n");
01426 }
01427
01428 iks_delete(iq);
01429 iks_delete(query);
01430 iks_delete(confirm);
01431
01432 } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "confirmaccount")) {
01433 iks *iq, *query, *feature;
01434
01435 iq = iks_new("iq");
01436 query = iks_new("query");
01437 feature = iks_new("feature");
01438
01439 if (iq && query && feature && client) {
01440 iks_insert_attrib(iq, "from", client->user);
01441 iks_insert_attrib(iq, "to", pak->from->full);
01442 iks_insert_attrib(iq, "id", pak->id);
01443 iks_insert_attrib(iq, "type", "result");
01444 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01445 iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
01446 iks_insert_node(iq, query);
01447 iks_insert_node(query, feature);
01448 ast_aji_send(client, iq);
01449 } else {
01450 ast_log(LOG_ERROR, "Out of memory.\n");
01451 }
01452
01453 iks_delete(iq);
01454 iks_delete(query);
01455 iks_delete(feature);
01456 }
01457
01458 ASTOBJ_UNREF(client, aji_client_destroy);
01459 return IKS_FILTER_EAT;
01460 }
01461
01462
01463
01464
01465
01466
01467
01468 static void aji_handle_iq(struct aji_client *client, iks *node)
01469 {
01470
01471 }
01472
01473
01474
01475
01476
01477
01478 static void aji_handle_message(struct aji_client *client, ikspak *pak)
01479 {
01480 struct aji_message *insert, *tmp;
01481 int flag = 0;
01482
01483 if (!(insert = ast_calloc(1, sizeof(*insert))))
01484 return;
01485 time(&insert->arrived);
01486 if (iks_find_cdata(pak->x, "body"))
01487 insert->message = ast_strdup(iks_find_cdata(pak->x, "body"));
01488 if (pak->id)
01489 ast_copy_string(insert->id, pak->id, sizeof(insert->message));
01490 if (pak->from)
01491 insert->from = ast_strdup(pak->from->full);
01492 AST_LIST_LOCK(&client->messages);
01493 AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, tmp, list) {
01494 if (flag) {
01495 AST_LIST_REMOVE_CURRENT(list);
01496 if (tmp->from)
01497 ast_free(tmp->from);
01498 if (tmp->message)
01499 ast_free(tmp->message);
01500 } else if (difftime(time(NULL), tmp->arrived) >= client->message_timeout) {
01501 flag = 1;
01502 AST_LIST_REMOVE_CURRENT(list);
01503 if (tmp->from)
01504 ast_free(tmp->from);
01505 if (tmp->message)
01506 ast_free(tmp->message);
01507 }
01508 }
01509 AST_LIST_TRAVERSE_SAFE_END;
01510 AST_LIST_INSERT_HEAD(&client->messages, insert, list);
01511 AST_LIST_UNLOCK(&client->messages);
01512 }
01513
01514
01515
01516
01517
01518 static void aji_handle_presence(struct aji_client *client, ikspak *pak)
01519 {
01520 int status, priority;
01521 struct aji_buddy *buddy;
01522 struct aji_resource *tmp = NULL, *last = NULL, *found = NULL;
01523 char *ver, *node, *descrip, *type;
01524
01525 if(client->state != AJI_CONNECTED)
01526 aji_create_buddy(pak->from->partial, client);
01527
01528 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01529 if (!buddy && pak->from->partial) {
01530
01531 if (!strcmp((const char *)pak->from->partial, (const char *)client->jid->partial))
01532 aji_create_buddy(pak->from->partial, client);
01533 else
01534 ast_log(LOG_NOTICE, "Got presence packet from %s, someone not in our roster!!!!\n", pak->from->partial);
01535 return;
01536 }
01537 type = iks_find_attrib(pak->x, "type");
01538 if(client->component && type &&!strcasecmp("probe", type)) {
01539 aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), client->status, client->statusmessage);
01540 ast_verbose("what i was looking for \n");
01541 }
01542 ASTOBJ_WRLOCK(buddy);
01543 status = (pak->show) ? pak->show : 6;
01544 priority = atoi((iks_find_cdata(pak->x, "priority")) ? iks_find_cdata(pak->x, "priority") : "0");
01545 tmp = buddy->resources;
01546 descrip = ast_strdup(iks_find_cdata(pak->x,"status"));
01547
01548 while (tmp && pak->from->resource) {
01549 if (!strcasecmp(tmp->resource, pak->from->resource)) {
01550 tmp->status = status;
01551 if (tmp->description) ast_free(tmp->description);
01552 tmp->description = descrip;
01553 found = tmp;
01554 if (status == 6) {
01555 if (last && found->next) {
01556 last->next = found->next;
01557 } else if (!last) {
01558 if (found->next)
01559 buddy->resources = found->next;
01560 else
01561 buddy->resources = NULL;
01562 } else if (!found->next) {
01563 if (last)
01564 last->next = NULL;
01565 else
01566 buddy->resources = NULL;
01567 }
01568 ast_free(found);
01569 found = NULL;
01570 break;
01571 }
01572
01573 if (tmp->priority != priority) {
01574 found->priority = priority;
01575 if (!last && !found->next)
01576
01577
01578 break;
01579
01580
01581 if (last)
01582 last->next = found->next;
01583 else
01584 buddy->resources = found->next;
01585
01586 last = NULL;
01587 tmp = buddy->resources;
01588 if (!buddy->resources)
01589 buddy->resources = found;
01590
01591 while (tmp) {
01592
01593
01594 if (found->priority > tmp->priority) {
01595 if (last)
01596
01597 last->next = found;
01598 found->next = tmp;
01599 if (!last)
01600
01601 buddy->resources = found;
01602 break;
01603 }
01604 if (!tmp->next) {
01605
01606 tmp->next = found;
01607 found->next = NULL;
01608 break;
01609 }
01610 last = tmp;
01611 tmp = tmp->next;
01612 }
01613 }
01614 break;
01615 }
01616 last = tmp;
01617 tmp = tmp->next;
01618 }
01619
01620
01621 if (!found && status != 6 && pak->from->resource) {
01622 found = ast_calloc(1, sizeof(*found));
01623
01624 if (!found) {
01625 ast_log(LOG_ERROR, "Out of memory!\n");
01626 return;
01627 }
01628 ast_copy_string(found->resource, pak->from->resource, sizeof(found->resource));
01629 found->status = status;
01630 found->description = descrip;
01631 found->priority = priority;
01632 found->next = NULL;
01633 last = NULL;
01634 tmp = buddy->resources;
01635 while (tmp) {
01636 if (found->priority > tmp->priority) {
01637 if (last)
01638 last->next = found;
01639 found->next = tmp;
01640 if (!last)
01641 buddy->resources = found;
01642 break;
01643 }
01644 if (!tmp->next) {
01645 tmp->next = found;
01646 break;
01647 }
01648 last = tmp;
01649 tmp = tmp->next;
01650 }
01651 if (!tmp)
01652 buddy->resources = found;
01653 }
01654
01655 ASTOBJ_UNLOCK(buddy);
01656 ASTOBJ_UNREF(buddy, aji_buddy_destroy);
01657
01658 node = iks_find_attrib(iks_find(pak->x, "c"), "node");
01659 ver = iks_find_attrib(iks_find(pak->x, "c"), "ver");
01660
01661
01662 if (!node && !ver) {
01663 node = iks_find_attrib(iks_find(pak->x, "caps:c"), "node");
01664 ver = iks_find_attrib(iks_find(pak->x, "caps:c"), "ver");
01665 }
01666
01667
01668 if(status !=6 && found && !found->cap) {
01669 found->cap = aji_find_version(node, ver, pak);
01670 if(gtalk_yuck(pak->x))
01671 found->cap->jingle = 1;
01672 if(found->cap->jingle && option_debug > 4) {
01673 ast_debug(1,"Special case for google till they support discover.\n");
01674 }
01675 else {
01676 iks *iq, *query;
01677 iq = iks_new("iq");
01678 query = iks_new("query");
01679 if(query && iq) {
01680 iks_insert_attrib(iq, "type", "get");
01681 iks_insert_attrib(iq, "to", pak->from->full);
01682 iks_insert_attrib(iq,"from", client->jid->full);
01683 iks_insert_attrib(iq, "id", client->mid);
01684 ast_aji_increment_mid(client->mid);
01685 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01686 iks_insert_node(iq, query);
01687 ast_aji_send(client, iq);
01688
01689 } else
01690 ast_log(LOG_ERROR, "Out of memory.\n");
01691
01692 iks_delete(query);
01693 iks_delete(iq);
01694 }
01695 }
01696 switch (pak->subtype) {
01697 case IKS_TYPE_AVAILABLE:
01698 ast_debug(3, "JABBER: I am available ^_* %i\n", pak->subtype);
01699 break;
01700 case IKS_TYPE_UNAVAILABLE:
01701 ast_debug(3, "JABBER: I am unavailable ^_* %i\n", pak->subtype);
01702 break;
01703 default:
01704 ast_debug(3, "JABBER: Ohh sexy and the wrong type: %i\n", pak->subtype);
01705 }
01706 switch (pak->show) {
01707 case IKS_SHOW_UNAVAILABLE:
01708 ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01709 break;
01710 case IKS_SHOW_AVAILABLE:
01711 ast_debug(3, "JABBER: type is available\n");
01712 break;
01713 case IKS_SHOW_CHAT:
01714 ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01715 break;
01716 case IKS_SHOW_AWAY:
01717 ast_debug(3, "JABBER: type is away\n");
01718 break;
01719 case IKS_SHOW_XA:
01720 ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01721 break;
01722 case IKS_SHOW_DND:
01723 ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01724 break;
01725 default:
01726 ast_debug(3, "JABBER: Kinky! how did that happen %i\n", pak->show);
01727 }
01728 }
01729
01730
01731
01732
01733
01734
01735
01736 static void aji_handle_subscribe(struct aji_client *client, ikspak *pak)
01737 {
01738 iks *presence = NULL, *status = NULL;
01739 struct aji_buddy* buddy = NULL;
01740
01741 switch (pak->subtype) {
01742 case IKS_TYPE_SUBSCRIBE:
01743 presence = iks_new("presence");
01744 status = iks_new("status");
01745 if (presence && status) {
01746 iks_insert_attrib(presence, "type", "subscribed");
01747 iks_insert_attrib(presence, "to", pak->from->full);
01748 iks_insert_attrib(presence, "from", client->jid->full);
01749 if (pak->id)
01750 iks_insert_attrib(presence, "id", pak->id);
01751 iks_insert_cdata(status, "Asterisk has approved subscription", 0);
01752 iks_insert_node(presence, status);
01753 ast_aji_send(client, presence);
01754 } else
01755 ast_log(LOG_ERROR, "Unable to allocate nodes\n");
01756
01757 iks_delete(presence);
01758 iks_delete(status);
01759
01760 if (client->component)
01761 aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), client->status, client->statusmessage);
01762 case IKS_TYPE_SUBSCRIBED:
01763 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01764 if (!buddy && pak->from->partial) {
01765 aji_create_buddy(pak->from->partial, client);
01766 }
01767 default:
01768 if (option_verbose > 4) {
01769 ast_verbose(VERBOSE_PREFIX_3 "JABBER: This is a subcription of type %i\n", pak->subtype);
01770 }
01771 }
01772 }
01773
01774
01775
01776
01777
01778
01779
01780
01781 int ast_aji_send_chat(struct aji_client *client, const char *address, const char *message)
01782 {
01783 int res = 0;
01784 iks *message_packet = NULL;
01785 if (client->state == AJI_CONNECTED) {
01786 message_packet = iks_make_msg(IKS_TYPE_CHAT, address, message);
01787 if (message_packet) {
01788 iks_insert_attrib(message_packet, "from", client->jid->full);
01789 res = ast_aji_send(client, message_packet);
01790 } else {
01791 ast_log(LOG_ERROR, "Out of memory.\n");
01792 }
01793
01794 iks_delete(message_packet);
01795 } else
01796 ast_log(LOG_WARNING, "JABBER: Not connected can't send\n");
01797 return 1;
01798 }
01799
01800
01801
01802
01803
01804
01805
01806
01807
01808 int ast_aji_create_chat(struct aji_client *client, char *room, char *server, char *topic)
01809 {
01810 int res = 0;
01811 iks *iq = NULL;
01812 iq = iks_new("iq");
01813
01814 if (iq && client) {
01815 iks_insert_attrib(iq, "type", "get");
01816 iks_insert_attrib(iq, "to", server);
01817 iks_insert_attrib(iq, "id", client->mid);
01818 ast_aji_increment_mid(client->mid);
01819 ast_aji_send(client, iq);
01820 } else
01821 ast_log(LOG_ERROR, "Out of memory.\n");
01822
01823 iks_delete(iq);
01824
01825 return res;
01826 }
01827
01828
01829
01830
01831
01832
01833
01834 int ast_aji_join_chat(struct aji_client *client, char *room)
01835 {
01836 int res = 0;
01837 iks *presence = NULL, *priority = NULL;
01838 presence = iks_new("presence");
01839 priority = iks_new("priority");
01840 if (presence && priority && client) {
01841 iks_insert_cdata(priority, "0", 1);
01842 iks_insert_attrib(presence, "to", room);
01843 iks_insert_node(presence, priority);
01844 res = ast_aji_send(client, presence);
01845 iks_insert_cdata(priority, "5", 1);
01846 iks_insert_attrib(presence, "to", room);
01847 res = ast_aji_send(client, presence);
01848 } else
01849 ast_log(LOG_ERROR, "Out of memory.\n");
01850
01851 iks_delete(presence);
01852 iks_delete(priority);
01853
01854 return res;
01855 }
01856
01857
01858
01859
01860
01861
01862
01863
01864
01865 int ast_aji_invite_chat(struct aji_client *client, char *user, char *room, char *message)
01866 {
01867 int res = 0;
01868 iks *invite, *body, *namespace;
01869
01870 invite = iks_new("message");
01871 body = iks_new("body");
01872 namespace = iks_new("x");
01873 if (client && invite && body && namespace) {
01874 iks_insert_attrib(invite, "to", user);
01875 iks_insert_attrib(invite, "id", client->mid);
01876 ast_aji_increment_mid(client->mid);
01877 iks_insert_cdata(body, message, 0);
01878 iks_insert_attrib(namespace, "xmlns", "jabber:x:conference");
01879 iks_insert_attrib(namespace, "jid", room);
01880 iks_insert_node(invite, body);
01881 iks_insert_node(invite, namespace);
01882 res = ast_aji_send(client, invite);
01883 } else
01884 ast_log(LOG_ERROR, "Out of memory.\n");
01885
01886 iks_delete(body);
01887 iks_delete(namespace);
01888 iks_delete(invite);
01889
01890 return res;
01891 }
01892
01893
01894
01895
01896
01897
01898
01899 static void *aji_recv_loop(void *data)
01900 {
01901 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01902 int res = IKS_HOOK;
01903
01904 while(res != IKS_OK) {
01905 ast_debug(3, "JABBER: Connecting.\n");
01906 res = aji_reconnect(client);
01907 sleep(4);
01908 }
01909
01910 do {
01911 if (res == IKS_NET_RWERR || client->timeout == 0) {
01912 while(res != IKS_OK) {
01913 ast_debug(3, "JABBER: reconnecting.\n");
01914 res = aji_reconnect(client);
01915 sleep(4);
01916 }
01917 }
01918
01919 res = aji_recv(client, 1);
01920
01921 if (client->state == AJI_DISCONNECTING) {
01922 ast_debug(2, "Ending our Jabber client's thread due to a disconnect\n");
01923 pthread_exit(NULL);
01924 }
01925
01926
01927 if (res == IKS_NET_EXPIRED)
01928 client->timeout--;
01929
01930 if (res == IKS_HOOK)
01931 ast_log(LOG_WARNING, "JABBER: Got hook event.\n");
01932 else if (res == IKS_NET_TLSFAIL)
01933 ast_log(LOG_ERROR, "JABBER: Failure in TLS.\n");
01934 else if (client->timeout == 0 && client->state == AJI_CONNECTED) {
01935 res = client->keepalive ? aji_send_raw(client, " ") : IKS_OK;
01936 if(res == IKS_OK)
01937 client->timeout = 50;
01938 else
01939 ast_log(LOG_WARNING, "JABBER: Network Timeout\n");
01940 } else if (res == IKS_NET_RWERR)
01941 ast_log(LOG_WARNING, "JABBER: socket read error\n");
01942 } while (client);
01943 ASTOBJ_UNREF(client, aji_client_destroy);
01944 return 0;
01945 }
01946
01947
01948
01949
01950
01951
01952 void ast_aji_increment_mid(char *mid)
01953 {
01954 int i = 0;
01955
01956 for (i = strlen(mid) - 1; i >= 0; i--) {
01957 if (mid[i] != 'z') {
01958 mid[i] = mid[i] + 1;
01959 i = 0;
01960 } else
01961 mid[i] = 'a';
01962 }
01963 }
01964
01965 #if 0
01966
01967
01968
01969
01970
01971
01972 static int aji_register_transport(void *data, ikspak *pak)
01973 {
01974 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01975 int res = 0;
01976 struct aji_buddy *buddy = NULL;
01977 iks *send = iks_make_iq(IKS_TYPE_GET, "jabber:iq:register");
01978
01979 if (client && send) {
01980 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
01981 ASTOBJ_RDLOCK(iterator);
01982 if (iterator->btype == AJI_TRANS) {
01983 buddy = iterator;
01984 }
01985 ASTOBJ_UNLOCK(iterator);
01986 });
01987 iks_filter_remove_hook(client->f, aji_register_transport);
01988 iks_filter_add_rule(client->f, aji_register_transport2, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_NS, IKS_NS_REGISTER, IKS_RULE_DONE);
01989 iks_insert_attrib(send, "to", buddy->host);
01990 iks_insert_attrib(send, "id", client->mid);
01991 ast_aji_increment_mid(client->mid);
01992 iks_insert_attrib(send, "from", client->user);
01993 res = ast_aji_send(client, send);
01994 } else
01995 ast_log(LOG_ERROR, "Out of memory.\n");
01996
01997 if (send)
01998 iks_delete(send);
01999 ASTOBJ_UNREF(client, aji_client_destroy);
02000 return IKS_FILTER_EAT;
02001
02002 }
02003
02004
02005
02006
02007
02008
02009 static int aji_register_transport2(void *data, ikspak *pak)
02010 {
02011 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
02012 int res = 0;
02013 struct aji_buddy *buddy = NULL;
02014
02015 iks *regiq = iks_new("iq");
02016 iks *regquery = iks_new("query");
02017 iks *reguser = iks_new("username");
02018 iks *regpass = iks_new("password");
02019
02020 if (client && regquery && reguser && regpass && regiq) {
02021 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02022 ASTOBJ_RDLOCK(iterator);
02023 if (iterator->btype == AJI_TRANS)
02024 buddy = iterator; ASTOBJ_UNLOCK(iterator);
02025 });
02026 iks_filter_remove_hook(client->f, aji_register_transport2);
02027 iks_insert_attrib(regiq, "to", buddy->host);
02028 iks_insert_attrib(regiq, "type", "set");
02029 iks_insert_attrib(regiq, "id", client->mid);
02030 ast_aji_increment_mid(client->mid);
02031 iks_insert_attrib(regiq, "from", client->user);
02032 iks_insert_attrib(regquery, "xmlns", "jabber:iq:register");
02033 iks_insert_cdata(reguser, buddy->user, 0);
02034 iks_insert_cdata(regpass, buddy->pass, 0);
02035 iks_insert_node(regiq, regquery);
02036 iks_insert_node(regquery, reguser);
02037 iks_insert_node(regquery, regpass);
02038 res = ast_aji_send(client, regiq);
02039 } else
02040 ast_log(LOG_ERROR, "Out of memory.\n");
02041 if (regiq)
02042 iks_delete(regiq);
02043 if (regquery)
02044 iks_delete(regquery);
02045 if (reguser)
02046 iks_delete(reguser);
02047 if (regpass)
02048 iks_delete(regpass);
02049 ASTOBJ_UNREF(client, aji_client_destroy);
02050 return IKS_FILTER_EAT;
02051 }
02052 #endif
02053
02054
02055
02056
02057
02058
02059
02060 static void aji_pruneregister(struct aji_client *client)
02061 {
02062 int res = 0;
02063 iks *removeiq = iks_new("iq");
02064 iks *removequery = iks_new("query");
02065 iks *removeitem = iks_new("item");
02066 iks *send = iks_make_iq(IKS_TYPE_GET, "http://jabber.org/protocol/disco#items");
02067 if (!client || !removeiq || !removequery || !removeitem || !send) {
02068 ast_log(LOG_ERROR, "Out of memory.\n");
02069 goto safeout;
02070 }
02071
02072 iks_insert_node(removeiq, removequery);
02073 iks_insert_node(removequery, removeitem);
02074 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02075 ASTOBJ_RDLOCK(iterator);
02076
02077
02078 if (ast_test_flag(&iterator->flags, AJI_AUTOPRUNE)) {
02079 res = ast_aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBE, iterator->name,
02080 "GoodBye. Your status is no longer needed by Asterisk the Open Source PBX"
02081 " so I am no longer subscribing to your presence.\n"));
02082 res = ast_aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBED, iterator->name,
02083 "GoodBye. You are no longer in the Asterisk config file so I am removing"
02084 " your access to my presence.\n"));
02085 iks_insert_attrib(removeiq, "from", client->jid->full);
02086 iks_insert_attrib(removeiq, "type", "set");
02087 iks_insert_attrib(removequery, "xmlns", "jabber:iq:roster");
02088 iks_insert_attrib(removeitem, "jid", iterator->name);
02089 iks_insert_attrib(removeitem, "subscription", "remove");
02090 res = ast_aji_send(client, removeiq);
02091 } else if (ast_test_flag(&iterator->flags, AJI_AUTOREGISTER)) {
02092 res = ast_aji_send(client, iks_make_s10n(IKS_TYPE_SUBSCRIBE, iterator->name,
02093 "Greetings! I am the Asterisk Open Source PBX and I want to subscribe to your presence\n"));
02094 ast_clear_flag(&iterator->flags, AJI_AUTOREGISTER);
02095 }
02096 ASTOBJ_UNLOCK(iterator);
02097 });
02098
02099 safeout:
02100 iks_delete(removeiq);
02101 iks_delete(removequery);
02102 iks_delete(removeitem);
02103 iks_delete(send);
02104
02105 ASTOBJ_CONTAINER_PRUNE_MARKED(&client->buddies, aji_buddy_destroy);
02106 }
02107
02108
02109
02110
02111
02112
02113
02114 static int aji_filter_roster(void *data, ikspak *pak)
02115 {
02116 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
02117 int flag = 0;
02118 iks *x = NULL;
02119 struct aji_buddy *buddy;
02120
02121 client->state = AJI_CONNECTED;
02122 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02123 ASTOBJ_RDLOCK(iterator);
02124 x = iks_child(pak->query);
02125 flag = 0;
02126 while (x) {
02127 if (!iks_strcmp(iks_name(x), "item")) {
02128 if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid"))) {
02129 flag = 1;
02130 ast_clear_flag(&iterator->flags, AJI_AUTOPRUNE | AJI_AUTOREGISTER);
02131 }
02132 }
02133 x = iks_next(x);
02134 }
02135 if (!flag)
02136 ast_copy_flags(&iterator->flags, &client->flags, AJI_AUTOREGISTER);
02137 iks_delete(x);
02138
02139 ASTOBJ_UNLOCK(iterator);
02140 });
02141
02142 x = iks_child(pak->query);
02143 while (x) {
02144 flag = 0;
02145 if (iks_strcmp(iks_name(x), "item") == 0) {
02146 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02147 ASTOBJ_RDLOCK(iterator);
02148 if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid")))
02149 flag = 1;
02150 ASTOBJ_UNLOCK(iterator);
02151 });
02152
02153 if (flag) {
02154
02155 x = iks_next(x);
02156 continue;
02157 }
02158
02159 buddy = ast_calloc(1, sizeof(*buddy));
02160 if (!buddy) {
02161 ast_log(LOG_WARNING, "Out of memory\n");
02162 return 0;
02163 }
02164 ASTOBJ_INIT(buddy);
02165 ASTOBJ_WRLOCK(buddy);
02166 ast_copy_string(buddy->name, iks_find_attrib(x, "jid"), sizeof(buddy->name));
02167 ast_clear_flag(&buddy->flags, AST_FLAGS_ALL);
02168 if(ast_test_flag(&client->flags, AJI_AUTOPRUNE)) {
02169 ast_set_flag(&buddy->flags, AJI_AUTOPRUNE);
02170 ASTOBJ_MARK(buddy);
02171 } else if (!iks_strcmp(iks_find_attrib(x, "subscription"), "none") || !iks_strcmp(iks_find_attrib(x, "subscription"), "from")) {
02172
02173
02174 ast_set_flag(&buddy->flags, AJI_AUTOREGISTER);
02175 }
02176 ASTOBJ_UNLOCK(buddy);
02177 if (buddy) {
02178 ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
02179 ASTOBJ_UNREF(buddy, aji_buddy_destroy);
02180 }
02181 }
02182 x = iks_next(x);
02183 }
02184
02185 iks_delete(x);
02186 aji_pruneregister(client);
02187
02188 ASTOBJ_UNREF(client, aji_client_destroy);
02189 return IKS_FILTER_EAT;
02190 }
02191
02192
02193
02194
02195
02196
02197 static int aji_reconnect(struct aji_client *client)
02198 {
02199 int res = 0;
02200
02201 if (client->state)
02202 client->state = AJI_DISCONNECTED;
02203 client->timeout=50;
02204 if (client->p)
02205 iks_parser_reset(client->p);
02206 if (client->authorized)
02207 client->authorized = 0;
02208
02209 res = aji_initialize(client);
02210
02211 return res;
02212 }
02213
02214
02215
02216
02217
02218
02219 static int aji_get_roster(struct aji_client *client)
02220 {
02221 iks *roster = NULL;
02222 roster = iks_make_iq(IKS_TYPE_GET, IKS_NS_ROSTER);
02223
02224 if(roster) {
02225 iks_insert_attrib(roster, "id", "roster");
02226 aji_set_presence(client, NULL, client->jid->full, client->status, client->statusmessage);
02227 ast_aji_send(client, roster);
02228 }
02229
02230 iks_delete(roster);
02231
02232 return 1;
02233 }
02234
02235
02236
02237
02238
02239
02240
02241 static int aji_client_connect(void *data, ikspak *pak)
02242 {
02243 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
02244 int res = 0;
02245
02246 if (client) {
02247 if (client->state == AJI_DISCONNECTED) {
02248 iks_filter_add_rule(client->f, aji_filter_roster, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, "roster", IKS_RULE_DONE);
02249 client->state = AJI_CONNECTING;
02250 client->jid = (iks_find_cdata(pak->query, "jid")) ? iks_id_new(client->stack, iks_find_cdata(pak->query, "jid")) : client->jid;
02251 iks_filter_remove_hook(client->f, aji_client_connect);
02252 if(!client->component)
02253 aji_get_roster(client);
02254 }
02255 } else
02256 ast_log(LOG_ERROR, "Out of memory.\n");
02257
02258 ASTOBJ_UNREF(client, aji_client_destroy);
02259 return res;
02260 }
02261
02262
02263
02264
02265
02266
02267 static int aji_initialize(struct aji_client *client)
02268 {
02269 int connected = IKS_NET_NOCONN;
02270
02271 #ifdef HAVE_OPENSSL
02272
02273 client->stream_flags = 0;
02274 #endif
02275
02276 connected = iks_connect_via(client->p, S_OR(client->serverhost, client->jid->server), client->port, client->component ? client->user : client->jid->server);
02277
02278 if (connected == IKS_NET_NOCONN) {
02279 ast_log(LOG_ERROR, "JABBER ERROR: No Connection\n");
02280 return IKS_HOOK;
02281 } else if (connected == IKS_NET_NODNS) {
02282 ast_log(LOG_ERROR, "JABBER ERROR: No DNS %s for client to %s\n", client->name, S_OR(client->serverhost, client->jid->server));
02283 return IKS_HOOK;
02284 }
02285
02286 return IKS_OK;
02287 }
02288
02289
02290
02291
02292
02293
02294 int ast_aji_disconnect(struct aji_client *client)
02295 {
02296 if (client) {
02297 ast_verb(4, "JABBER: Disconnecting\n");
02298 #ifdef HAVE_OPENSSL
02299 if (client->stream_flags & SECURE) {
02300 SSL_shutdown(client->ssl_session);
02301 SSL_CTX_free(client->ssl_context);
02302 SSL_free(client->ssl_session);
02303 }
02304 #endif
02305 iks_disconnect(client->p);
02306 iks_parser_delete(client->p);
02307 ASTOBJ_UNREF(client, aji_client_destroy);
02308 }
02309
02310 return 1;
02311 }
02312
02313
02314
02315
02316
02317
02318
02319
02320
02321
02322 static void aji_set_presence(struct aji_client *client, char *to, char *from, int level, char *desc)
02323 {
02324 int res = 0;
02325 iks *presence = iks_make_pres(level, desc);
02326 iks *cnode = iks_new("c");
02327 iks *priority = iks_new("priority");
02328 char priorityS[10];
02329
02330 if (presence && cnode && client && priority) {
02331 if(to)
02332 iks_insert_attrib(presence, "to", to);
02333 if(from)
02334 iks_insert_attrib(presence, "from", from);
02335 snprintf(priorityS, sizeof(priorityS), "%d", client->priority);
02336 iks_insert_cdata(priority, priorityS, strlen(priorityS));
02337 iks_insert_node(presence, priority);
02338 iks_insert_attrib(cnode, "node", "http://www.asterisk.org/xmpp/client/caps");
02339 iks_insert_attrib(cnode, "ver", "asterisk-xmpp");
02340 iks_insert_attrib(cnode, "ext", "voice-v1");
02341 iks_insert_attrib(cnode, "xmlns", "http://jabber.org/protocol/caps");
02342 iks_insert_node(presence, cnode);
02343 res = ast_aji_send(client, presence);
02344 } else
02345 ast_log(LOG_ERROR, "Out of memory.\n");
02346
02347 iks_delete(cnode);
02348 iks_delete(presence);
02349 iks_delete(priority);
02350 }
02351
02352
02353
02354
02355
02356 static char *aji_do_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02357 {
02358 switch (cmd) {
02359 case CLI_INIT:
02360 e->command = "jabber set debug {on|off}";
02361 e->usage =
02362 "Usage: jabber set debug {on|off}\n"
02363 " Enables/disables dumping of XMPP/Jabber packets for debugging purposes.\n";
02364 return NULL;
02365 case CLI_GENERATE:
02366 return NULL;
02367 }
02368
02369 if (a->argc != e->args)
02370 return CLI_SHOWUSAGE;
02371
02372 if (!strncasecmp(a->argv[e->args - 1], "on", 2)) {
02373 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02374 ASTOBJ_RDLOCK(iterator);
02375 iterator->debug = 1;
02376 ASTOBJ_UNLOCK(iterator);
02377 });
02378 ast_cli(a->fd, "Jabber Debugging Enabled.\n");
02379 return CLI_SUCCESS;
02380 } else if (!strncasecmp(a->argv[e->args - 1], "off", 3)) {
02381 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02382 ASTOBJ_RDLOCK(iterator);
02383 iterator->debug = 0;
02384 ASTOBJ_UNLOCK(iterator);
02385 });
02386 ast_cli(a->fd, "Jabber Debugging Disabled.\n");
02387 return CLI_SUCCESS;
02388 }
02389 return CLI_SHOWUSAGE;
02390 }
02391
02392
02393
02394
02395
02396 static char *aji_do_debug_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02397 {
02398
02399 switch (cmd) {
02400 case CLI_INIT:
02401 e->command = "jabber debug [off]";
02402 e->usage =
02403 "Usage: jabber debug [off]\n"
02404 " Enables/disables dumping of Jabber packets for debugging purposes.\n";
02405 return NULL;
02406 case CLI_GENERATE:
02407 return NULL;
02408 }
02409
02410 if (a->argc == 2) {
02411 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02412 ASTOBJ_RDLOCK(iterator);
02413 iterator->debug = 1;
02414 ASTOBJ_UNLOCK(iterator);
02415 });
02416 ast_cli(a->fd, "Jabber Debugging Enabled.\n");
02417 return CLI_SUCCESS;
02418 } else if (a->argc == 3) {
02419 if (!strncasecmp(a->argv[2], "off", 3)) {
02420 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02421 ASTOBJ_RDLOCK(iterator);
02422 iterator->debug = 0;
02423 ASTOBJ_UNLOCK(iterator);
02424 });
02425 ast_cli(a->fd, "Jabber Debugging Disabled.\n");
02426 return CLI_SUCCESS;
02427 }
02428 }
02429 return CLI_SHOWUSAGE;
02430 }
02431
02432
02433
02434
02435
02436 static char *aji_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02437 {
02438 switch (cmd) {
02439 case CLI_INIT:
02440 e->command = "jabber reload";
02441 e->usage =
02442 "Usage: jabber reload\n"
02443 " Reloads the Jabber module.\n";
02444 return NULL;
02445 case CLI_GENERATE:
02446 return NULL;
02447 }
02448
02449 aji_reload(1);
02450 ast_cli(a->fd, "Jabber Reloaded.\n");
02451 return CLI_SUCCESS;
02452 }
02453
02454
02455
02456
02457
02458 static char *aji_show_clients(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02459 {
02460 char *status;
02461 int count = 0;
02462
02463 switch (cmd) {
02464 case CLI_INIT:
02465 e->command = "jabber show connected";
02466 e->usage =
02467 "Usage: jabber show connected\n"
02468 " Shows state of clients and components\n";
02469 return NULL;
02470 case CLI_GENERATE:
02471 return NULL;
02472 }
02473
02474 ast_cli(a->fd, "Jabber Users and their status:\n");
02475 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02476 ASTOBJ_RDLOCK(iterator);
02477 count++;
02478 switch (iterator->state) {
02479 case AJI_DISCONNECTED:
02480 status = "Disconnected";
02481 break;
02482 case AJI_CONNECTING:
02483 status = "Connecting";
02484 break;
02485 case AJI_CONNECTED:
02486 status = "Connected";
02487 break;
02488 default:
02489 status = "Unknown";
02490 }
02491 ast_cli(a->fd, " User: %s - %s\n", iterator->user, status);
02492 ASTOBJ_UNLOCK(iterator);
02493 });
02494 ast_cli(a->fd, "----\n");
02495 ast_cli(a->fd, " Number of users: %d\n", count);
02496 return CLI_SUCCESS;
02497 }
02498
02499
02500
02501
02502
02503 static char *aji_show_buddies(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02504 {
02505 struct aji_resource *resource;
02506 struct aji_client *client;
02507
02508 switch (cmd) {
02509 case CLI_INIT:
02510 e->command = "jabber show buddies";
02511 e->usage =
02512 "Usage: jabber show buddies\n"
02513 " Shows buddy lists of our clients\n";
02514 return NULL;
02515 case CLI_GENERATE:
02516 return NULL;
02517 }
02518
02519 ast_cli(a->fd, "Jabber buddy lists\n");
02520 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02521 ast_cli(a->fd,"Client: %s\n", iterator->user);
02522 client = iterator;
02523 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02524 ASTOBJ_RDLOCK(iterator);
02525 ast_cli(a->fd,"\tBuddy:\t%s\n", iterator->name);
02526 if (!iterator->resources)
02527 ast_cli(a->fd,"\t\tResource: None\n");
02528 for (resource = iterator->resources; resource; resource = resource->next) {
02529 ast_cli(a->fd,"\t\tResource: %s\n", resource->resource);
02530 if(resource->cap) {
02531 ast_cli(a->fd,"\t\t\tnode: %s\n", resource->cap->parent->node);
02532 ast_cli(a->fd,"\t\t\tversion: %s\n", resource->cap->version);
02533 ast_cli(a->fd,"\t\t\tJingle capable: %s\n", resource->cap->jingle ? "yes" : "no");
02534 }
02535 ast_cli(a->fd,"\t\tStatus: %d\n", resource->status);
02536 ast_cli(a->fd,"\t\tPriority: %d\n", resource->priority);
02537 }
02538 ASTOBJ_UNLOCK(iterator);
02539 });
02540 iterator = client;
02541 });
02542 return CLI_SUCCESS;
02543 }
02544
02545
02546
02547
02548
02549 static char *aji_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02550 {
02551 struct aji_client *client;
02552 struct aji_resource *resource;
02553 const char *name = "asterisk";
02554 struct aji_message *tmp;
02555
02556 switch (cmd) {
02557 case CLI_INIT:
02558 e->command = "jabber test";
02559 e->usage =
02560 "Usage: jabber test [client]\n"
02561 " Sends test message for debugging purposes. A specific client\n"
02562 " as configured in jabber.conf can be optionally specified.\n";
02563 return NULL;
02564 case CLI_GENERATE:
02565 return NULL;
02566 }
02567
02568 if (a->argc > 3)
02569 return CLI_SHOWUSAGE;
02570 else if (a->argc == 3)
02571 name = a->argv[2];
02572
02573 if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
02574 ast_cli(a->fd, "Unable to find client '%s'!\n", name);
02575 return CLI_FAILURE;
02576 }
02577
02578
02579 ast_aji_send_chat(client, "mogorman@astjab.org", "blahblah");
02580 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02581 ASTOBJ_RDLOCK(iterator);
02582 ast_verbose("User: %s\n", iterator->name);
02583 for (resource = iterator->resources; resource; resource = resource->next) {
02584 ast_verbose("Resource: %s\n", resource->resource);
02585 if(resource->cap) {
02586 ast_verbose(" client: %s\n", resource->cap->parent->node);
02587 ast_verbose(" version: %s\n", resource->cap->version);
02588 ast_verbose(" Jingle Capable: %d\n", resource->cap->jingle);
02589 }
02590 ast_verbose(" Priority: %d\n", resource->priority);
02591 ast_verbose(" Status: %d\n", resource->status);
02592 ast_verbose(" Message: %s\n", S_OR(resource->description,""));
02593 }
02594 ASTOBJ_UNLOCK(iterator);
02595 });
02596 ast_verbose("\nOooh a working message stack!\n");
02597 AST_LIST_LOCK(&client->messages);
02598 AST_LIST_TRAVERSE(&client->messages, tmp, list) {
02599 ast_verbose(" Message from: %s with id %s @ %s %s\n",tmp->from, S_OR(tmp->id,""), ctime(&tmp->arrived), S_OR(tmp->message, ""));
02600 }
02601 AST_LIST_UNLOCK(&client->messages);
02602 ASTOBJ_UNREF(client, aji_client_destroy);
02603
02604 return CLI_SUCCESS;
02605 }
02606
02607
02608
02609
02610
02611
02612
02613
02614 static int aji_create_client(char *label, struct ast_variable *var, int debug)
02615 {
02616 char *resource;
02617 struct aji_client *client = NULL;
02618 int flag = 0;
02619
02620 client = ASTOBJ_CONTAINER_FIND(&clients,label);
02621 if (!client) {
02622 flag = 1;
02623 client = ast_calloc(1, sizeof(*client));
02624 if (!client) {
02625 ast_log(LOG_ERROR, "Out of memory!\n");
02626 return 0;
02627 }
02628 ASTOBJ_INIT(client);
02629 ASTOBJ_WRLOCK(client);
02630 ASTOBJ_CONTAINER_INIT(&client->buddies);
02631 } else {
02632 ASTOBJ_WRLOCK(client);
02633 ASTOBJ_UNMARK(client);
02634 }
02635 ASTOBJ_CONTAINER_MARKALL(&client->buddies);
02636 ast_copy_string(client->name, label, sizeof(client->name));
02637 ast_copy_string(client->mid, "aaaaa", sizeof(client->mid));
02638
02639
02640 client->debug = debug;
02641 ast_copy_flags(&client->flags, &globalflags, AST_FLAGS_ALL);
02642 client->port = 5222;
02643 client->usetls = 1;
02644 client->usesasl = 1;
02645 client->forcessl = 0;
02646 client->keepalive = 1;
02647 client->timeout = 50;
02648 client->message_timeout = 100;
02649 AST_LIST_HEAD_INIT(&client->messages);
02650 client->component = 0;
02651 ast_copy_string(client->statusmessage, "Online and Available", sizeof(client->statusmessage));
02652 client->priority = 0;
02653 client->status = IKS_SHOW_AVAILABLE;
02654
02655 if (flag) {
02656 client->authorized = 0;
02657 client->state = AJI_DISCONNECTED;
02658 }
02659 while (var) {
02660 if (!strcasecmp(var->name, "username"))
02661 ast_copy_string(client->user, var->value, sizeof(client->user));
02662 else if (!strcasecmp(var->name, "serverhost"))
02663 ast_copy_string(client->serverhost, var->value, sizeof(client->serverhost));
02664 else if (!strcasecmp(var->name, "secret"))
02665 ast_copy_string(client->password, var->value, sizeof(client->password));
02666 else if (!strcasecmp(var->name, "statusmessage"))
02667 ast_copy_string(client->statusmessage, var->value, sizeof(client->statusmessage));
02668 else if (!strcasecmp(var->name, "port"))
02669 client->port = atoi(var->value);
02670 else if (!strcasecmp(var->name, "timeout"))
02671 client->message_timeout = atoi(var->value);
02672 else if (!strcasecmp(var->name, "debug"))
02673 client->debug = (ast_false(var->value)) ? 0 : 1;
02674 else if (!strcasecmp(var->name, "type")) {
02675 if (!strcasecmp(var->value, "component"))
02676 client->component = 1;
02677 } else if (!strcasecmp(var->name, "usetls")) {
02678 client->usetls = (ast_false(var->value)) ? 0 : 1;
02679 } else if (!strcasecmp(var->name, "usesasl")) {
02680 client->usesasl = (ast_false(var->value)) ? 0 : 1;
02681 } else if (!strcasecmp(var->name, "forceoldssl"))
02682 client->forcessl = (ast_false(var->value)) ? 0 : 1;
02683 else if (!strcasecmp(var->name, "keepalive"))
02684 client->keepalive = (ast_false(var->value)) ? 0 : 1;
02685 else if (!strcasecmp(var->name, "autoprune"))
02686 ast_set2_flag(&client->flags, ast_true(var->value), AJI_AUTOPRUNE);
02687 else if (!strcasecmp(var->name, "autoregister"))
02688 ast_set2_flag(&client->flags, ast_true(var->value), AJI_AUTOREGISTER);
02689 else if (!strcasecmp(var->name, "buddy"))
02690 aji_create_buddy((char *)var->value, client);
02691 else if (!strcasecmp(var->name, "priority"))
02692 client->priority = atoi(var->value);
02693 else if (!strcasecmp(var->name, "status")) {
02694 if (!strcasecmp(var->value, "unavailable"))
02695 client->status = IKS_SHOW_UNAVAILABLE;
02696 else
02697 if (!strcasecmp(var->value, "available")
02698 || !strcasecmp(var->value, "online"))
02699 client->status = IKS_SHOW_AVAILABLE;
02700 else
02701 if (!strcasecmp(var->value, "chat")
02702 || !strcasecmp(var->value, "chatty"))
02703 client->status = IKS_SHOW_CHAT;
02704 else
02705 if (!strcasecmp(var->value, "away"))
02706 client->status = IKS_SHOW_AWAY;
02707 else
02708 if (!strcasecmp(var->value, "xa")
02709 || !strcasecmp(var->value, "xaway"))
02710 client->status = IKS_SHOW_XA;
02711 else
02712 if (!strcasecmp(var->value, "dnd"))
02713 client->status = IKS_SHOW_DND;
02714 else
02715 if (!strcasecmp(var->value, "invisible"))
02716 #ifdef IKS_SHOW_INVISIBLE
02717 client->status = IKS_SHOW_INVISIBLE;
02718 #else
02719 {
02720 ast_log(LOG_WARNING, "Your iksemel doesn't support invisible status: falling back to DND\n");
02721 client->status = IKS_SHOW_DND;
02722 }
02723 #endif
02724 else
02725 ast_log(LOG_WARNING, "Unknown presence status: %s\n", var->value);
02726 }
02727
02728
02729
02730
02731 var = var->next;
02732 }
02733 if (!flag) {
02734 ASTOBJ_UNLOCK(client);
02735 ASTOBJ_UNREF(client, aji_client_destroy);
02736 return 1;
02737 }
02738
02739 ast_copy_string(client->name_space, (client->component) ? "jabber:component:accept" : "jabber:client", sizeof(client->name_space));
02740 client->p = iks_stream_new(client->name_space, client, aji_act_hook);
02741 if (!client->p) {
02742 ast_log(LOG_ERROR, "Failed to create stream for client '%s'!\n", client->name);
02743 return 0;
02744 }
02745 client->stack = iks_stack_new(8192, 8192);
02746 if (!client->stack) {
02747 ast_log(LOG_ERROR, "Failed to allocate stack for client '%s'\n", client->name);
02748 return 0;
02749 }
02750 client->f = iks_filter_new();
02751 if (!client->f) {
02752 ast_log(LOG_ERROR, "Failed to create filter for client '%s'\n", client->name);
02753 return 0;
02754 }
02755 if (!strchr(client->user, '/') && !client->component) {
02756 resource = NULL;
02757 if (asprintf(&resource, "%s/asterisk", client->user) >= 0) {
02758 client->jid = iks_id_new(client->stack, resource);
02759 ast_free(resource);
02760 }
02761 } else
02762 client->jid = iks_id_new(client->stack, client->user);
02763 if (client->component) {
02764 iks_filter_add_rule(client->f, aji_dinfo_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
02765 iks_filter_add_rule(client->f, aji_ditems_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#items", IKS_RULE_DONE);
02766 iks_filter_add_rule(client->f, aji_register_query_handler, client, IKS_RULE_SUBTYPE, IKS_TYPE_GET, IKS_RULE_NS, "jabber:iq:register", IKS_RULE_DONE);
02767 iks_filter_add_rule(client->f, aji_register_approve_handler, client, IKS_RULE_SUBTYPE, IKS_TYPE_SET, IKS_RULE_NS, "jabber:iq:register", IKS_RULE_DONE);
02768 } else {
02769 iks_filter_add_rule(client->f, aji_client_info_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
02770 }
02771 if (!strchr(client->user, '/') && !client->component) {
02772 resource = NULL;
02773 if (asprintf(&resource, "%s/asterisk", client->user) >= 0) {
02774 client->jid = iks_id_new(client->stack, resource);
02775 ast_free(resource);
02776 }
02777 } else
02778 client->jid = iks_id_new(client->stack, client->user);
02779 iks_set_log_hook(client->p, aji_log_hook);
02780 ASTOBJ_UNLOCK(client);
02781 ASTOBJ_CONTAINER_LINK(&clients,client);
02782 return 1;
02783 }
02784
02785 #if 0
02786
02787
02788
02789
02790
02791
02792 static int aji_create_transport(char *label, struct aji_client *client)
02793 {
02794 char *server = NULL, *buddyname = NULL, *user = NULL, *pass = NULL;
02795 struct aji_buddy *buddy = NULL;
02796
02797 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies,label);
02798 if (!buddy) {
02799 buddy = ast_calloc(1, sizeof(*buddy));
02800 if(!buddy) {
02801 ast_log(LOG_WARNING, "Out of memory\n");
02802 return 0;
02803 }
02804 ASTOBJ_INIT(buddy);
02805 }
02806 ASTOBJ_WRLOCK(buddy);
02807 server = label;
02808 if ((buddyname = strchr(label, ','))) {
02809 *buddyname = '\0';
02810 buddyname++;
02811 if (buddyname && buddyname[0] != '\0') {
02812 if ((user = strchr(buddyname, ','))) {
02813 *user = '\0';
02814 user++;
02815 if (user && user[0] != '\0') {
02816 if ((pass = strchr(user, ','))) {
02817 *pass = '\0';
02818 pass++;
02819 ast_copy_string(buddy->pass, pass, sizeof(buddy->pass));
02820 ast_copy_string(buddy->user, user, sizeof(buddy->user));
02821 ast_copy_string(buddy->name, buddyname, sizeof(buddy->name));
02822 ast_copy_string(buddy->server, server, sizeof(buddy->server));
02823 return 1;
02824 }
02825 }
02826 }
02827 }
02828 }
02829 ASTOBJ_UNLOCK(buddy);
02830 ASTOBJ_UNMARK(buddy);
02831 ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
02832 return 0;
02833 }
02834 #endif
02835
02836
02837
02838
02839
02840
02841
02842 static int aji_create_buddy(char *label, struct aji_client *client)
02843 {
02844 struct aji_buddy *buddy = NULL;
02845 int flag = 0;
02846 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies,label);
02847 if (!buddy) {
02848 flag = 1;
02849 buddy = ast_calloc(1, sizeof(*buddy));
02850 if(!buddy) {
02851 ast_log(LOG_WARNING, "Out of memory\n");
02852 return 0;
02853 }
02854 ASTOBJ_INIT(buddy);
02855 }
02856 ASTOBJ_WRLOCK(buddy);
02857 ast_copy_string(buddy->name, label, sizeof(buddy->name));
02858 ASTOBJ_UNLOCK(buddy);
02859 if(flag)
02860 ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
02861 else {
02862 ASTOBJ_UNMARK(buddy);
02863 ASTOBJ_UNREF(buddy, aji_buddy_destroy);
02864 }
02865 return 1;
02866 }
02867
02868
02869 static int aji_load_config(int reload)
02870 {
02871 char *cat = NULL;
02872 int debug = 1;
02873 struct ast_config *cfg = NULL;
02874 struct ast_variable *var = NULL;
02875 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
02876
02877 if ((cfg = ast_config_load(JABBER_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
02878 return -1;
02879
02880
02881 ast_set_flag(&globalflags, AJI_AUTOPRUNE | AJI_AUTOREGISTER);
02882
02883 if (!cfg) {
02884 ast_log(LOG_WARNING, "No such configuration file %s\n", JABBER_CONFIG);
02885 return 0;
02886 }
02887
02888 cat = ast_category_browse(cfg, NULL);
02889 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
02890 if (!strcasecmp(var->name, "debug"))
02891 debug = (ast_false(ast_variable_retrieve(cfg, "general", "debug"))) ? 0 : 1;
02892 else if (!strcasecmp(var->name, "autoprune"))
02893 ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOPRUNE);
02894 else if (!strcasecmp(var->name, "autoregister"))
02895 ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOREGISTER);
02896 }
02897
02898 while (cat) {
02899 if (strcasecmp(cat, "general")) {
02900 var = ast_variable_browse(cfg, cat);
02901 aji_create_client(cat, var, debug);
02902 }
02903 cat = ast_category_browse(cfg, cat);
02904 }
02905 ast_config_destroy(cfg);
02906 return 1;
02907 }
02908
02909
02910
02911
02912
02913
02914
02915 struct aji_client *ast_aji_get_client(const char *name)
02916 {
02917 struct aji_client *client = NULL;
02918 char *aux = NULL;
02919
02920 client = ASTOBJ_CONTAINER_FIND(&clients, name);
02921 if (!client && strchr(name, '@')) {
02922 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02923 aux = ast_strdupa(iterator->user);
02924 if (strchr(aux, '/')) {
02925
02926 aux = strsep(&aux, "/");
02927 }
02928 if (!strncasecmp(aux, name, strlen(aux))) {
02929 client = iterator;
02930 }
02931 });
02932 }
02933
02934 return client;
02935 }
02936
02937 struct aji_client_container *ast_aji_get_clients(void)
02938 {
02939 return &clients;
02940 }
02941
02942 static char mandescr_jabber_send[] =
02943 "Description: Sends a message to a Jabber Client.\n"
02944 "Variables: \n"
02945 " Jabber: Client or transport Asterisk uses to connect to JABBER.\n"
02946 " ScreenName: User Name to message.\n"
02947 " Message: Message to be sent to the buddy\n";
02948
02949
02950
02951
02952
02953
02954
02955 static int manager_jabber_send(struct mansession *s, const struct message *m)
02956 {
02957 struct aji_client *client = NULL;
02958 const char *id = astman_get_header(m,"ActionID");
02959 const char *jabber = astman_get_header(m,"Jabber");
02960 const char *screenname = astman_get_header(m,"ScreenName");
02961 const char *message = astman_get_header(m,"Message");
02962
02963 if (ast_strlen_zero(jabber)) {
02964 astman_send_error(s, m, "No transport specified");
02965 return 0;
02966 }
02967 if (ast_strlen_zero(screenname)) {
02968 astman_send_error(s, m, "No ScreenName specified");
02969 return 0;
02970 }
02971 if (ast_strlen_zero(message)) {
02972 astman_send_error(s, m, "No Message specified");
02973 return 0;
02974 }
02975
02976 astman_send_ack(s, m, "Attempting to send Jabber Message");
02977 client = ast_aji_get_client(jabber);
02978 if (!client) {
02979 astman_send_error(s, m, "Could not find Sender");
02980 return 0;
02981 }
02982 if (strchr(screenname, '@') && message){
02983 ast_aji_send_chat(client, screenname, message);
02984 astman_append(s, "Response: Success\r\n");
02985 if (!ast_strlen_zero(id))
02986 astman_append(s, "ActionID: %s\r\n",id);
02987 return 0;
02988 }
02989 astman_append(s, "Response: Error\r\n");
02990 if (!ast_strlen_zero(id))
02991 astman_append(s, "ActionID: %s\r\n",id);
02992 return 0;
02993 }
02994
02995
02996 static int aji_reload(int reload)
02997 {
02998 int res;
02999
03000 ASTOBJ_CONTAINER_MARKALL(&clients);
03001 if (!(res = aji_load_config(reload))) {
03002 ast_log(LOG_ERROR, "JABBER: Failed to load config.\n");
03003 return 0;
03004 } else if (res == -1)
03005 return 1;
03006
03007 ASTOBJ_CONTAINER_PRUNE_MARKED(&clients, aji_client_destroy);
03008 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
03009 ASTOBJ_RDLOCK(iterator);
03010 if(iterator->state == AJI_DISCONNECTED) {
03011 if (!iterator->thread)
03012 ast_pthread_create_background(&iterator->thread, NULL, aji_recv_loop, iterator);
03013 } else if (iterator->state == AJI_CONNECTING)
03014 aji_get_roster(iterator);
03015 ASTOBJ_UNLOCK(iterator);
03016 });
03017
03018 return 1;
03019 }
03020
03021
03022 static int unload_module(void)
03023 {
03024
03025 ast_cli_unregister_multiple(aji_cli, sizeof(aji_cli) / sizeof(struct ast_cli_entry));
03026 ast_unregister_application(app_ajisend);
03027 ast_unregister_application(app_ajistatus);
03028 ast_manager_unregister("JabberSend");
03029 ast_custom_function_unregister(&jabberstatus_function);
03030
03031 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
03032 ASTOBJ_RDLOCK(iterator);
03033 ast_debug(3, "JABBER: Releasing and disconnecting client: %s\n", iterator->name);
03034 iterator->state = AJI_DISCONNECTING;
03035 ast_aji_disconnect(iterator);
03036 pthread_join(iterator->thread, NULL);
03037 ASTOBJ_UNLOCK(iterator);
03038 });
03039
03040 ASTOBJ_CONTAINER_DESTROYALL(&clients, aji_client_destroy);
03041 ASTOBJ_CONTAINER_DESTROY(&clients);
03042 return 0;
03043 }
03044
03045
03046 static int load_module(void)
03047 {
03048 ASTOBJ_CONTAINER_INIT(&clients);
03049 if(!aji_reload(0))
03050 return AST_MODULE_LOAD_DECLINE;
03051 ast_manager_register2("JabberSend", EVENT_FLAG_SYSTEM, manager_jabber_send,
03052 "Sends a message to a Jabber Client", mandescr_jabber_send);
03053 ast_register_application(app_ajisend, aji_send_exec, ajisend_synopsis, ajisend_descrip);
03054 ast_register_application(app_ajistatus, aji_status_exec, ajistatus_synopsis, ajistatus_descrip);
03055 ast_cli_register_multiple(aji_cli, sizeof(aji_cli) / sizeof(struct ast_cli_entry));
03056 ast_custom_function_register(&jabberstatus_function);
03057
03058 return 0;
03059 }
03060
03061
03062 static int reload(void)
03063 {
03064 aji_reload(1);
03065 return 0;
03066 }
03067
03068 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "AJI - Asterisk Jabber Interface",
03069 .load = load_module,
03070 .unload = unload_module,
03071 .reload = reload,
03072 );