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