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