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: 198384 $")
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_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 - 2, 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 switch (ret) {
00692 case IKS_NOMEM:
00693 ast_log(LOG_WARNING, "Parsing failure: Out of memory.\n");
00694 break;
00695 case IKS_BADXML:
00696 ast_log(LOG_WARNING, "Parsing failure: Invalid XML.\n");
00697 break;
00698 case IKS_HOOK:
00699 ast_log(LOG_WARNING, "Parsing failure: Hook returned an error.\n");
00700 break;
00701 }
00702 if (ret != IKS_OK) {
00703 return ret;
00704 }
00705 ast_debug(3, "XML parsing successful\n");
00706 }
00707 return IKS_OK;
00708 }
00709
00710
00711
00712
00713
00714
00715
00716 static int aji_send_header(struct aji_client *client, const char *to)
00717 {
00718 char *msg;
00719 int len, err;
00720
00721 len = 91 + strlen(client->name_space) + 6 + strlen(to) + 16 + 1;
00722 msg = iks_malloc(len);
00723 if (!msg)
00724 return IKS_NOMEM;
00725 sprintf(msg, "<?xml version='1.0'?>"
00726 "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='"
00727 "%s' to='%s' version='1.0'>", client->name_space, to);
00728 err = aji_send_raw(client, msg);
00729 iks_free(msg);
00730 if (err != IKS_OK)
00731 return err;
00732
00733 return IKS_OK;
00734 }
00735
00736
00737
00738
00739
00740
00741
00742 int ast_aji_send(struct aji_client *client, iks *x)
00743 {
00744 return aji_send_raw(client, iks_string(iks_stack(x), x));
00745 }
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755 static int aji_send_raw(struct aji_client *client, const char *xmlstr)
00756 {
00757 int ret;
00758 #ifdef HAVE_OPENSSL
00759 int len = strlen(xmlstr);
00760
00761 if (aji_is_secure(client)) {
00762 ret = SSL_write(client->ssl_session, xmlstr, len);
00763 if (ret) {
00764
00765
00766 aji_log_hook(client, xmlstr, len, 0);
00767 return IKS_OK;
00768 }
00769 }
00770 #endif
00771
00772
00773 ret = iks_send_raw(client->p, xmlstr);
00774 if (ret != IKS_OK)
00775 return ret;
00776
00777 return IKS_OK;
00778 }
00779
00780
00781
00782
00783
00784
00785
00786
00787 static void aji_log_hook(void *data, const char *xmpp, size_t size, int is_incoming)
00788 {
00789 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00790
00791 if (!ast_strlen_zero(xmpp))
00792 manager_event(EVENT_FLAG_USER, "JabberEvent", "Account: %s\r\nPacket: %s\r\n", client->name, xmpp);
00793
00794 if (client->debug) {
00795 if (is_incoming)
00796 ast_verbose("\nJABBER: %s INCOMING: %s\n", client->name, xmpp);
00797 else {
00798 if( strlen(xmpp) == 1) {
00799 if(option_debug > 2 && xmpp[0] == ' ') {
00800 ast_verbose("\nJABBER: Keep alive packet\n");
00801 }
00802 } else
00803 ast_verbose("\nJABBER: %s OUTGOING: %s\n", client->name, xmpp);
00804 }
00805
00806 }
00807 ASTOBJ_UNREF(client, aji_client_destroy);
00808 }
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819 static int aji_start_sasl(struct aji_client *client, enum ikssasltype type, char *username, char *pass)
00820 {
00821 iks *x = NULL;
00822 int len;
00823 char *s;
00824 char *base64;
00825
00826
00827
00828
00829 if ((type & IKS_STREAM_SASL_MD5) && !aji_is_secure(client))
00830 return iks_start_sasl(client->p, IKS_SASL_DIGEST_MD5, username, pass);
00831 if (!(type & IKS_STREAM_SASL_PLAIN)) {
00832 ast_log(LOG_ERROR, "Server does not support SASL PLAIN authentication\n");
00833 return IKS_NET_NOTSUPP;
00834 }
00835
00836 x = iks_new("auth");
00837 if (!x) {
00838 ast_log(LOG_ERROR, "Out of memory.\n");
00839 return IKS_NET_NOTSUPP;
00840 }
00841
00842 iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_SASL);
00843 len = strlen(username) + strlen(pass) + 3;
00844 s = alloca(len);
00845 base64 = alloca((len + 2) * 4 / 3);
00846 iks_insert_attrib(x, "mechanism", "PLAIN");
00847 snprintf(s, len, "%c%s%c%s", 0, username, 0, pass);
00848
00849
00850
00851
00852
00853 ast_base64encode(base64, (const unsigned char *) s, len - 1, (len + 2) * 4 / 3);
00854 iks_insert_cdata(x, base64, 0);
00855 ast_aji_send(client, x);
00856 iks_delete(x);
00857
00858 return IKS_OK;
00859 }
00860
00861
00862
00863
00864
00865
00866
00867
00868 static int aji_act_hook(void *data, int type, iks *node)
00869 {
00870 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
00871 ikspak *pak = NULL;
00872 iks *auth = NULL;
00873 int features = 0;
00874
00875 if(!node) {
00876 ast_log(LOG_ERROR, "aji_act_hook was called with out a packet\n");
00877 ASTOBJ_UNREF(client, aji_client_destroy);
00878 return IKS_HOOK;
00879 }
00880
00881 if (client->state == AJI_DISCONNECTING) {
00882 ASTOBJ_UNREF(client, aji_client_destroy);
00883 return IKS_HOOK;
00884 }
00885
00886 pak = iks_packet(node);
00887
00888 if (!client->component) {
00889 switch (type) {
00890 case IKS_NODE_START:
00891 if (client->usetls && !aji_is_secure(client)) {
00892 #ifndef HAVE_OPENSSL
00893 ast_log(LOG_ERROR, "OpenSSL not installed. You need to install OpenSSL on this system, or disable the TLS option in your configuration file\n");
00894 ASTOBJ_UNREF(client, aji_client_destroy);
00895 return IKS_HOOK;
00896 #else
00897 if (aji_start_tls(client) == IKS_NET_TLSFAIL) {
00898 ast_log(LOG_ERROR, "Could not start TLS\n");
00899 ASTOBJ_UNREF(client, aji_client_destroy);
00900 return IKS_HOOK;
00901 }
00902 #endif
00903 break;
00904 }
00905 if (!client->usesasl) {
00906 iks_filter_add_rule(client->f, aji_client_connect, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->mid, IKS_RULE_DONE);
00907 auth = jabber_make_auth(client->jid, client->password, iks_find_attrib(node, "id"));
00908 if (auth) {
00909 iks_insert_attrib(auth, "id", client->mid);
00910 iks_insert_attrib(auth, "to", client->jid->server);
00911 ast_aji_increment_mid(client->mid);
00912 ast_aji_send(client, auth);
00913 iks_delete(auth);
00914 } else
00915 ast_log(LOG_ERROR, "Out of memory.\n");
00916 }
00917 break;
00918
00919 case IKS_NODE_NORMAL:
00920 #ifdef HAVE_OPENSSL
00921 if (client->stream_flags & TRY_SECURE) {
00922 if (!strcmp("proceed", iks_name(node))) {
00923 return aji_tls_handshake(client);
00924 }
00925 }
00926 #endif
00927 if (!strcmp("stream:features", iks_name(node))) {
00928 features = iks_stream_features(node);
00929 if (client->usesasl) {
00930 if (client->usetls && !aji_is_secure(client))
00931 break;
00932 if (client->authorized) {
00933 if (features & IKS_STREAM_BIND) {
00934 iks_filter_add_rule(client->f, aji_client_connect, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_DONE);
00935 auth = iks_make_resource_bind(client->jid);
00936 if (auth) {
00937 iks_insert_attrib(auth, "id", client->mid);
00938 ast_aji_increment_mid(client->mid);
00939 ast_aji_send(client, auth);
00940 iks_delete(auth);
00941 } else {
00942 ast_log(LOG_ERROR, "Out of memory.\n");
00943 break;
00944 }
00945 }
00946 if (features & IKS_STREAM_SESSION) {
00947 iks_filter_add_rule (client->f, aji_client_connect, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, "auth", IKS_RULE_DONE);
00948 auth = iks_make_session();
00949 if (auth) {
00950 iks_insert_attrib(auth, "id", "auth");
00951 ast_aji_increment_mid(client->mid);
00952 ast_aji_send(client, auth);
00953 iks_delete(auth);
00954 } else {
00955 ast_log(LOG_ERROR, "Out of memory.\n");
00956 }
00957 }
00958 } else {
00959 int ret;
00960 if (!client->jid->user) {
00961 ast_log(LOG_ERROR, "Malformed Jabber ID : %s (domain missing?)\n", client->jid->full);
00962 break;
00963 }
00964
00965 ret = aji_start_sasl(client, features, client->jid->user, client->password);
00966 if (ret != IKS_OK) {
00967 ASTOBJ_UNREF(client, aji_client_destroy);
00968 return IKS_HOOK;
00969 }
00970 break;
00971 }
00972 }
00973 } else if (!strcmp("failure", iks_name(node))) {
00974 ast_log(LOG_ERROR, "JABBER: encryption failure. possible bad password.\n");
00975 } else if (!strcmp("success", iks_name(node))) {
00976 client->authorized = 1;
00977 aji_send_header(client, client->jid->server);
00978 }
00979 break;
00980 case IKS_NODE_ERROR:
00981 ast_log(LOG_ERROR, "JABBER: Node Error\n");
00982 ASTOBJ_UNREF(client, aji_client_destroy);
00983 return IKS_HOOK;
00984 break;
00985 case IKS_NODE_STOP:
00986 ast_log(LOG_WARNING, "JABBER: Disconnected\n");
00987 ASTOBJ_UNREF(client, aji_client_destroy);
00988 return IKS_HOOK;
00989 break;
00990 }
00991 } else if (client->state != AJI_CONNECTED && client->component) {
00992 switch (type) {
00993 case IKS_NODE_START:
00994 if (client->state == AJI_DISCONNECTED) {
00995 char secret[160], shasum[320], *handshake;
00996
00997 sprintf(secret, "%s%s", pak->id, client->password);
00998 ast_sha1_hash(shasum, secret);
00999 handshake = NULL;
01000 if (asprintf(&handshake, "<handshake>%s</handshake>", shasum) >= 0) {
01001 aji_send_raw(client, handshake);
01002 ast_free(handshake);
01003 handshake = NULL;
01004 }
01005 client->state = AJI_CONNECTING;
01006 if(aji_recv(client, 1) == 2)
01007 client->state = AJI_CONNECTED;
01008 else
01009 ast_log(LOG_WARNING, "Jabber didn't seem to handshake, failed to authenticate.\n");
01010 break;
01011 }
01012 break;
01013
01014 case IKS_NODE_NORMAL:
01015 break;
01016
01017 case IKS_NODE_ERROR:
01018 ast_log(LOG_ERROR, "JABBER: Node Error\n");
01019 ASTOBJ_UNREF(client, aji_client_destroy);
01020 return IKS_HOOK;
01021
01022 case IKS_NODE_STOP:
01023 ast_log(LOG_WARNING, "JABBER: Disconnected\n");
01024 ASTOBJ_UNREF(client, aji_client_destroy);
01025 return IKS_HOOK;
01026 }
01027 }
01028
01029 switch (pak->type) {
01030 case IKS_PAK_NONE:
01031 ast_debug(1, "JABBER: I don't know what to do with paktype NONE.\n");
01032 break;
01033 case IKS_PAK_MESSAGE:
01034 aji_handle_message(client, pak);
01035 ast_debug(1, "JABBER: Handling paktype MESSAGE.\n");
01036 break;
01037 case IKS_PAK_PRESENCE:
01038 aji_handle_presence(client, pak);
01039 ast_debug(1, "JABBER: Handling paktype PRESENCE\n");
01040 break;
01041 case IKS_PAK_S10N:
01042 aji_handle_subscribe(client, pak);
01043 ast_debug(1, "JABBER: Handling paktype S10N\n");
01044 break;
01045 case IKS_PAK_IQ:
01046 ast_debug(1, "JABBER: Handling paktype IQ\n");
01047 aji_handle_iq(client, node);
01048 break;
01049 default:
01050 ast_debug(1, "JABBER: I don't know anything about paktype '%d'\n", pak->type);
01051 break;
01052 }
01053
01054 iks_filter_packet(client->f, pak);
01055
01056 if (node)
01057 iks_delete(node);
01058
01059 ASTOBJ_UNREF(client, aji_client_destroy);
01060 return IKS_OK;
01061 }
01062
01063
01064
01065
01066
01067
01068 static int aji_register_approve_handler(void *data, ikspak *pak)
01069 {
01070 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01071 iks *iq = NULL, *presence = NULL, *x = NULL;
01072
01073 iq = iks_new("iq");
01074 presence = iks_new("presence");
01075 x = iks_new("x");
01076 if (client && iq && presence && x) {
01077 if (!iks_find(pak->query, "remove")) {
01078 iks_insert_attrib(iq, "from", client->jid->full);
01079 iks_insert_attrib(iq, "to", pak->from->full);
01080 iks_insert_attrib(iq, "id", pak->id);
01081 iks_insert_attrib(iq, "type", "result");
01082 ast_aji_send(client, iq);
01083
01084 iks_insert_attrib(presence, "from", client->jid->full);
01085 iks_insert_attrib(presence, "to", pak->from->partial);
01086 iks_insert_attrib(presence, "id", client->mid);
01087 ast_aji_increment_mid(client->mid);
01088 iks_insert_attrib(presence, "type", "subscribe");
01089 iks_insert_attrib(x, "xmlns", "vcard-temp:x:update");
01090 iks_insert_node(presence, x);
01091 ast_aji_send(client, presence);
01092 }
01093 } else {
01094 ast_log(LOG_ERROR, "Out of memory.\n");
01095 }
01096
01097
01098 iks_delete(iq);
01099 iks_delete(presence);
01100 iks_delete(x);
01101
01102 ASTOBJ_UNREF(client, aji_client_destroy);
01103 return IKS_FILTER_EAT;
01104 }
01105
01106
01107
01108
01109
01110
01111 static int aji_register_query_handler(void *data, ikspak *pak)
01112 {
01113 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01114 struct aji_buddy *buddy = NULL;
01115 char *node = NULL;
01116 iks *iq = NULL, *query = NULL;
01117
01118 client = (struct aji_client *) data;
01119
01120 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01121 if (!buddy) {
01122 iks *error = NULL, *notacceptable = NULL;
01123
01124 ast_log(LOG_ERROR, "Someone.... %s tried to register but they aren't allowed\n", pak->from->partial);
01125 iq = iks_new("iq");
01126 query = iks_new("query");
01127 error = iks_new("error");
01128 notacceptable = iks_new("not-acceptable");
01129 if(iq && query && error && notacceptable) {
01130 iks_insert_attrib(iq, "type", "error");
01131 iks_insert_attrib(iq, "from", client->user);
01132 iks_insert_attrib(iq, "to", pak->from->full);
01133 iks_insert_attrib(iq, "id", pak->id);
01134 iks_insert_attrib(query, "xmlns", "jabber:iq:register");
01135 iks_insert_attrib(error, "code" , "406");
01136 iks_insert_attrib(error, "type", "modify");
01137 iks_insert_attrib(notacceptable, "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas");
01138 iks_insert_node(iq, query);
01139 iks_insert_node(iq, error);
01140 iks_insert_node(error, notacceptable);
01141 ast_aji_send(client, iq);
01142 } else {
01143 ast_log(LOG_ERROR, "Out of memory.\n");
01144 }
01145
01146 iks_delete(error);
01147 iks_delete(notacceptable);
01148 } else if (!(node = iks_find_attrib(pak->query, "node"))) {
01149 iks *instructions = NULL;
01150 char *explain = "Welcome to Asterisk - the Open Source PBX.\n";
01151 iq = iks_new("iq");
01152 query = iks_new("query");
01153 instructions = iks_new("instructions");
01154 if (iq && query && instructions && client) {
01155 iks_insert_attrib(iq, "from", client->user);
01156 iks_insert_attrib(iq, "to", pak->from->full);
01157 iks_insert_attrib(iq, "id", pak->id);
01158 iks_insert_attrib(iq, "type", "result");
01159 iks_insert_attrib(query, "xmlns", "jabber:iq:register");
01160 iks_insert_cdata(instructions, explain, 0);
01161 iks_insert_node(iq, query);
01162 iks_insert_node(query, instructions);
01163 ast_aji_send(client, iq);
01164 } else {
01165 ast_log(LOG_ERROR, "Out of memory.\n");
01166 }
01167
01168 iks_delete(instructions);
01169 }
01170 iks_delete(iq);
01171 iks_delete(query);
01172 ASTOBJ_UNREF(client, aji_client_destroy);
01173 return IKS_FILTER_EAT;
01174 }
01175
01176
01177
01178
01179
01180
01181
01182 static int aji_ditems_handler(void *data, ikspak *pak)
01183 {
01184 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01185 char *node = NULL;
01186
01187 if (!(node = iks_find_attrib(pak->query, "node"))) {
01188 iks *iq = NULL, *query = NULL, *item = NULL;
01189 iq = iks_new("iq");
01190 query = iks_new("query");
01191 item = iks_new("item");
01192
01193 if (iq && query && item) {
01194 iks_insert_attrib(iq, "from", client->user);
01195 iks_insert_attrib(iq, "to", pak->from->full);
01196 iks_insert_attrib(iq, "id", pak->id);
01197 iks_insert_attrib(iq, "type", "result");
01198 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01199 iks_insert_attrib(item, "node", "http://jabber.org/protocol/commands");
01200 iks_insert_attrib(item, "name", "Million Dollar Asterisk Commands");
01201 iks_insert_attrib(item, "jid", client->user);
01202
01203 iks_insert_node(iq, query);
01204 iks_insert_node(query, item);
01205 ast_aji_send(client, iq);
01206 } else {
01207 ast_log(LOG_ERROR, "Out of memory.\n");
01208 }
01209
01210 iks_delete(iq);
01211 iks_delete(query);
01212 iks_delete(item);
01213
01214 } else if (!strcasecmp(node, "http://jabber.org/protocol/commands")) {
01215 iks *iq, *query, *confirm;
01216 iq = iks_new("iq");
01217 query = iks_new("query");
01218 confirm = iks_new("item");
01219 if (iq && query && confirm && client) {
01220 iks_insert_attrib(iq, "from", client->user);
01221 iks_insert_attrib(iq, "to", pak->from->full);
01222 iks_insert_attrib(iq, "id", pak->id);
01223 iks_insert_attrib(iq, "type", "result");
01224 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01225 iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
01226 iks_insert_attrib(confirm, "node", "confirmaccount");
01227 iks_insert_attrib(confirm, "name", "Confirm AIM account");
01228 iks_insert_attrib(confirm, "jid", "blog.astjab.org");
01229
01230 iks_insert_node(iq, query);
01231 iks_insert_node(query, confirm);
01232 ast_aji_send(client, iq);
01233 } else {
01234 ast_log(LOG_ERROR, "Out of memory.\n");
01235 }
01236
01237 iks_delete(iq);
01238 iks_delete(query);
01239 iks_delete(confirm);
01240
01241 } else if (!strcasecmp(node, "confirmaccount")) {
01242 iks *iq = NULL, *query = NULL, *feature = NULL;
01243
01244 iq = iks_new("iq");
01245 query = iks_new("query");
01246 feature = iks_new("feature");
01247
01248 if (iq && query && feature && client) {
01249 iks_insert_attrib(iq, "from", client->user);
01250 iks_insert_attrib(iq, "to", pak->from->full);
01251 iks_insert_attrib(iq, "id", pak->id);
01252 iks_insert_attrib(iq, "type", "result");
01253 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01254 iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
01255 iks_insert_node(iq, query);
01256 iks_insert_node(query, feature);
01257 ast_aji_send(client, iq);
01258 } else {
01259 ast_log(LOG_ERROR, "Out of memory.\n");
01260 }
01261
01262 iks_delete(iq);
01263 iks_delete(query);
01264 iks_delete(feature);
01265 }
01266
01267 ASTOBJ_UNREF(client, aji_client_destroy);
01268 return IKS_FILTER_EAT;
01269
01270 }
01271
01272
01273
01274
01275
01276
01277 static int aji_client_info_handler(void *data, ikspak *pak)
01278 {
01279 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01280 struct aji_resource *resource = NULL;
01281 struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01282
01283 resource = aji_find_resource(buddy, pak->from->resource);
01284 if (pak->subtype == IKS_TYPE_RESULT) {
01285 if (!resource) {
01286 ast_log(LOG_NOTICE, "JABBER: Received client info from %s when not requested.\n", pak->from->full);
01287 ASTOBJ_UNREF(client, aji_client_destroy);
01288 return IKS_FILTER_EAT;
01289 }
01290 if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
01291 resource->cap->jingle = 1;
01292 } else
01293 resource->cap->jingle = 0;
01294 } else if (pak->subtype == IKS_TYPE_GET) {
01295 iks *iq, *disco, *ident, *google, *query;
01296 iq = iks_new("iq");
01297 query = iks_new("query");
01298 ident = iks_new("identity");
01299 disco = iks_new("feature");
01300 google = iks_new("feature");
01301 if (iq && ident && disco && google) {
01302 iks_insert_attrib(iq, "from", client->jid->full);
01303 iks_insert_attrib(iq, "to", pak->from->full);
01304 iks_insert_attrib(iq, "type", "result");
01305 iks_insert_attrib(iq, "id", pak->id);
01306 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01307 iks_insert_attrib(ident, "category", "client");
01308 iks_insert_attrib(ident, "type", "pc");
01309 iks_insert_attrib(ident, "name", "asterisk");
01310 iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco#info");
01311 iks_insert_attrib(google, "var", "http://www.google.com/xmpp/protocol/voice/v1");
01312 iks_insert_node(iq, query);
01313 iks_insert_node(query, ident);
01314 iks_insert_node(query, google);
01315 iks_insert_node(query, disco);
01316 ast_aji_send(client, iq);
01317 } else
01318 ast_log(LOG_ERROR, "Out of Memory.\n");
01319
01320 iks_delete(iq);
01321 iks_delete(query);
01322 iks_delete(ident);
01323 iks_delete(google);
01324 iks_delete(disco);
01325 } else if (pak->subtype == IKS_TYPE_ERROR) {
01326 ast_log(LOG_NOTICE, "User %s does not support discovery.\n", pak->from->full);
01327 }
01328 ASTOBJ_UNREF(client, aji_client_destroy);
01329 return IKS_FILTER_EAT;
01330 }
01331
01332
01333
01334
01335
01336
01337 static int aji_dinfo_handler(void *data, ikspak *pak)
01338 {
01339 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01340 char *node = NULL;
01341 struct aji_resource *resource = NULL;
01342 struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01343
01344 resource = aji_find_resource(buddy, pak->from->resource);
01345 if (pak->subtype == IKS_TYPE_ERROR) {
01346 ast_log(LOG_WARNING, "Recieved error from a client, turn on jabber debug!\n");
01347 return IKS_FILTER_EAT;
01348 }
01349 if (pak->subtype == IKS_TYPE_RESULT) {
01350 if (!resource) {
01351 ast_log(LOG_NOTICE,"JABBER: Received client info from %s when not requested.\n", pak->from->full);
01352 ASTOBJ_UNREF(client, aji_client_destroy);
01353 return IKS_FILTER_EAT;
01354 }
01355 if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
01356 resource->cap->jingle = 1;
01357 } else
01358 resource->cap->jingle = 0;
01359 } else if (pak->subtype == IKS_TYPE_GET && !(node = iks_find_attrib(pak->query, "node"))) {
01360 iks *iq, *query, *identity, *disco, *reg, *commands, *gateway, *version, *vcard, *search;
01361
01362 iq = iks_new("iq");
01363 query = iks_new("query");
01364 identity = iks_new("identity");
01365 disco = iks_new("feature");
01366 reg = iks_new("feature");
01367 commands = iks_new("feature");
01368 gateway = iks_new("feature");
01369 version = iks_new("feature");
01370 vcard = iks_new("feature");
01371 search = iks_new("feature");
01372
01373 if (iq && query && identity && disco && reg && commands && gateway && version && vcard && search && client) {
01374 iks_insert_attrib(iq, "from", client->user);
01375 iks_insert_attrib(iq, "to", pak->from->full);
01376 iks_insert_attrib(iq, "id", pak->id);
01377 iks_insert_attrib(iq, "type", "result");
01378 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01379 iks_insert_attrib(identity, "category", "gateway");
01380 iks_insert_attrib(identity, "type", "pstn");
01381 iks_insert_attrib(identity, "name", "Asterisk The Open Source PBX");
01382 iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco");
01383 iks_insert_attrib(reg, "var", "jabber:iq:register");
01384 iks_insert_attrib(commands, "var", "http://jabber.org/protocol/commands");
01385 iks_insert_attrib(gateway, "var", "jabber:iq:gateway");
01386 iks_insert_attrib(version, "var", "jabber:iq:version");
01387 iks_insert_attrib(vcard, "var", "vcard-temp");
01388 iks_insert_attrib(search, "var", "jabber:iq:search");
01389
01390 iks_insert_node(iq, query);
01391 iks_insert_node(query, identity);
01392 iks_insert_node(query, disco);
01393 iks_insert_node(query, reg);
01394 iks_insert_node(query, commands);
01395 iks_insert_node(query, gateway);
01396 iks_insert_node(query, version);
01397 iks_insert_node(query, vcard);
01398 iks_insert_node(query, search);
01399 ast_aji_send(client, iq);
01400 } else {
01401 ast_log(LOG_ERROR, "Out of memory.\n");
01402 }
01403
01404 iks_delete(iq);
01405 iks_delete(query);
01406 iks_delete(identity);
01407 iks_delete(disco);
01408 iks_delete(reg);
01409 iks_delete(commands);
01410 iks_delete(gateway);
01411 iks_delete(version);
01412 iks_delete(vcard);
01413 iks_delete(search);
01414
01415 } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "http://jabber.org/protocol/commands")) {
01416 iks *iq, *query, *confirm;
01417 iq = iks_new("iq");
01418 query = iks_new("query");
01419 confirm = iks_new("item");
01420
01421 if (iq && query && confirm && client) {
01422 iks_insert_attrib(iq, "from", client->user);
01423 iks_insert_attrib(iq, "to", pak->from->full);
01424 iks_insert_attrib(iq, "id", pak->id);
01425 iks_insert_attrib(iq, "type", "result");
01426 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01427 iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
01428 iks_insert_attrib(confirm, "node", "confirmaccount");
01429 iks_insert_attrib(confirm, "name", "Confirm AIM account");
01430 iks_insert_attrib(confirm, "jid", client->user);
01431 iks_insert_node(iq, query);
01432 iks_insert_node(query, confirm);
01433 ast_aji_send(client, iq);
01434 } else {
01435 ast_log(LOG_ERROR, "Out of memory.\n");
01436 }
01437
01438 iks_delete(iq);
01439 iks_delete(query);
01440 iks_delete(confirm);
01441
01442 } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "confirmaccount")) {
01443 iks *iq, *query, *feature;
01444
01445 iq = iks_new("iq");
01446 query = iks_new("query");
01447 feature = iks_new("feature");
01448
01449 if (iq && query && feature && client) {
01450 iks_insert_attrib(iq, "from", client->user);
01451 iks_insert_attrib(iq, "to", pak->from->full);
01452 iks_insert_attrib(iq, "id", pak->id);
01453 iks_insert_attrib(iq, "type", "result");
01454 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01455 iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
01456 iks_insert_node(iq, query);
01457 iks_insert_node(query, feature);
01458 ast_aji_send(client, iq);
01459 } else {
01460 ast_log(LOG_ERROR, "Out of memory.\n");
01461 }
01462
01463 iks_delete(iq);
01464 iks_delete(query);
01465 iks_delete(feature);
01466 }
01467
01468 ASTOBJ_UNREF(client, aji_client_destroy);
01469 return IKS_FILTER_EAT;
01470 }
01471
01472
01473
01474
01475
01476
01477
01478 static void aji_handle_iq(struct aji_client *client, iks *node)
01479 {
01480
01481 }
01482
01483
01484
01485
01486
01487
01488 static void aji_handle_message(struct aji_client *client, ikspak *pak)
01489 {
01490 struct aji_message *insert, *tmp;
01491 int flag = 0;
01492
01493 if (!(insert = ast_calloc(1, sizeof(*insert))))
01494 return;
01495 time(&insert->arrived);
01496 if (iks_find_cdata(pak->x, "body"))
01497 insert->message = ast_strdup(iks_find_cdata(pak->x, "body"));
01498 if (pak->id)
01499 ast_copy_string(insert->id, pak->id, sizeof(insert->message));
01500 if (pak->from)
01501 insert->from = ast_strdup(pak->from->full);
01502 AST_LIST_LOCK(&client->messages);
01503 AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, tmp, list) {
01504 if (flag) {
01505 AST_LIST_REMOVE_CURRENT(list);
01506 if (tmp->from)
01507 ast_free(tmp->from);
01508 if (tmp->message)
01509 ast_free(tmp->message);
01510 } else if (difftime(time(NULL), tmp->arrived) >= client->message_timeout) {
01511 flag = 1;
01512 AST_LIST_REMOVE_CURRENT(list);
01513 if (tmp->from)
01514 ast_free(tmp->from);
01515 if (tmp->message)
01516 ast_free(tmp->message);
01517 }
01518 }
01519 AST_LIST_TRAVERSE_SAFE_END;
01520 AST_LIST_INSERT_HEAD(&client->messages, insert, list);
01521 AST_LIST_UNLOCK(&client->messages);
01522 }
01523
01524
01525
01526
01527
01528 static void aji_handle_presence(struct aji_client *client, ikspak *pak)
01529 {
01530 int status, priority;
01531 struct aji_buddy *buddy;
01532 struct aji_resource *tmp = NULL, *last = NULL, *found = NULL;
01533 char *ver, *node, *descrip, *type;
01534
01535 if(client->state != AJI_CONNECTED)
01536 aji_create_buddy(pak->from->partial, client);
01537
01538 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01539 if (!buddy && pak->from->partial) {
01540
01541 if (!strcmp((const char *)pak->from->partial, (const char *)client->jid->partial))
01542 aji_create_buddy(pak->from->partial, client);
01543 else
01544 ast_log(LOG_NOTICE, "Got presence packet from %s, someone not in our roster!!!!\n", pak->from->partial);
01545 return;
01546 }
01547 type = iks_find_attrib(pak->x, "type");
01548 if(client->component && type &&!strcasecmp("probe", type)) {
01549 aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), client->status, client->statusmessage);
01550 ast_verbose("what i was looking for \n");
01551 }
01552 ASTOBJ_WRLOCK(buddy);
01553 status = (pak->show) ? pak->show : 6;
01554 priority = atoi((iks_find_cdata(pak->x, "priority")) ? iks_find_cdata(pak->x, "priority") : "0");
01555 tmp = buddy->resources;
01556 descrip = ast_strdup(iks_find_cdata(pak->x,"status"));
01557
01558 while (tmp && pak->from->resource) {
01559 if (!strcasecmp(tmp->resource, pak->from->resource)) {
01560 tmp->status = status;
01561 if (tmp->description) ast_free(tmp->description);
01562 tmp->description = descrip;
01563 found = tmp;
01564 if (status == 6) {
01565 if (last && found->next) {
01566 last->next = found->next;
01567 } else if (!last) {
01568 if (found->next)
01569 buddy->resources = found->next;
01570 else
01571 buddy->resources = NULL;
01572 } else if (!found->next) {
01573 if (last)
01574 last->next = NULL;
01575 else
01576 buddy->resources = NULL;
01577 }
01578 ast_free(found);
01579 found = NULL;
01580 break;
01581 }
01582
01583 if (tmp->priority != priority) {
01584 found->priority = priority;
01585 if (!last && !found->next)
01586
01587
01588 break;
01589
01590
01591 if (last)
01592 last->next = found->next;
01593 else
01594 buddy->resources = found->next;
01595
01596 last = NULL;
01597 tmp = buddy->resources;
01598 if (!buddy->resources)
01599 buddy->resources = found;
01600
01601 while (tmp) {
01602
01603
01604 if (found->priority > tmp->priority) {
01605 if (last)
01606
01607 last->next = found;
01608 found->next = tmp;
01609 if (!last)
01610
01611 buddy->resources = found;
01612 break;
01613 }
01614 if (!tmp->next) {
01615
01616 tmp->next = found;
01617 found->next = NULL;
01618 break;
01619 }
01620 last = tmp;
01621 tmp = tmp->next;
01622 }
01623 }
01624 break;
01625 }
01626 last = tmp;
01627 tmp = tmp->next;
01628 }
01629
01630
01631 if (!found && status != 6 && pak->from->resource) {
01632 found = ast_calloc(1, sizeof(*found));
01633
01634 if (!found) {
01635 ast_log(LOG_ERROR, "Out of memory!\n");
01636 return;
01637 }
01638 ast_copy_string(found->resource, pak->from->resource, sizeof(found->resource));
01639 found->status = status;
01640 found->description = descrip;
01641 found->priority = priority;
01642 found->next = NULL;
01643 last = NULL;
01644 tmp = buddy->resources;
01645 while (tmp) {
01646 if (found->priority > tmp->priority) {
01647 if (last)
01648 last->next = found;
01649 found->next = tmp;
01650 if (!last)
01651 buddy->resources = found;
01652 break;
01653 }
01654 if (!tmp->next) {
01655 tmp->next = found;
01656 break;
01657 }
01658 last = tmp;
01659 tmp = tmp->next;
01660 }
01661 if (!tmp)
01662 buddy->resources = found;
01663 }
01664
01665 ASTOBJ_UNLOCK(buddy);
01666 ASTOBJ_UNREF(buddy, aji_buddy_destroy);
01667
01668 node = iks_find_attrib(iks_find(pak->x, "c"), "node");
01669 ver = iks_find_attrib(iks_find(pak->x, "c"), "ver");
01670
01671
01672 if (!node && !ver) {
01673 node = iks_find_attrib(iks_find(pak->x, "caps:c"), "node");
01674 ver = iks_find_attrib(iks_find(pak->x, "caps:c"), "ver");
01675 }
01676
01677
01678 if(status !=6 && found && !found->cap) {
01679 found->cap = aji_find_version(node, ver, pak);
01680 if(gtalk_yuck(pak->x))
01681 found->cap->jingle = 1;
01682 if(found->cap->jingle && option_debug > 4) {
01683 ast_debug(1,"Special case for google till they support discover.\n");
01684 }
01685 else {
01686 iks *iq, *query;
01687 iq = iks_new("iq");
01688 query = iks_new("query");
01689 if(query && iq) {
01690 iks_insert_attrib(iq, "type", "get");
01691 iks_insert_attrib(iq, "to", pak->from->full);
01692 iks_insert_attrib(iq,"from", client->jid->full);
01693 iks_insert_attrib(iq, "id", client->mid);
01694 ast_aji_increment_mid(client->mid);
01695 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
01696 iks_insert_node(iq, query);
01697 ast_aji_send(client, iq);
01698
01699 } else
01700 ast_log(LOG_ERROR, "Out of memory.\n");
01701
01702 iks_delete(query);
01703 iks_delete(iq);
01704 }
01705 }
01706 switch (pak->subtype) {
01707 case IKS_TYPE_AVAILABLE:
01708 ast_debug(3, "JABBER: I am available ^_* %i\n", pak->subtype);
01709 break;
01710 case IKS_TYPE_UNAVAILABLE:
01711 ast_debug(3, "JABBER: I am unavailable ^_* %i\n", pak->subtype);
01712 break;
01713 default:
01714 ast_debug(3, "JABBER: Ohh sexy and the wrong type: %i\n", pak->subtype);
01715 }
01716 switch (pak->show) {
01717 case IKS_SHOW_UNAVAILABLE:
01718 ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01719 break;
01720 case IKS_SHOW_AVAILABLE:
01721 ast_debug(3, "JABBER: type is available\n");
01722 break;
01723 case IKS_SHOW_CHAT:
01724 ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01725 break;
01726 case IKS_SHOW_AWAY:
01727 ast_debug(3, "JABBER: type is away\n");
01728 break;
01729 case IKS_SHOW_XA:
01730 ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01731 break;
01732 case IKS_SHOW_DND:
01733 ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
01734 break;
01735 default:
01736 ast_debug(3, "JABBER: Kinky! how did that happen %i\n", pak->show);
01737 }
01738 }
01739
01740
01741
01742
01743
01744
01745
01746 static void aji_handle_subscribe(struct aji_client *client, ikspak *pak)
01747 {
01748 iks *presence = NULL, *status = NULL;
01749 struct aji_buddy* buddy = NULL;
01750
01751 switch (pak->subtype) {
01752 case IKS_TYPE_SUBSCRIBE:
01753 presence = iks_new("presence");
01754 status = iks_new("status");
01755 if (presence && status) {
01756 iks_insert_attrib(presence, "type", "subscribed");
01757 iks_insert_attrib(presence, "to", pak->from->full);
01758 iks_insert_attrib(presence, "from", client->jid->full);
01759 if (pak->id)
01760 iks_insert_attrib(presence, "id", pak->id);
01761 iks_insert_cdata(status, "Asterisk has approved subscription", 0);
01762 iks_insert_node(presence, status);
01763 ast_aji_send(client, presence);
01764 } else
01765 ast_log(LOG_ERROR, "Unable to allocate nodes\n");
01766
01767 iks_delete(presence);
01768 iks_delete(status);
01769
01770 if (client->component)
01771 aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), client->status, client->statusmessage);
01772 case IKS_TYPE_SUBSCRIBED:
01773 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01774 if (!buddy && pak->from->partial) {
01775 aji_create_buddy(pak->from->partial, client);
01776 }
01777 default:
01778 if (option_verbose > 4) {
01779 ast_verbose(VERBOSE_PREFIX_3 "JABBER: This is a subcription of type %i\n", pak->subtype);
01780 }
01781 }
01782 }
01783
01784
01785
01786
01787
01788
01789
01790
01791 int ast_aji_send_chat(struct aji_client *client, const char *address, const char *message)
01792 {
01793 int res = 0;
01794 iks *message_packet = NULL;
01795 if (client->state == AJI_CONNECTED) {
01796 message_packet = iks_make_msg(IKS_TYPE_CHAT, address, message);
01797 if (message_packet) {
01798 iks_insert_attrib(message_packet, "from", client->jid->full);
01799 res = ast_aji_send(client, message_packet);
01800 } else {
01801 ast_log(LOG_ERROR, "Out of memory.\n");
01802 }
01803
01804 iks_delete(message_packet);
01805 } else
01806 ast_log(LOG_WARNING, "JABBER: Not connected can't send\n");
01807 return 1;
01808 }
01809
01810
01811
01812
01813
01814
01815
01816
01817
01818 int ast_aji_create_chat(struct aji_client *client, char *room, char *server, char *topic)
01819 {
01820 int res = 0;
01821 iks *iq = NULL;
01822 iq = iks_new("iq");
01823
01824 if (iq && client) {
01825 iks_insert_attrib(iq, "type", "get");
01826 iks_insert_attrib(iq, "to", server);
01827 iks_insert_attrib(iq, "id", client->mid);
01828 ast_aji_increment_mid(client->mid);
01829 ast_aji_send(client, iq);
01830 } else
01831 ast_log(LOG_ERROR, "Out of memory.\n");
01832
01833 iks_delete(iq);
01834
01835 return res;
01836 }
01837
01838
01839
01840
01841
01842
01843
01844 int ast_aji_join_chat(struct aji_client *client, char *room)
01845 {
01846 int res = 0;
01847 iks *presence = NULL, *priority = NULL;
01848 presence = iks_new("presence");
01849 priority = iks_new("priority");
01850 if (presence && priority && client) {
01851 iks_insert_cdata(priority, "0", 1);
01852 iks_insert_attrib(presence, "to", room);
01853 iks_insert_node(presence, priority);
01854 res = ast_aji_send(client, presence);
01855 iks_insert_cdata(priority, "5", 1);
01856 iks_insert_attrib(presence, "to", room);
01857 res = ast_aji_send(client, presence);
01858 } else
01859 ast_log(LOG_ERROR, "Out of memory.\n");
01860
01861 iks_delete(presence);
01862 iks_delete(priority);
01863
01864 return res;
01865 }
01866
01867
01868
01869
01870
01871
01872
01873
01874
01875 int ast_aji_invite_chat(struct aji_client *client, char *user, char *room, char *message)
01876 {
01877 int res = 0;
01878 iks *invite, *body, *namespace;
01879
01880 invite = iks_new("message");
01881 body = iks_new("body");
01882 namespace = iks_new("x");
01883 if (client && invite && body && namespace) {
01884 iks_insert_attrib(invite, "to", user);
01885 iks_insert_attrib(invite, "id", client->mid);
01886 ast_aji_increment_mid(client->mid);
01887 iks_insert_cdata(body, message, 0);
01888 iks_insert_attrib(namespace, "xmlns", "jabber:x:conference");
01889 iks_insert_attrib(namespace, "jid", room);
01890 iks_insert_node(invite, body);
01891 iks_insert_node(invite, namespace);
01892 res = ast_aji_send(client, invite);
01893 } else
01894 ast_log(LOG_ERROR, "Out of memory.\n");
01895
01896 iks_delete(body);
01897 iks_delete(namespace);
01898 iks_delete(invite);
01899
01900 return res;
01901 }
01902
01903
01904
01905
01906
01907
01908
01909 static void *aji_recv_loop(void *data)
01910 {
01911 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01912 int res = IKS_HOOK;
01913
01914 while(res != IKS_OK) {
01915 ast_debug(3, "JABBER: Connecting.\n");
01916 res = aji_reconnect(client);
01917 sleep(4);
01918 }
01919
01920 do {
01921 if (res == IKS_NET_RWERR || client->timeout == 0) {
01922 while(res != IKS_OK) {
01923 ast_debug(3, "JABBER: reconnecting.\n");
01924 res = aji_reconnect(client);
01925 sleep(4);
01926 }
01927 }
01928
01929 res = aji_recv(client, 1);
01930
01931 if (client->state == AJI_DISCONNECTING) {
01932 ast_debug(2, "Ending our Jabber client's thread due to a disconnect\n");
01933 pthread_exit(NULL);
01934 }
01935
01936
01937 if (res == IKS_NET_EXPIRED)
01938 client->timeout--;
01939
01940 if (res == IKS_HOOK)
01941 ast_log(LOG_WARNING, "JABBER: Got hook event.\n");
01942 else if (res == IKS_NET_TLSFAIL)
01943 ast_log(LOG_ERROR, "JABBER: Failure in TLS.\n");
01944 else if (client->timeout == 0 && client->state == AJI_CONNECTED) {
01945 res = client->keepalive ? aji_send_raw(client, " ") : IKS_OK;
01946 if(res == IKS_OK)
01947 client->timeout = 50;
01948 else
01949 ast_log(LOG_WARNING, "JABBER: Network Timeout\n");
01950 } else if (res == IKS_NET_RWERR)
01951 ast_log(LOG_WARNING, "JABBER: socket read error\n");
01952 } while (client);
01953 ASTOBJ_UNREF(client, aji_client_destroy);
01954 return 0;
01955 }
01956
01957
01958
01959
01960
01961
01962 void ast_aji_increment_mid(char *mid)
01963 {
01964 int i = 0;
01965
01966 for (i = strlen(mid) - 1; i >= 0; i--) {
01967 if (mid[i] != 'z') {
01968 mid[i] = mid[i] + 1;
01969 i = 0;
01970 } else
01971 mid[i] = 'a';
01972 }
01973 }
01974
01975 #if 0
01976
01977
01978
01979
01980
01981
01982 static int aji_register_transport(void *data, ikspak *pak)
01983 {
01984 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01985 int res = 0;
01986 struct aji_buddy *buddy = NULL;
01987 iks *send = iks_make_iq(IKS_TYPE_GET, "jabber:iq:register");
01988
01989 if (client && send) {
01990 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
01991 ASTOBJ_RDLOCK(iterator);
01992 if (iterator->btype == AJI_TRANS) {
01993 buddy = iterator;
01994 }
01995 ASTOBJ_UNLOCK(iterator);
01996 });
01997 iks_filter_remove_hook(client->f, aji_register_transport);
01998 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);
01999 iks_insert_attrib(send, "to", buddy->host);
02000 iks_insert_attrib(send, "id", client->mid);
02001 ast_aji_increment_mid(client->mid);
02002 iks_insert_attrib(send, "from", client->user);
02003 res = ast_aji_send(client, send);
02004 } else
02005 ast_log(LOG_ERROR, "Out of memory.\n");
02006
02007 if (send)
02008 iks_delete(send);
02009 ASTOBJ_UNREF(client, aji_client_destroy);
02010 return IKS_FILTER_EAT;
02011
02012 }
02013
02014
02015
02016
02017
02018
02019 static int aji_register_transport2(void *data, ikspak *pak)
02020 {
02021 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
02022 int res = 0;
02023 struct aji_buddy *buddy = NULL;
02024
02025 iks *regiq = iks_new("iq");
02026 iks *regquery = iks_new("query");
02027 iks *reguser = iks_new("username");
02028 iks *regpass = iks_new("password");
02029
02030 if (client && regquery && reguser && regpass && regiq) {
02031 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02032 ASTOBJ_RDLOCK(iterator);
02033 if (iterator->btype == AJI_TRANS)
02034 buddy = iterator; ASTOBJ_UNLOCK(iterator);
02035 });
02036 iks_filter_remove_hook(client->f, aji_register_transport2);
02037 iks_insert_attrib(regiq, "to", buddy->host);
02038 iks_insert_attrib(regiq, "type", "set");
02039 iks_insert_attrib(regiq, "id", client->mid);
02040 ast_aji_increment_mid(client->mid);
02041 iks_insert_attrib(regiq, "from", client->user);
02042 iks_insert_attrib(regquery, "xmlns", "jabber:iq:register");
02043 iks_insert_cdata(reguser, buddy->user, 0);
02044 iks_insert_cdata(regpass, buddy->pass, 0);
02045 iks_insert_node(regiq, regquery);
02046 iks_insert_node(regquery, reguser);
02047 iks_insert_node(regquery, regpass);
02048 res = ast_aji_send(client, regiq);
02049 } else
02050 ast_log(LOG_ERROR, "Out of memory.\n");
02051 if (regiq)
02052 iks_delete(regiq);
02053 if (regquery)
02054 iks_delete(regquery);
02055 if (reguser)
02056 iks_delete(reguser);
02057 if (regpass)
02058 iks_delete(regpass);
02059 ASTOBJ_UNREF(client, aji_client_destroy);
02060 return IKS_FILTER_EAT;
02061 }
02062 #endif
02063
02064
02065
02066
02067
02068
02069
02070 static void aji_pruneregister(struct aji_client *client)
02071 {
02072 int res = 0;
02073 iks *removeiq = iks_new("iq");
02074 iks *removequery = iks_new("query");
02075 iks *removeitem = iks_new("item");
02076 iks *send = iks_make_iq(IKS_TYPE_GET, "http://jabber.org/protocol/disco#items");
02077 if (!client || !removeiq || !removequery || !removeitem || !send) {
02078 ast_log(LOG_ERROR, "Out of memory.\n");
02079 goto safeout;
02080 }
02081
02082 iks_insert_node(removeiq, removequery);
02083 iks_insert_node(removequery, removeitem);
02084 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02085 ASTOBJ_RDLOCK(iterator);
02086
02087
02088 if (ast_test_flag(&iterator->flags, AJI_AUTOPRUNE)) {
02089 res = ast_aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBE, iterator->name,
02090 "GoodBye. Your status is no longer needed by Asterisk the Open Source PBX"
02091 " so I am no longer subscribing to your presence.\n"));
02092 res = ast_aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBED, iterator->name,
02093 "GoodBye. You are no longer in the Asterisk config file so I am removing"
02094 " your access to my presence.\n"));
02095 iks_insert_attrib(removeiq, "from", client->jid->full);
02096 iks_insert_attrib(removeiq, "type", "set");
02097 iks_insert_attrib(removequery, "xmlns", "jabber:iq:roster");
02098 iks_insert_attrib(removeitem, "jid", iterator->name);
02099 iks_insert_attrib(removeitem, "subscription", "remove");
02100 res = ast_aji_send(client, removeiq);
02101 } else if (ast_test_flag(&iterator->flags, AJI_AUTOREGISTER)) {
02102 res = ast_aji_send(client, iks_make_s10n(IKS_TYPE_SUBSCRIBE, iterator->name,
02103 "Greetings! I am the Asterisk Open Source PBX and I want to subscribe to your presence\n"));
02104 ast_clear_flag(&iterator->flags, AJI_AUTOREGISTER);
02105 }
02106 ASTOBJ_UNLOCK(iterator);
02107 });
02108
02109 safeout:
02110 iks_delete(removeiq);
02111 iks_delete(removequery);
02112 iks_delete(removeitem);
02113 iks_delete(send);
02114
02115 ASTOBJ_CONTAINER_PRUNE_MARKED(&client->buddies, aji_buddy_destroy);
02116 }
02117
02118
02119
02120
02121
02122
02123
02124 static int aji_filter_roster(void *data, ikspak *pak)
02125 {
02126 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
02127 int flag = 0;
02128 iks *x = NULL;
02129 struct aji_buddy *buddy;
02130
02131 client->state = AJI_CONNECTED;
02132 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02133 ASTOBJ_RDLOCK(iterator);
02134 x = iks_child(pak->query);
02135 flag = 0;
02136 while (x) {
02137 if (!iks_strcmp(iks_name(x), "item")) {
02138 if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid"))) {
02139 flag = 1;
02140 ast_clear_flag(&iterator->flags, AJI_AUTOPRUNE | AJI_AUTOREGISTER);
02141 }
02142 }
02143 x = iks_next(x);
02144 }
02145 if (!flag)
02146 ast_copy_flags(&iterator->flags, &client->flags, AJI_AUTOREGISTER);
02147 iks_delete(x);
02148
02149 ASTOBJ_UNLOCK(iterator);
02150 });
02151
02152 x = iks_child(pak->query);
02153 while (x) {
02154 flag = 0;
02155 if (iks_strcmp(iks_name(x), "item") == 0) {
02156 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02157 ASTOBJ_RDLOCK(iterator);
02158 if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid")))
02159 flag = 1;
02160 ASTOBJ_UNLOCK(iterator);
02161 });
02162
02163 if (flag) {
02164
02165 x = iks_next(x);
02166 continue;
02167 }
02168
02169 buddy = ast_calloc(1, sizeof(*buddy));
02170 if (!buddy) {
02171 ast_log(LOG_WARNING, "Out of memory\n");
02172 return 0;
02173 }
02174 ASTOBJ_INIT(buddy);
02175 ASTOBJ_WRLOCK(buddy);
02176 ast_copy_string(buddy->name, iks_find_attrib(x, "jid"), sizeof(buddy->name));
02177 ast_clear_flag(&buddy->flags, AST_FLAGS_ALL);
02178 if(ast_test_flag(&client->flags, AJI_AUTOPRUNE)) {
02179 ast_set_flag(&buddy->flags, AJI_AUTOPRUNE);
02180 ASTOBJ_MARK(buddy);
02181 } else if (!iks_strcmp(iks_find_attrib(x, "subscription"), "none") || !iks_strcmp(iks_find_attrib(x, "subscription"), "from")) {
02182
02183
02184 ast_set_flag(&buddy->flags, AJI_AUTOREGISTER);
02185 }
02186 ASTOBJ_UNLOCK(buddy);
02187 if (buddy) {
02188 ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
02189 ASTOBJ_UNREF(buddy, aji_buddy_destroy);
02190 }
02191 }
02192 x = iks_next(x);
02193 }
02194
02195 iks_delete(x);
02196 aji_pruneregister(client);
02197
02198 ASTOBJ_UNREF(client, aji_client_destroy);
02199 return IKS_FILTER_EAT;
02200 }
02201
02202
02203
02204
02205
02206
02207 static int aji_reconnect(struct aji_client *client)
02208 {
02209 int res = 0;
02210
02211 if (client->state)
02212 client->state = AJI_DISCONNECTED;
02213 client->timeout=50;
02214 if (client->p)
02215 iks_parser_reset(client->p);
02216 if (client->authorized)
02217 client->authorized = 0;
02218
02219 res = aji_initialize(client);
02220
02221 return res;
02222 }
02223
02224
02225
02226
02227
02228
02229 static int aji_get_roster(struct aji_client *client)
02230 {
02231 iks *roster = NULL;
02232 roster = iks_make_iq(IKS_TYPE_GET, IKS_NS_ROSTER);
02233
02234 if(roster) {
02235 iks_insert_attrib(roster, "id", "roster");
02236 aji_set_presence(client, NULL, client->jid->full, client->status, client->statusmessage);
02237 ast_aji_send(client, roster);
02238 }
02239
02240 iks_delete(roster);
02241
02242 return 1;
02243 }
02244
02245
02246
02247
02248
02249
02250
02251 static int aji_client_connect(void *data, ikspak *pak)
02252 {
02253 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
02254 int res = 0;
02255
02256 if (client) {
02257 if (client->state == AJI_DISCONNECTED) {
02258 iks_filter_add_rule(client->f, aji_filter_roster, client, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, "roster", IKS_RULE_DONE);
02259 client->state = AJI_CONNECTING;
02260 client->jid = (iks_find_cdata(pak->query, "jid")) ? iks_id_new(client->stack, iks_find_cdata(pak->query, "jid")) : client->jid;
02261 iks_filter_remove_hook(client->f, aji_client_connect);
02262 if(!client->component)
02263 aji_get_roster(client);
02264 }
02265 } else
02266 ast_log(LOG_ERROR, "Out of memory.\n");
02267
02268 ASTOBJ_UNREF(client, aji_client_destroy);
02269 return res;
02270 }
02271
02272
02273
02274
02275
02276
02277 static int aji_initialize(struct aji_client *client)
02278 {
02279 int connected = IKS_NET_NOCONN;
02280
02281 #ifdef HAVE_OPENSSL
02282
02283 client->stream_flags = 0;
02284 #endif
02285
02286 connected = iks_connect_via(client->p, S_OR(client->serverhost, client->jid->server), client->port, client->component ? client->user : client->jid->server);
02287
02288 if (connected == IKS_NET_NOCONN) {
02289 ast_log(LOG_ERROR, "JABBER ERROR: No Connection\n");
02290 return IKS_HOOK;
02291 } else if (connected == IKS_NET_NODNS) {
02292 ast_log(LOG_ERROR, "JABBER ERROR: No DNS %s for client to %s\n", client->name, S_OR(client->serverhost, client->jid->server));
02293 return IKS_HOOK;
02294 }
02295
02296 return IKS_OK;
02297 }
02298
02299
02300
02301
02302
02303
02304 int ast_aji_disconnect(struct aji_client *client)
02305 {
02306 if (client) {
02307 ast_verb(4, "JABBER: Disconnecting\n");
02308 #ifdef HAVE_OPENSSL
02309 if (client->stream_flags & SECURE) {
02310 SSL_shutdown(client->ssl_session);
02311 SSL_CTX_free(client->ssl_context);
02312 SSL_free(client->ssl_session);
02313 }
02314 #endif
02315 iks_disconnect(client->p);
02316 iks_parser_delete(client->p);
02317 ASTOBJ_UNREF(client, aji_client_destroy);
02318 }
02319
02320 return 1;
02321 }
02322
02323
02324
02325
02326
02327
02328
02329
02330
02331
02332 static void aji_set_presence(struct aji_client *client, char *to, char *from, int level, char *desc)
02333 {
02334 int res = 0;
02335 iks *presence = iks_make_pres(level, desc);
02336 iks *cnode = iks_new("c");
02337 iks *priority = iks_new("priority");
02338 char priorityS[10];
02339
02340 if (presence && cnode && client && priority) {
02341 if(to)
02342 iks_insert_attrib(presence, "to", to);
02343 if(from)
02344 iks_insert_attrib(presence, "from", from);
02345 snprintf(priorityS, sizeof(priorityS), "%d", client->priority);
02346 iks_insert_cdata(priority, priorityS, strlen(priorityS));
02347 iks_insert_node(presence, priority);
02348 iks_insert_attrib(cnode, "node", "http://www.asterisk.org/xmpp/client/caps");
02349 iks_insert_attrib(cnode, "ver", "asterisk-xmpp");
02350 iks_insert_attrib(cnode, "ext", "voice-v1");
02351 iks_insert_attrib(cnode, "xmlns", "http://jabber.org/protocol/caps");
02352 iks_insert_node(presence, cnode);
02353 res = ast_aji_send(client, presence);
02354 } else
02355 ast_log(LOG_ERROR, "Out of memory.\n");
02356
02357 iks_delete(cnode);
02358 iks_delete(presence);
02359 iks_delete(priority);
02360 }
02361
02362
02363
02364
02365
02366 static char *aji_do_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02367 {
02368 switch (cmd) {
02369 case CLI_INIT:
02370 e->command = "jabber set debug {on|off}";
02371 e->usage =
02372 "Usage: jabber set debug {on|off}\n"
02373 " Enables/disables dumping of XMPP/Jabber packets for debugging purposes.\n";
02374 return NULL;
02375 case CLI_GENERATE:
02376 return NULL;
02377 }
02378
02379 if (a->argc != e->args)
02380 return CLI_SHOWUSAGE;
02381
02382 if (!strncasecmp(a->argv[e->args - 1], "on", 2)) {
02383 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02384 ASTOBJ_RDLOCK(iterator);
02385 iterator->debug = 1;
02386 ASTOBJ_UNLOCK(iterator);
02387 });
02388 ast_cli(a->fd, "Jabber Debugging Enabled.\n");
02389 return CLI_SUCCESS;
02390 } else if (!strncasecmp(a->argv[e->args - 1], "off", 3)) {
02391 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02392 ASTOBJ_RDLOCK(iterator);
02393 iterator->debug = 0;
02394 ASTOBJ_UNLOCK(iterator);
02395 });
02396 ast_cli(a->fd, "Jabber Debugging Disabled.\n");
02397 return CLI_SUCCESS;
02398 }
02399 return CLI_SHOWUSAGE;
02400 }
02401
02402
02403
02404
02405
02406 static char *aji_do_debug_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02407 {
02408
02409 switch (cmd) {
02410 case CLI_INIT:
02411 e->command = "jabber debug [off]";
02412 e->usage =
02413 "Usage: jabber debug [off]\n"
02414 " Enables/disables dumping of Jabber packets for debugging purposes.\n";
02415 return NULL;
02416 case CLI_GENERATE:
02417 return NULL;
02418 }
02419
02420 if (a->argc == 2) {
02421 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02422 ASTOBJ_RDLOCK(iterator);
02423 iterator->debug = 1;
02424 ASTOBJ_UNLOCK(iterator);
02425 });
02426 ast_cli(a->fd, "Jabber Debugging Enabled.\n");
02427 return CLI_SUCCESS;
02428 } else if (a->argc == 3) {
02429 if (!strncasecmp(a->argv[2], "off", 3)) {
02430 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02431 ASTOBJ_RDLOCK(iterator);
02432 iterator->debug = 0;
02433 ASTOBJ_UNLOCK(iterator);
02434 });
02435 ast_cli(a->fd, "Jabber Debugging Disabled.\n");
02436 return CLI_SUCCESS;
02437 }
02438 }
02439 return CLI_SHOWUSAGE;
02440 }
02441
02442
02443
02444
02445
02446 static char *aji_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02447 {
02448 switch (cmd) {
02449 case CLI_INIT:
02450 e->command = "jabber reload";
02451 e->usage =
02452 "Usage: jabber reload\n"
02453 " Reloads the Jabber module.\n";
02454 return NULL;
02455 case CLI_GENERATE:
02456 return NULL;
02457 }
02458
02459 aji_reload(1);
02460 ast_cli(a->fd, "Jabber Reloaded.\n");
02461 return CLI_SUCCESS;
02462 }
02463
02464
02465
02466
02467
02468 static char *aji_show_clients(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02469 {
02470 char *status;
02471 int count = 0;
02472
02473 switch (cmd) {
02474 case CLI_INIT:
02475 e->command = "jabber show connected";
02476 e->usage =
02477 "Usage: jabber show connected\n"
02478 " Shows state of clients and components\n";
02479 return NULL;
02480 case CLI_GENERATE:
02481 return NULL;
02482 }
02483
02484 ast_cli(a->fd, "Jabber Users and their status:\n");
02485 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02486 ASTOBJ_RDLOCK(iterator);
02487 count++;
02488 switch (iterator->state) {
02489 case AJI_DISCONNECTED:
02490 status = "Disconnected";
02491 break;
02492 case AJI_CONNECTING:
02493 status = "Connecting";
02494 break;
02495 case AJI_CONNECTED:
02496 status = "Connected";
02497 break;
02498 default:
02499 status = "Unknown";
02500 }
02501 ast_cli(a->fd, " User: %s - %s\n", iterator->user, status);
02502 ASTOBJ_UNLOCK(iterator);
02503 });
02504 ast_cli(a->fd, "----\n");
02505 ast_cli(a->fd, " Number of users: %d\n", count);
02506 return CLI_SUCCESS;
02507 }
02508
02509
02510
02511
02512
02513 static char *aji_show_buddies(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02514 {
02515 struct aji_resource *resource;
02516 struct aji_client *client;
02517
02518 switch (cmd) {
02519 case CLI_INIT:
02520 e->command = "jabber show buddies";
02521 e->usage =
02522 "Usage: jabber show buddies\n"
02523 " Shows buddy lists of our clients\n";
02524 return NULL;
02525 case CLI_GENERATE:
02526 return NULL;
02527 }
02528
02529 ast_cli(a->fd, "Jabber buddy lists\n");
02530 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02531 ast_cli(a->fd,"Client: %s\n", iterator->user);
02532 client = iterator;
02533 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02534 ASTOBJ_RDLOCK(iterator);
02535 ast_cli(a->fd,"\tBuddy:\t%s\n", iterator->name);
02536 if (!iterator->resources)
02537 ast_cli(a->fd,"\t\tResource: None\n");
02538 for (resource = iterator->resources; resource; resource = resource->next) {
02539 ast_cli(a->fd,"\t\tResource: %s\n", resource->resource);
02540 if(resource->cap) {
02541 ast_cli(a->fd,"\t\t\tnode: %s\n", resource->cap->parent->node);
02542 ast_cli(a->fd,"\t\t\tversion: %s\n", resource->cap->version);
02543 ast_cli(a->fd,"\t\t\tJingle capable: %s\n", resource->cap->jingle ? "yes" : "no");
02544 }
02545 ast_cli(a->fd,"\t\tStatus: %d\n", resource->status);
02546 ast_cli(a->fd,"\t\tPriority: %d\n", resource->priority);
02547 }
02548 ASTOBJ_UNLOCK(iterator);
02549 });
02550 iterator = client;
02551 });
02552 return CLI_SUCCESS;
02553 }
02554
02555
02556
02557
02558
02559 static char *aji_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02560 {
02561 struct aji_client *client;
02562 struct aji_resource *resource;
02563 const char *name = "asterisk";
02564 struct aji_message *tmp;
02565
02566 switch (cmd) {
02567 case CLI_INIT:
02568 e->command = "jabber test";
02569 e->usage =
02570 "Usage: jabber test [client]\n"
02571 " Sends test message for debugging purposes. A specific client\n"
02572 " as configured in jabber.conf can be optionally specified.\n";
02573 return NULL;
02574 case CLI_GENERATE:
02575 return NULL;
02576 }
02577
02578 if (a->argc > 3)
02579 return CLI_SHOWUSAGE;
02580 else if (a->argc == 3)
02581 name = a->argv[2];
02582
02583 if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
02584 ast_cli(a->fd, "Unable to find client '%s'!\n", name);
02585 return CLI_FAILURE;
02586 }
02587
02588
02589 ast_aji_send_chat(client, "mogorman@astjab.org", "blahblah");
02590 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02591 ASTOBJ_RDLOCK(iterator);
02592 ast_verbose("User: %s\n", iterator->name);
02593 for (resource = iterator->resources; resource; resource = resource->next) {
02594 ast_verbose("Resource: %s\n", resource->resource);
02595 if(resource->cap) {
02596 ast_verbose(" client: %s\n", resource->cap->parent->node);
02597 ast_verbose(" version: %s\n", resource->cap->version);
02598 ast_verbose(" Jingle Capable: %d\n", resource->cap->jingle);
02599 }
02600 ast_verbose(" Priority: %d\n", resource->priority);
02601 ast_verbose(" Status: %d\n", resource->status);
02602 ast_verbose(" Message: %s\n", S_OR(resource->description,""));
02603 }
02604 ASTOBJ_UNLOCK(iterator);
02605 });
02606 ast_verbose("\nOooh a working message stack!\n");
02607 AST_LIST_LOCK(&client->messages);
02608 AST_LIST_TRAVERSE(&client->messages, tmp, list) {
02609 ast_verbose(" Message from: %s with id %s @ %s %s\n",tmp->from, S_OR(tmp->id,""), ctime(&tmp->arrived), S_OR(tmp->message, ""));
02610 }
02611 AST_LIST_UNLOCK(&client->messages);
02612 ASTOBJ_UNREF(client, aji_client_destroy);
02613
02614 return CLI_SUCCESS;
02615 }
02616
02617
02618
02619
02620
02621
02622
02623
02624 static int aji_create_client(char *label, struct ast_variable *var, int debug)
02625 {
02626 char *resource;
02627 struct aji_client *client = NULL;
02628 int flag = 0;
02629
02630 client = ASTOBJ_CONTAINER_FIND(&clients,label);
02631 if (!client) {
02632 flag = 1;
02633 client = ast_calloc(1, sizeof(*client));
02634 if (!client) {
02635 ast_log(LOG_ERROR, "Out of memory!\n");
02636 return 0;
02637 }
02638 ASTOBJ_INIT(client);
02639 ASTOBJ_WRLOCK(client);
02640 ASTOBJ_CONTAINER_INIT(&client->buddies);
02641 } else {
02642 ASTOBJ_WRLOCK(client);
02643 ASTOBJ_UNMARK(client);
02644 }
02645 ASTOBJ_CONTAINER_MARKALL(&client->buddies);
02646 ast_copy_string(client->name, label, sizeof(client->name));
02647 ast_copy_string(client->mid, "aaaaa", sizeof(client->mid));
02648
02649
02650 client->debug = debug;
02651 ast_copy_flags(&client->flags, &globalflags, AST_FLAGS_ALL);
02652 client->port = 5222;
02653 client->usetls = 1;
02654 client->usesasl = 1;
02655 client->forcessl = 0;
02656 client->keepalive = 1;
02657 client->timeout = 50;
02658 client->message_timeout = 100;
02659 AST_LIST_HEAD_INIT(&client->messages);
02660 client->component = 0;
02661 ast_copy_string(client->statusmessage, "Online and Available", sizeof(client->statusmessage));
02662 client->priority = 0;
02663 client->status = IKS_SHOW_AVAILABLE;
02664
02665 if (flag) {
02666 client->authorized = 0;
02667 client->state = AJI_DISCONNECTED;
02668 }
02669 while (var) {
02670 if (!strcasecmp(var->name, "username"))
02671 ast_copy_string(client->user, var->value, sizeof(client->user));
02672 else if (!strcasecmp(var->name, "serverhost"))
02673 ast_copy_string(client->serverhost, var->value, sizeof(client->serverhost));
02674 else if (!strcasecmp(var->name, "secret"))
02675 ast_copy_string(client->password, var->value, sizeof(client->password));
02676 else if (!strcasecmp(var->name, "statusmessage"))
02677 ast_copy_string(client->statusmessage, var->value, sizeof(client->statusmessage));
02678 else if (!strcasecmp(var->name, "port"))
02679 client->port = atoi(var->value);
02680 else if (!strcasecmp(var->name, "timeout"))
02681 client->message_timeout = atoi(var->value);
02682 else if (!strcasecmp(var->name, "debug"))
02683 client->debug = (ast_false(var->value)) ? 0 : 1;
02684 else if (!strcasecmp(var->name, "type")) {
02685 if (!strcasecmp(var->value, "component"))
02686 client->component = 1;
02687 } else if (!strcasecmp(var->name, "usetls")) {
02688 client->usetls = (ast_false(var->value)) ? 0 : 1;
02689 } else if (!strcasecmp(var->name, "usesasl")) {
02690 client->usesasl = (ast_false(var->value)) ? 0 : 1;
02691 } else if (!strcasecmp(var->name, "forceoldssl"))
02692 client->forcessl = (ast_false(var->value)) ? 0 : 1;
02693 else if (!strcasecmp(var->name, "keepalive"))
02694 client->keepalive = (ast_false(var->value)) ? 0 : 1;
02695 else if (!strcasecmp(var->name, "autoprune"))
02696 ast_set2_flag(&client->flags, ast_true(var->value), AJI_AUTOPRUNE);
02697 else if (!strcasecmp(var->name, "autoregister"))
02698 ast_set2_flag(&client->flags, ast_true(var->value), AJI_AUTOREGISTER);
02699 else if (!strcasecmp(var->name, "buddy"))
02700 aji_create_buddy((char *)var->value, client);
02701 else if (!strcasecmp(var->name, "priority"))
02702 client->priority = atoi(var->value);
02703 else if (!strcasecmp(var->name, "status")) {
02704 if (!strcasecmp(var->value, "unavailable"))
02705 client->status = IKS_SHOW_UNAVAILABLE;
02706 else
02707 if (!strcasecmp(var->value, "available")
02708 || !strcasecmp(var->value, "online"))
02709 client->status = IKS_SHOW_AVAILABLE;
02710 else
02711 if (!strcasecmp(var->value, "chat")
02712 || !strcasecmp(var->value, "chatty"))
02713 client->status = IKS_SHOW_CHAT;
02714 else
02715 if (!strcasecmp(var->value, "away"))
02716 client->status = IKS_SHOW_AWAY;
02717 else
02718 if (!strcasecmp(var->value, "xa")
02719 || !strcasecmp(var->value, "xaway"))
02720 client->status = IKS_SHOW_XA;
02721 else
02722 if (!strcasecmp(var->value, "dnd"))
02723 client->status = IKS_SHOW_DND;
02724 else
02725 if (!strcasecmp(var->value, "invisible"))
02726 #ifdef IKS_SHOW_INVISIBLE
02727 client->status = IKS_SHOW_INVISIBLE;
02728 #else
02729 {
02730 ast_log(LOG_WARNING, "Your iksemel doesn't support invisible status: falling back to DND\n");
02731 client->status = IKS_SHOW_DND;
02732 }
02733 #endif
02734 else
02735 ast_log(LOG_WARNING, "Unknown presence status: %s\n", var->value);
02736 }
02737
02738
02739
02740
02741 var = var->next;
02742 }
02743 if (!flag) {
02744 ASTOBJ_UNLOCK(client);
02745 ASTOBJ_UNREF(client, aji_client_destroy);
02746 return 1;
02747 }
02748
02749 ast_copy_string(client->name_space, (client->component) ? "jabber:component:accept" : "jabber:client", sizeof(client->name_space));
02750 client->p = iks_stream_new(client->name_space, client, aji_act_hook);
02751 if (!client->p) {
02752 ast_log(LOG_ERROR, "Failed to create stream for client '%s'!\n", client->name);
02753 return 0;
02754 }
02755 client->stack = iks_stack_new(8192, 8192);
02756 if (!client->stack) {
02757 ast_log(LOG_ERROR, "Failed to allocate stack for client '%s'\n", client->name);
02758 return 0;
02759 }
02760 client->f = iks_filter_new();
02761 if (!client->f) {
02762 ast_log(LOG_ERROR, "Failed to create filter for client '%s'\n", client->name);
02763 return 0;
02764 }
02765 if (!strchr(client->user, '/') && !client->component) {
02766 resource = NULL;
02767 if (asprintf(&resource, "%s/asterisk", client->user) >= 0) {
02768 client->jid = iks_id_new(client->stack, resource);
02769 ast_free(resource);
02770 }
02771 } else
02772 client->jid = iks_id_new(client->stack, client->user);
02773 if (client->component) {
02774 iks_filter_add_rule(client->f, aji_dinfo_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
02775 iks_filter_add_rule(client->f, aji_ditems_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#items", IKS_RULE_DONE);
02776 iks_filter_add_rule(client->f, aji_register_query_handler, client, IKS_RULE_SUBTYPE, IKS_TYPE_GET, IKS_RULE_NS, "jabber:iq:register", IKS_RULE_DONE);
02777 iks_filter_add_rule(client->f, aji_register_approve_handler, client, IKS_RULE_SUBTYPE, IKS_TYPE_SET, IKS_RULE_NS, "jabber:iq:register", IKS_RULE_DONE);
02778 } else {
02779 iks_filter_add_rule(client->f, aji_client_info_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
02780 }
02781 if (!strchr(client->user, '/') && !client->component) {
02782 resource = NULL;
02783 if (asprintf(&resource, "%s/asterisk", client->user) >= 0) {
02784 client->jid = iks_id_new(client->stack, resource);
02785 ast_free(resource);
02786 }
02787 } else
02788 client->jid = iks_id_new(client->stack, client->user);
02789 iks_set_log_hook(client->p, aji_log_hook);
02790 ASTOBJ_UNLOCK(client);
02791 ASTOBJ_CONTAINER_LINK(&clients,client);
02792 return 1;
02793 }
02794
02795 #if 0
02796
02797
02798
02799
02800
02801
02802 static int aji_create_transport(char *label, struct aji_client *client)
02803 {
02804 char *server = NULL, *buddyname = NULL, *user = NULL, *pass = NULL;
02805 struct aji_buddy *buddy = NULL;
02806
02807 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies,label);
02808 if (!buddy) {
02809 buddy = ast_calloc(1, sizeof(*buddy));
02810 if(!buddy) {
02811 ast_log(LOG_WARNING, "Out of memory\n");
02812 return 0;
02813 }
02814 ASTOBJ_INIT(buddy);
02815 }
02816 ASTOBJ_WRLOCK(buddy);
02817 server = label;
02818 if ((buddyname = strchr(label, ','))) {
02819 *buddyname = '\0';
02820 buddyname++;
02821 if (buddyname && buddyname[0] != '\0') {
02822 if ((user = strchr(buddyname, ','))) {
02823 *user = '\0';
02824 user++;
02825 if (user && user[0] != '\0') {
02826 if ((pass = strchr(user, ','))) {
02827 *pass = '\0';
02828 pass++;
02829 ast_copy_string(buddy->pass, pass, sizeof(buddy->pass));
02830 ast_copy_string(buddy->user, user, sizeof(buddy->user));
02831 ast_copy_string(buddy->name, buddyname, sizeof(buddy->name));
02832 ast_copy_string(buddy->server, server, sizeof(buddy->server));
02833 return 1;
02834 }
02835 }
02836 }
02837 }
02838 }
02839 ASTOBJ_UNLOCK(buddy);
02840 ASTOBJ_UNMARK(buddy);
02841 ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
02842 return 0;
02843 }
02844 #endif
02845
02846
02847
02848
02849
02850
02851
02852 static int aji_create_buddy(char *label, struct aji_client *client)
02853 {
02854 struct aji_buddy *buddy = NULL;
02855 int flag = 0;
02856 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies,label);
02857 if (!buddy) {
02858 flag = 1;
02859 buddy = ast_calloc(1, sizeof(*buddy));
02860 if(!buddy) {
02861 ast_log(LOG_WARNING, "Out of memory\n");
02862 return 0;
02863 }
02864 ASTOBJ_INIT(buddy);
02865 }
02866 ASTOBJ_WRLOCK(buddy);
02867 ast_copy_string(buddy->name, label, sizeof(buddy->name));
02868 ASTOBJ_UNLOCK(buddy);
02869 if(flag)
02870 ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
02871 else {
02872 ASTOBJ_UNMARK(buddy);
02873 ASTOBJ_UNREF(buddy, aji_buddy_destroy);
02874 }
02875 return 1;
02876 }
02877
02878
02879 static int aji_load_config(int reload)
02880 {
02881 char *cat = NULL;
02882 int debug = 1;
02883 struct ast_config *cfg = NULL;
02884 struct ast_variable *var = NULL;
02885 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
02886
02887 if ((cfg = ast_config_load(JABBER_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
02888 return -1;
02889
02890
02891 ast_set_flag(&globalflags, AJI_AUTOREGISTER);
02892
02893 if (!cfg) {
02894 ast_log(LOG_WARNING, "No such configuration file %s\n", JABBER_CONFIG);
02895 return 0;
02896 }
02897
02898 cat = ast_category_browse(cfg, NULL);
02899 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
02900 if (!strcasecmp(var->name, "debug")) {
02901 debug = (ast_false(ast_variable_retrieve(cfg, "general", "debug"))) ? 0 : 1;
02902 } else if (!strcasecmp(var->name, "autoprune")) {
02903 ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOPRUNE);
02904 } else if (!strcasecmp(var->name, "autoregister")) {
02905 ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOREGISTER);
02906 }
02907 }
02908
02909 while (cat) {
02910 if (strcasecmp(cat, "general")) {
02911 var = ast_variable_browse(cfg, cat);
02912 aji_create_client(cat, var, debug);
02913 }
02914 cat = ast_category_browse(cfg, cat);
02915 }
02916 ast_config_destroy(cfg);
02917 return 1;
02918 }
02919
02920
02921
02922
02923
02924
02925
02926 struct aji_client *ast_aji_get_client(const char *name)
02927 {
02928 struct aji_client *client = NULL;
02929 char *aux = NULL;
02930
02931 client = ASTOBJ_CONTAINER_FIND(&clients, name);
02932 if (!client && strchr(name, '@')) {
02933 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
02934 aux = ast_strdupa(iterator->user);
02935 if (strchr(aux, '/')) {
02936
02937 aux = strsep(&aux, "/");
02938 }
02939 if (!strncasecmp(aux, name, strlen(aux))) {
02940 client = iterator;
02941 }
02942 });
02943 }
02944
02945 return client;
02946 }
02947
02948 struct aji_client_container *ast_aji_get_clients(void)
02949 {
02950 return &clients;
02951 }
02952
02953 static char mandescr_jabber_send[] =
02954 "Description: Sends a message to a Jabber Client.\n"
02955 "Variables: \n"
02956 " Jabber: Client or transport Asterisk uses to connect to JABBER.\n"
02957 " ScreenName: User Name to message.\n"
02958 " Message: Message to be sent to the buddy\n";
02959
02960
02961
02962
02963
02964
02965
02966 static int manager_jabber_send(struct mansession *s, const struct message *m)
02967 {
02968 struct aji_client *client = NULL;
02969 const char *id = astman_get_header(m,"ActionID");
02970 const char *jabber = astman_get_header(m,"Jabber");
02971 const char *screenname = astman_get_header(m,"ScreenName");
02972 const char *message = astman_get_header(m,"Message");
02973
02974 if (ast_strlen_zero(jabber)) {
02975 astman_send_error(s, m, "No transport specified");
02976 return 0;
02977 }
02978 if (ast_strlen_zero(screenname)) {
02979 astman_send_error(s, m, "No ScreenName specified");
02980 return 0;
02981 }
02982 if (ast_strlen_zero(message)) {
02983 astman_send_error(s, m, "No Message specified");
02984 return 0;
02985 }
02986
02987 astman_send_ack(s, m, "Attempting to send Jabber Message");
02988 client = ast_aji_get_client(jabber);
02989 if (!client) {
02990 astman_send_error(s, m, "Could not find Sender");
02991 return 0;
02992 }
02993 if (strchr(screenname, '@') && message) {
02994 ast_aji_send_chat(client, screenname, message);
02995 astman_append(s, "Response: Success\r\n");
02996 } else {
02997 astman_append(s, "Response: Error\r\n");
02998 }
02999 if (!ast_strlen_zero(id)) {
03000 astman_append(s, "ActionID: %s\r\n",id);
03001 }
03002 astman_append(s, "\r\n");
03003 return 0;
03004 }
03005
03006
03007 static int aji_reload(int reload)
03008 {
03009 int res;
03010
03011 ASTOBJ_CONTAINER_MARKALL(&clients);
03012 if (!(res = aji_load_config(reload))) {
03013 ast_log(LOG_ERROR, "JABBER: Failed to load config.\n");
03014 return 0;
03015 } else if (res == -1)
03016 return 1;
03017
03018 ASTOBJ_CONTAINER_PRUNE_MARKED(&clients, aji_client_destroy);
03019 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
03020 ASTOBJ_RDLOCK(iterator);
03021 if(iterator->state == AJI_DISCONNECTED) {
03022 if (!iterator->thread)
03023 ast_pthread_create_background(&iterator->thread, NULL, aji_recv_loop, iterator);
03024 } else if (iterator->state == AJI_CONNECTING)
03025 aji_get_roster(iterator);
03026 ASTOBJ_UNLOCK(iterator);
03027 });
03028
03029 return 1;
03030 }
03031
03032
03033 static int unload_module(void)
03034 {
03035
03036 ast_cli_unregister_multiple(aji_cli, sizeof(aji_cli) / sizeof(struct ast_cli_entry));
03037 ast_unregister_application(app_ajisend);
03038 ast_unregister_application(app_ajistatus);
03039 ast_manager_unregister("JabberSend");
03040 ast_custom_function_unregister(&jabberstatus_function);
03041
03042 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
03043 ASTOBJ_RDLOCK(iterator);
03044 ast_debug(3, "JABBER: Releasing and disconnecting client: %s\n", iterator->name);
03045 iterator->state = AJI_DISCONNECTING;
03046 ast_aji_disconnect(iterator);
03047 pthread_join(iterator->thread, NULL);
03048 ASTOBJ_UNLOCK(iterator);
03049 });
03050
03051 ASTOBJ_CONTAINER_DESTROYALL(&clients, aji_client_destroy);
03052 ASTOBJ_CONTAINER_DESTROY(&clients);
03053 return 0;
03054 }
03055
03056
03057 static int load_module(void)
03058 {
03059 ASTOBJ_CONTAINER_INIT(&clients);
03060 if(!aji_reload(0))
03061 return AST_MODULE_LOAD_DECLINE;
03062 ast_manager_register2("JabberSend", EVENT_FLAG_SYSTEM, manager_jabber_send,
03063 "Sends a message to a Jabber Client", mandescr_jabber_send);
03064 ast_register_application(app_ajisend, aji_send_exec, ajisend_synopsis, ajisend_descrip);
03065 ast_register_application(app_ajistatus, aji_status_exec, ajistatus_synopsis, ajistatus_descrip);
03066 ast_cli_register_multiple(aji_cli, sizeof(aji_cli) / sizeof(struct ast_cli_entry));
03067 ast_custom_function_register(&jabberstatus_function);
03068
03069 return 0;
03070 }
03071
03072
03073 static int reload(void)
03074 {
03075 aji_reload(1);
03076 return 0;
03077 }
03078
03079 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "AJI - Asterisk Jabber Interface",
03080 .load = load_module,
03081 .unload = unload_module,
03082 .reload = reload,
03083 );