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