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
00039 #include "asterisk.h"
00040
00041 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 374335 $")
00042
00043 #include <ctype.h>
00044 #include <iksemel.h>
00045
00046 #include "asterisk/channel.h"
00047 #include "asterisk/jabber.h"
00048 #include "asterisk/file.h"
00049 #include "asterisk/config.h"
00050 #include "asterisk/callerid.h"
00051 #include "asterisk/lock.h"
00052 #include "asterisk/cli.h"
00053 #include "asterisk/app.h"
00054 #include "asterisk/pbx.h"
00055 #include "asterisk/md5.h"
00056 #include "asterisk/acl.h"
00057 #include "asterisk/utils.h"
00058 #include "asterisk/module.h"
00059 #include "asterisk/astobj.h"
00060 #include "asterisk/astdb.h"
00061 #include "asterisk/manager.h"
00062 #include "asterisk/event.h"
00063 #include "asterisk/devicestate.h"
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
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285 #define JABBER_CONFIG "jabber.conf"
00286
00287
00288 static void aji_message_destroy(struct aji_message *obj);
00289 static int aji_is_secure(struct aji_client *client);
00290 #ifdef HAVE_OPENSSL
00291 static int aji_start_tls(struct aji_client *client);
00292 static int aji_tls_handshake(struct aji_client *client);
00293 #endif
00294 static int aji_io_recv(struct aji_client *client, char *buffer, size_t buf_len, int timeout);
00295 static int aji_recv(struct aji_client *client, int timeout);
00296 static int aji_send_header(struct aji_client *client, const char *to);
00297 static int aji_send_raw(struct aji_client *client, const char *xmlstr);
00298 static void aji_log_hook(void *data, const char *xmpp, size_t size, int is_incoming);
00299 static int aji_start_sasl(struct aji_client *client, enum ikssasltype type, char *username, char *pass);
00300 static int aji_act_hook(void *data, int type, iks *node);
00301 static void aji_handle_iq(struct aji_client *client, iks *node);
00302 static void aji_handle_message(struct aji_client *client, ikspak *pak);
00303 static void aji_handle_presence(struct aji_client *client, ikspak *pak);
00304 static void aji_handle_subscribe(struct aji_client *client, ikspak *pak);
00305 static int aji_send_raw_chat(struct aji_client *client, int groupchat, const char *nick, const char *address, const char *message);
00306 static void *aji_recv_loop(void *data);
00307 static int aji_initialize(struct aji_client *client);
00308 static int aji_client_connect(void *data, ikspak *pak);
00309 static void aji_set_presence(struct aji_client *client, char *to, char *from, int level, char *desc);
00310 static int aji_set_group_presence(struct aji_client *client, char *room, int level, char *nick, char *desc);
00311 static char *aji_do_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
00312 static char *aji_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
00313 static char *aji_show_clients(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
00314 static char *aji_show_buddies(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
00315 static int aji_create_client(char *label, struct ast_variable *var, int debug);
00316 static int aji_create_buddy(char *label, struct aji_client *client);
00317 static int aji_reload(int reload);
00318 static int aji_load_config(int reload);
00319 static void aji_pruneregister(struct aji_client *client);
00320 static int aji_filter_roster(void *data, ikspak *pak);
00321 static int aji_get_roster(struct aji_client *client);
00322 static int aji_client_info_handler(void *data, ikspak *pak);
00323 static int aji_dinfo_handler(void *data, ikspak *pak);
00324 static int aji_ditems_handler(void *data, ikspak *pak);
00325 static int aji_register_query_handler(void *data, ikspak *pak);
00326 static int aji_register_approve_handler(void *data, ikspak *pak);
00327 static int aji_reconnect(struct aji_client *client);
00328 static char *aji_cli_create_collection(struct ast_cli_entry *e, int cmd,
00329 struct ast_cli_args *a);
00330 static char *aji_cli_list_pubsub_nodes(struct ast_cli_entry *e, int cmd,
00331 struct ast_cli_args *a);
00332 static char *aji_cli_delete_pubsub_node(struct ast_cli_entry *e, int cmd, struct
00333 ast_cli_args *a);
00334 static char *aji_cli_purge_pubsub_nodes(struct ast_cli_entry *e, int cmd, struct
00335 ast_cli_args *a);
00336 static iks *jabber_make_auth(iksid * id, const char *pass, const char *sid);
00337 static int aji_receive_node_list(void *data, ikspak* pak);
00338 static void aji_init_event_distribution(struct aji_client *client);
00339 static iks* aji_create_pubsub_node(struct aji_client *client, const char *node_type,
00340 const char *name, const char *collection_name);
00341 static iks* aji_build_node_config(iks *pubsub, const char *node_type,
00342 const char *collection_name);
00343 static void aji_create_pubsub_collection(struct aji_client *client,
00344 const char *collection_name);
00345 static void aji_create_pubsub_leaf(struct aji_client *client, const char *collection_name,
00346 const char *leaf_name);
00347 static char *aji_cli_create_leafnode(struct ast_cli_entry *e, int cmd,
00348 struct ast_cli_args *a);
00349 static void aji_create_affiliations(struct aji_client *client, const char *node);
00350 static iks* aji_pubsub_iq_create(struct aji_client *client, const char *type);
00351 static void aji_publish_device_state(struct aji_client *client, const char * device,
00352 const char *device_state);
00353 static int aji_handle_pubsub_error(void *data, ikspak *pak);
00354 static int aji_handle_pubsub_event(void *data, ikspak *pak);
00355 static void aji_pubsub_subscribe(struct aji_client *client, const char *node);
00356 static void aji_delete_pubsub_node(struct aji_client *client, const char *node_name);
00357 static iks* aji_build_node_request(struct aji_client *client, const char *collection);
00358 static int aji_delete_node_list(void *data, ikspak* pak);
00359 static void aji_pubsub_purge_nodes(struct aji_client *client,
00360 const char* collection_name);
00361 static void aji_publish_mwi(struct aji_client *client, const char *mailbox,
00362 const char *context, const char *oldmsgs, const char *newmsgs);
00363 static void aji_devstate_cb(const struct ast_event *ast_event, void *data);
00364 static void aji_mwi_cb(const struct ast_event *ast_event, void *data);
00365 static iks* aji_build_publish_skeleton(struct aji_client *client, const char *node,
00366 const char *event_type);
00367
00368
00369
00370
00371
00372
00373
00374 static struct ast_cli_entry aji_cli[] = {
00375 AST_CLI_DEFINE(aji_do_set_debug, "Enable/Disable Jabber debug"),
00376 AST_CLI_DEFINE(aji_do_reload, "Reload Jabber configuration"),
00377 AST_CLI_DEFINE(aji_show_clients, "Show state of clients and components"),
00378 AST_CLI_DEFINE(aji_show_buddies, "Show buddy lists of our clients"),
00379 AST_CLI_DEFINE(aji_cli_create_collection, "Creates a PubSub node collection."),
00380 AST_CLI_DEFINE(aji_cli_list_pubsub_nodes, "Lists PubSub nodes"),
00381 AST_CLI_DEFINE(aji_cli_create_leafnode, "Creates a PubSub leaf node"),
00382 AST_CLI_DEFINE(aji_cli_delete_pubsub_node, "Deletes a PubSub node"),
00383 AST_CLI_DEFINE(aji_cli_purge_pubsub_nodes, "Purges PubSub nodes"),
00384 };
00385
00386 static char *app_ajisend = "JabberSend";
00387 static char *app_ajisendgroup = "JabberSendGroup";
00388 static char *app_ajistatus = "JabberStatus";
00389 static char *app_ajijoin = "JabberJoin";
00390 static char *app_ajileave = "JabberLeave";
00391
00392 static struct aji_client_container clients;
00393 static struct aji_capabilities *capabilities = NULL;
00394 static struct ast_event_sub *mwi_sub = NULL;
00395 static struct ast_event_sub *device_state_sub = NULL;
00396 static ast_cond_t message_received_condition;
00397 static ast_mutex_t messagelock;
00398
00399
00400 static struct ast_flags globalflags = { AJI_AUTOREGISTER | AJI_AUTOACCEPT };
00401
00402
00403 static struct ast_flags pubsubflags = { 0 };
00404
00405
00406
00407
00408
00409
00410 void ast_aji_client_destroy(struct aji_client *obj)
00411 {
00412 struct aji_message *tmp;
00413 ASTOBJ_CONTAINER_DESTROYALL(&obj->buddies, ast_aji_buddy_destroy);
00414 ASTOBJ_CONTAINER_DESTROY(&obj->buddies);
00415 iks_filter_delete(obj->f);
00416 iks_parser_delete(obj->p);
00417 iks_stack_delete(obj->stack);
00418 AST_LIST_LOCK(&obj->messages);
00419 while ((tmp = AST_LIST_REMOVE_HEAD(&obj->messages, list))) {
00420 aji_message_destroy(tmp);
00421 }
00422 AST_LIST_HEAD_DESTROY(&obj->messages);
00423 ast_free(obj);
00424 }
00425
00426
00427
00428
00429
00430
00431
00432 void ast_aji_buddy_destroy(struct aji_buddy *obj)
00433 {
00434 struct aji_resource *tmp;
00435
00436 while ((tmp = obj->resources)) {
00437 obj->resources = obj->resources->next;
00438 ast_free(tmp->description);
00439 ast_free(tmp);
00440 }
00441
00442 ast_free(obj);
00443 }
00444
00445
00446
00447
00448
00449
00450
00451 static void aji_message_destroy(struct aji_message *obj)
00452 {
00453 if (obj->from) {
00454 ast_free(obj->from);
00455 }
00456 if (obj->message) {
00457 ast_free(obj->message);
00458 }
00459 ast_free(obj);
00460 }
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472 static struct aji_version *aji_find_version(char *node, char *version, ikspak *pak)
00473 {
00474 struct aji_capabilities *list = NULL;
00475 struct aji_version *res = NULL;
00476
00477 list = capabilities;
00478
00479 if (!node) {
00480 node = pak->from->full;
00481 }
00482 if (!version) {
00483 version = "none supplied.";
00484 }
00485 while (list) {
00486 if (!strcasecmp(list->node, node)) {
00487 res = list->versions;
00488 while(res) {
00489 if (!strcasecmp(res->version, version)) {
00490 return res;
00491 }
00492 res = res->next;
00493 }
00494
00495
00496 if (!res) {
00497 res = ast_malloc(sizeof(*res));
00498 if (!res) {
00499 ast_log(LOG_ERROR, "Out of memory!\n");
00500 return NULL;
00501 }
00502 res->jingle = 0;
00503 res->parent = list;
00504 ast_copy_string(res->version, version, sizeof(res->version));
00505 res->next = list->versions;
00506 list->versions = res;
00507 return res;
00508 }
00509 }
00510 list = list->next;
00511 }
00512
00513 if (!list) {
00514 list = ast_malloc(sizeof(*list));
00515 if (!list) {
00516 ast_log(LOG_ERROR, "Out of memory!\n");
00517 return NULL;
00518 }
00519 res = ast_malloc(sizeof(*res));
00520 if (!res) {
00521 ast_log(LOG_ERROR, "Out of memory!\n");
00522 ast_free(list);
00523 return NULL;
00524 }
00525 ast_copy_string(list->node, node, sizeof(list->node));
00526 ast_copy_string(res->version, version, sizeof(res->version));
00527 res->jingle = 0;
00528 res->parent = list;
00529 res->next = NULL;
00530 list->versions = res;
00531 list->next = capabilities;
00532 capabilities = list;
00533 }
00534 return res;
00535 }
00536
00537
00538
00539
00540
00541
00542
00543
00544 static struct aji_resource *aji_find_resource(struct aji_buddy *buddy, char *name)
00545 {
00546 struct aji_resource *res = NULL;
00547 if (!buddy || !name) {
00548 return res;
00549 }
00550 res = buddy->resources;
00551 while (res) {
00552 if (!strcasecmp(res->resource, name)) {
00553 break;
00554 }
00555 res = res->next;
00556 }
00557 return res;
00558 }
00559
00560
00561
00562
00563
00564
00565
00566 static int gtalk_yuck(iks *node)
00567 {
00568 if (iks_find_with_attrib(node, "c", "node", "http://www.google.com/xmpp/client/caps")) {
00569 ast_debug(1, "Found resource with Googletalk voice capabilities\n");
00570 return 1;
00571 } else if (iks_find_with_attrib(node, "caps:c", "ext", "pmuc-v1 sms-v1 camera-v1 video-v1 voice-v1")) {
00572 ast_debug(1, "Found resource with Gmail voice/video chat capabilities\n");
00573 return 1;
00574 } else if (iks_find_with_attrib(node, "caps:c", "ext", "pmuc-v1 sms-v1 video-v1 voice-v1")) {
00575 ast_debug(1, "Found resource with Gmail voice/video chat capabilities (no camera)\n");
00576 return 1;
00577 }
00578
00579 return 0;
00580 }
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590 static iks *jabber_make_auth(iksid * id, const char *pass, const char *sid)
00591 {
00592 iks *x, *y;
00593 x = iks_new("iq");
00594 iks_insert_attrib(x, "type", "set");
00595 y = iks_insert(x, "query");
00596 iks_insert_attrib(y, "xmlns", IKS_NS_AUTH);
00597 iks_insert_cdata(iks_insert(y, "username"), id->user, 0);
00598 iks_insert_cdata(iks_insert(y, "resource"), id->resource, 0);
00599 if (sid) {
00600 char buf[41];
00601 char sidpass[100];
00602 snprintf(sidpass, sizeof(sidpass), "%s%s", sid, pass);
00603 ast_sha1_hash(buf, sidpass);
00604 iks_insert_cdata(iks_insert(y, "digest"), buf, 0);
00605 } else {
00606 iks_insert_cdata(iks_insert(y, "password"), pass, 0);
00607 }
00608 return x;
00609 }
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620 static int aji_status_exec(struct ast_channel *chan, const char *data)
00621 {
00622 struct aji_client *client = NULL;
00623 struct aji_buddy *buddy = NULL;
00624 struct aji_resource *r = NULL;
00625 char *s = NULL;
00626 int stat = 7;
00627 char status[2];
00628 static int deprecation_warning = 0;
00629 AST_DECLARE_APP_ARGS(args,
00630 AST_APP_ARG(sender);
00631 AST_APP_ARG(jid);
00632 AST_APP_ARG(variable);
00633 );
00634 AST_DECLARE_APP_ARGS(jid,
00635 AST_APP_ARG(screenname);
00636 AST_APP_ARG(resource);
00637 );
00638
00639 if (deprecation_warning++ % 10 == 0) {
00640 ast_log(LOG_WARNING, "JabberStatus is deprecated. Please use the JABBER_STATUS dialplan function in the future.\n");
00641 }
00642
00643 if (!data) {
00644 ast_log(LOG_ERROR, "Usage: JabberStatus(<sender>,<jid>[/<resource>],<varname>\n");
00645 return 0;
00646 }
00647 s = ast_strdupa(data);
00648 AST_STANDARD_APP_ARGS(args, s);
00649
00650 if (args.argc != 3) {
00651 ast_log(LOG_ERROR, "JabberStatus() requires 3 arguments.\n");
00652 return -1;
00653 }
00654
00655 AST_NONSTANDARD_APP_ARGS(jid, args.jid, '/');
00656 if (jid.argc < 1 || jid.argc > 2) {
00657 ast_log(LOG_WARNING, "Wrong JID %s, exiting\n", args.jid);
00658 return -1;
00659 }
00660
00661 if (!(client = ast_aji_get_client(args.sender))) {
00662 ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
00663 return -1;
00664 }
00665 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, jid.screenname);
00666 if (!buddy) {
00667 ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
00668 ASTOBJ_UNREF(client, ast_aji_client_destroy);
00669 return -1;
00670 }
00671 r = aji_find_resource(buddy, jid.resource);
00672 if (!r && buddy->resources) {
00673 r = buddy->resources;
00674 }
00675 ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
00676 ASTOBJ_UNREF(client, ast_aji_client_destroy);
00677 if (!r) {
00678 ast_log(LOG_NOTICE, "Resource '%s' of buddy '%s' was not found\n", jid.resource, jid.screenname);
00679 } else {
00680 stat = r->status;
00681 }
00682 snprintf(status, sizeof(status), "%d", stat);
00683 pbx_builtin_setvar_helper(chan, args.variable, status);
00684 return 0;
00685 }
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696 static int acf_jabberstatus_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
00697 {
00698 struct aji_client *client = NULL;
00699 struct aji_buddy *buddy = NULL;
00700 struct aji_resource *r = NULL;
00701 int stat = 7;
00702 AST_DECLARE_APP_ARGS(args,
00703 AST_APP_ARG(sender);
00704 AST_APP_ARG(jid);
00705 );
00706 AST_DECLARE_APP_ARGS(jid,
00707 AST_APP_ARG(screenname);
00708 AST_APP_ARG(resource);
00709 );
00710
00711 if (!data) {
00712 ast_log(LOG_ERROR, "Usage: JABBER_STATUS(<sender>,<jid>[/<resource>])\n");
00713 return 0;
00714 }
00715 AST_STANDARD_APP_ARGS(args, data);
00716
00717 if (args.argc != 2) {
00718 ast_log(LOG_ERROR, "JABBER_STATUS requires 2 arguments: sender and jid.\n");
00719 return -1;
00720 }
00721
00722 AST_NONSTANDARD_APP_ARGS(jid, args.jid, '/');
00723 if (jid.argc < 1 || jid.argc > 2) {
00724 ast_log(LOG_WARNING, "Wrong JID %s, exiting\n", args.jid);
00725 return -1;
00726 }
00727
00728 if (!(client = ast_aji_get_client(args.sender))) {
00729 ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
00730 return -1;
00731 }
00732 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, jid.screenname);
00733 if (!buddy) {
00734 ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
00735 ASTOBJ_UNREF(client, ast_aji_client_destroy);
00736 return -1;
00737 }
00738 r = aji_find_resource(buddy, jid.resource);
00739 if (!r && buddy->resources) {
00740 r = buddy->resources;
00741 }
00742 ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
00743 ASTOBJ_UNREF(client, ast_aji_client_destroy);
00744 if (!r) {
00745 ast_log(LOG_NOTICE, "Resource %s of buddy %s was not found.\n", jid.resource, jid.screenname);
00746 } else {
00747 stat = r->status;
00748 }
00749 snprintf(buf, buflen, "%d", stat);
00750 return 0;
00751 }
00752
00753 static struct ast_custom_function jabberstatus_function = {
00754 .name = "JABBER_STATUS",
00755 .read = acf_jabberstatus_read,
00756 };
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767 static int acf_jabberreceive_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
00768 {
00769 char *aux = NULL, *parse = NULL;
00770 int timeout;
00771 int jidlen, resourcelen;
00772 struct timeval start;
00773 long diff = 0;
00774 struct aji_client *client = NULL;
00775 int found = 0;
00776 struct aji_message *tmp = NULL;
00777 AST_DECLARE_APP_ARGS(args,
00778 AST_APP_ARG(account);
00779 AST_APP_ARG(jid);
00780 AST_APP_ARG(timeout);
00781 );
00782 AST_DECLARE_APP_ARGS(jid,
00783 AST_APP_ARG(screenname);
00784 AST_APP_ARG(resource);
00785 );
00786
00787 if (ast_strlen_zero(data)) {
00788 ast_log(LOG_WARNING, "%s requires arguments (account,jid[,timeout])\n", name);
00789 return -1;
00790 }
00791
00792 parse = ast_strdupa(data);
00793 AST_STANDARD_APP_ARGS(args, parse);
00794
00795 if (args.argc < 2 || args.argc > 3) {
00796 ast_log(LOG_WARNING, "%s requires arguments (account,jid[,timeout])\n", name);
00797 return -1;
00798 }
00799
00800 parse = ast_strdupa(args.jid);
00801 AST_NONSTANDARD_APP_ARGS(jid, parse, '/');
00802 if (jid.argc < 1 || jid.argc > 2 || strlen(args.jid) > AJI_MAX_JIDLEN) {
00803 ast_log(LOG_WARNING, "Invalid JID : %s\n", parse);
00804 return -1;
00805 }
00806
00807 if (ast_strlen_zero(args.timeout)) {
00808 timeout = 20;
00809 } else {
00810 sscanf(args.timeout, "%d", &timeout);
00811 if (timeout <= 0) {
00812 ast_log(LOG_WARNING, "Invalid timeout specified: '%s'\n", args.timeout);
00813 return -1;
00814 }
00815 }
00816
00817 jidlen = strlen(jid.screenname);
00818 resourcelen = ast_strlen_zero(jid.resource) ? 0 : strlen(jid.resource);
00819
00820 client = ast_aji_get_client(args.account);
00821 if (!client) {
00822 ast_log(LOG_WARNING, "Could not find client %s, exiting\n", args.account);
00823 return -1;
00824 }
00825
00826 ast_debug(3, "Waiting for an XMPP message from %s\n", args.jid);
00827
00828 start = ast_tvnow();
00829
00830 if (ast_autoservice_start(chan) < 0) {
00831 ast_log(LOG_WARNING, "Cannot start autoservice for channel %s\n", chan->name);
00832 ASTOBJ_UNREF(client, ast_aji_client_destroy);
00833 return -1;
00834 }
00835
00836
00837
00838 while (diff < timeout) {
00839 struct timespec ts = { 0, };
00840 struct timeval wait;
00841 int res;
00842
00843 wait = ast_tvadd(start, ast_tv(timeout, 0));
00844 ts.tv_sec = wait.tv_sec;
00845 ts.tv_nsec = wait.tv_usec * 1000;
00846
00847
00848 ast_mutex_lock(&messagelock);
00849 res = ast_cond_timedwait(&message_received_condition, &messagelock, &ts);
00850 ast_mutex_unlock(&messagelock);
00851 if (res == ETIMEDOUT) {
00852 ast_debug(3, "No message received from %s in %d seconds\n", args.jid, timeout);
00853 break;
00854 }
00855
00856 AST_LIST_LOCK(&client->messages);
00857 AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, tmp, list) {
00858 if (jid.argc == 1) {
00859
00860 if (strncasecmp(jid.screenname, tmp->from, jidlen)) {
00861 continue;
00862 }
00863 } else {
00864
00865 char *resource = strchr(tmp->from, '/');
00866 if (!resource || strlen(resource) == 0) {
00867 ast_log(LOG_WARNING, "Remote JID has no resource : %s\n", tmp->from);
00868 if (strncasecmp(jid.screenname, tmp->from, jidlen)) {
00869 continue;
00870 }
00871 } else {
00872 resource ++;
00873 if (strncasecmp(jid.screenname, tmp->from, jidlen) || strncmp(jid.resource, resource, resourcelen)) {
00874 continue;
00875 }
00876 }
00877 }
00878
00879 if (ast_tvdiff_sec(ast_tvnow(), tmp->arrived) >= client->message_timeout) {
00880 ast_debug(3, "Found old message from %s, deleting it\n", tmp->from);
00881 AST_LIST_REMOVE_CURRENT(list);
00882 aji_message_destroy(tmp);
00883 continue;
00884 }
00885 found = 1;
00886 aux = ast_strdupa(tmp->message);
00887 AST_LIST_REMOVE_CURRENT(list);
00888 aji_message_destroy(tmp);
00889 break;
00890 }
00891 AST_LIST_TRAVERSE_SAFE_END;
00892 AST_LIST_UNLOCK(&client->messages);
00893 if (found) {
00894 break;
00895 }
00896
00897
00898 diff = ast_tvdiff_ms(ast_tvnow(), start);
00899 }
00900
00901 ASTOBJ_UNREF(client, ast_aji_client_destroy);
00902 if (ast_autoservice_stop(chan) < 0) {
00903 ast_log(LOG_WARNING, "Cannot stop autoservice for channel %s\n", chan->name);
00904 }
00905
00906
00907 if (!found) {
00908 ast_log(LOG_NOTICE, "Timed out : no message received from %s\n", args.jid);
00909 return -1;
00910 }
00911 ast_copy_string(buf, aux, buflen);
00912
00913 return 0;
00914 }
00915
00916 static struct ast_custom_function jabberreceive_function = {
00917 .name = "JABBER_RECEIVE",
00918 .read = acf_jabberreceive_read,
00919 };
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930 static int delete_old_messages(struct aji_client *client, char *from)
00931 {
00932 int deleted = 0;
00933 int isold = 0;
00934 struct aji_message *tmp = NULL;
00935 if (!client) {
00936 ast_log(LOG_ERROR, "Cannot find our XMPP client\n");
00937 return -1;
00938 }
00939
00940
00941 AST_LIST_LOCK(&client->messages);
00942 if (AST_LIST_EMPTY(&client->messages)) {
00943 AST_LIST_UNLOCK(&client->messages);
00944 return 0;
00945 }
00946
00947 AST_LIST_TRAVERSE_SAFE_BEGIN(&client->messages, tmp, list) {
00948 if (isold) {
00949 if (!from || !strncasecmp(from, tmp->from, strlen(from))) {
00950 AST_LIST_REMOVE_CURRENT(list);
00951 aji_message_destroy(tmp);
00952 deleted ++;
00953 }
00954 } else if (ast_tvdiff_sec(ast_tvnow(), tmp->arrived) >= client->message_timeout) {
00955 isold = 1;
00956 if (!from || !strncasecmp(from, tmp->from, strlen(from))) {
00957 AST_LIST_REMOVE_CURRENT(list);
00958 aji_message_destroy(tmp);
00959 deleted ++;
00960 }
00961 }
00962 }
00963 AST_LIST_TRAVERSE_SAFE_END;
00964 AST_LIST_UNLOCK(&client->messages);
00965
00966 return deleted;
00967 }
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977 static int delete_old_messages_all(struct aji_client *client)
00978 {
00979 return delete_old_messages(client, NULL);
00980 }
00981
00982
00983
00984
00985
00986
00987
00988
00989 static int aji_join_exec(struct ast_channel *chan, const char *data)
00990 {
00991 struct aji_client *client = NULL;
00992 char *s;
00993 char nick[AJI_MAX_RESJIDLEN];
00994
00995 AST_DECLARE_APP_ARGS(args,
00996 AST_APP_ARG(sender);
00997 AST_APP_ARG(jid);
00998 AST_APP_ARG(nick);
00999 );
01000
01001 if (!data) {
01002 ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajijoin);
01003 return -1;
01004 }
01005 s = ast_strdupa(data);
01006
01007 AST_STANDARD_APP_ARGS(args, s);
01008 if (args.argc < 2 || args.argc > 3) {
01009 ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajijoin);
01010 return -1;
01011 }
01012
01013 if (strchr(args.jid, '/')) {
01014 ast_log(LOG_ERROR, "Invalid room name : resource must not be appended\n");
01015 return -1;
01016 }
01017
01018 if (!(client = ast_aji_get_client(args.sender))) {
01019 ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
01020 return -1;
01021 }
01022
01023 if (!ast_strlen_zero(args.nick)) {
01024 snprintf(nick, AJI_MAX_RESJIDLEN, "%s", args.nick);
01025 } else {
01026 if (client->component) {
01027 sprintf(nick, "asterisk");
01028 } else {
01029 snprintf(nick, AJI_MAX_RESJIDLEN, "%s", client->jid->user);
01030 }
01031 }
01032
01033 if (!ast_strlen_zero(args.jid) && strchr(args.jid, '@')) {
01034 ast_aji_join_chat(client, args.jid, nick);
01035 } else {
01036 ast_log(LOG_ERROR, "Problem with specified jid of '%s'\n", args.jid);
01037 }
01038
01039 ASTOBJ_UNREF(client, ast_aji_client_destroy);
01040 return 0;
01041 }
01042
01043
01044
01045
01046
01047
01048
01049
01050 static int aji_leave_exec(struct ast_channel *chan, const char *data)
01051 {
01052 struct aji_client *client = NULL;
01053 char *s;
01054 char nick[AJI_MAX_RESJIDLEN];
01055 AST_DECLARE_APP_ARGS(args,
01056 AST_APP_ARG(sender);
01057 AST_APP_ARG(jid);
01058 AST_APP_ARG(nick);
01059 );
01060
01061 if (!data) {
01062 ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajileave);
01063 return -1;
01064 }
01065 s = ast_strdupa(data);
01066
01067 AST_STANDARD_APP_ARGS(args, s);
01068 if (args.argc < 2 || args.argc > 3) {
01069 ast_log(LOG_ERROR, "%s requires arguments (sender,jid[,nickname])\n", app_ajileave);
01070 return -1;
01071 }
01072
01073 if (strchr(args.jid, '/')) {
01074 ast_log(LOG_ERROR, "Invalid room name, resource must not be appended\n");
01075 return -1;
01076 }
01077
01078 if (!(client = ast_aji_get_client(args.sender))) {
01079 ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
01080 return -1;
01081 }
01082
01083 if (!ast_strlen_zero(args.nick)) {
01084 snprintf(nick, AJI_MAX_RESJIDLEN, "%s", args.nick);
01085 } else {
01086 if (client->component) {
01087 sprintf(nick, "asterisk");
01088 } else {
01089 snprintf(nick, AJI_MAX_RESJIDLEN, "%s", client->jid->user);
01090 }
01091 }
01092
01093 if (!ast_strlen_zero(args.jid) && strchr(args.jid, '@')) {
01094 ast_aji_leave_chat(client, args.jid, nick);
01095 }
01096 ASTOBJ_UNREF(client, ast_aji_client_destroy);
01097 return 0;
01098 }
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108 static int aji_send_exec(struct ast_channel *chan, const char *data)
01109 {
01110 struct aji_client *client = NULL;
01111 char *s;
01112 AST_DECLARE_APP_ARGS(args,
01113 AST_APP_ARG(sender);
01114 AST_APP_ARG(recipient);
01115 AST_APP_ARG(message);
01116 );
01117
01118 if (!data) {
01119 ast_log(LOG_WARNING, "%s requires arguments (account,jid,message)\n", app_ajisend);
01120 return -1;
01121 }
01122 s = ast_strdupa(data);
01123
01124 AST_STANDARD_APP_ARGS(args, s);
01125 if (args.argc < 3) {
01126 ast_log(LOG_WARNING, "%s requires arguments (account,jid,message)\n", app_ajisend);
01127 return -1;
01128 }
01129
01130 if (!(client = ast_aji_get_client(args.sender))) {
01131 ast_log(LOG_WARNING, "Could not find sender connection: '%s'\n", args.sender);
01132 return -1;
01133 }
01134 if (strchr(args.recipient, '@') && !ast_strlen_zero(args.message)) {
01135 ast_aji_send_chat(client, args.recipient, args.message);
01136 }
01137 ASTOBJ_UNREF(client, ast_aji_client_destroy);
01138 return 0;
01139 }
01140
01141
01142
01143
01144
01145
01146
01147
01148 static int aji_sendgroup_exec(struct ast_channel *chan, const char *data)
01149 {
01150 struct aji_client *client = NULL;
01151 char *s;
01152 char nick[AJI_MAX_RESJIDLEN];
01153 int res = 0;
01154 AST_DECLARE_APP_ARGS(args,
01155 AST_APP_ARG(sender);
01156 AST_APP_ARG(groupchat);
01157 AST_APP_ARG(message);
01158 AST_APP_ARG(nick);
01159 );
01160
01161 if (!data) {
01162 ast_log(LOG_ERROR, "%s requires arguments (sender,groupchatid,message[,nickname])\n", app_ajisendgroup);
01163 return -1;
01164 }
01165 s = ast_strdupa(data);
01166
01167 AST_STANDARD_APP_ARGS(args, s);
01168 if (args.argc < 3 || args.argc > 4) {
01169 ast_log(LOG_ERROR, "%s requires arguments (sender,groupchatid,message[,nickname])\n", app_ajisendgroup);
01170 return -1;
01171 }
01172
01173 if (!(client = ast_aji_get_client(args.sender))) {
01174 ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
01175 return -1;
01176 }
01177
01178 if (ast_strlen_zero(args.nick) || args.argc == 3) {
01179 if (client->component) {
01180 sprintf(nick, "asterisk");
01181 } else {
01182 snprintf(nick, AJI_MAX_RESJIDLEN, "%s", client->jid->user);
01183 }
01184 } else {
01185 snprintf(nick, AJI_MAX_RESJIDLEN, "%s", args.nick);
01186 }
01187
01188 if (strchr(args.groupchat, '@') && !ast_strlen_zero(args.message)) {
01189 res = ast_aji_send_groupchat(client, nick, args.groupchat, args.message);
01190 }
01191
01192 ASTOBJ_UNREF(client, ast_aji_client_destroy);
01193 if (res != IKS_OK) {
01194 return -1;
01195 }
01196 return 0;
01197 }
01198
01199
01200
01201
01202
01203
01204 static int aji_is_secure(struct aji_client *client)
01205 {
01206 #ifdef HAVE_OPENSSL
01207 return client->stream_flags & SECURE;
01208 #else
01209 return 0;
01210 #endif
01211 }
01212
01213 #ifdef HAVE_OPENSSL
01214
01215
01216
01217
01218
01219
01220
01221 static int aji_start_tls(struct aji_client *client)
01222 {
01223 int ret;
01224
01225
01226 if ((ret = iks_send_raw(client->p, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>"))) {
01227 return ret;
01228 }
01229
01230 client->stream_flags |= TRY_SECURE;
01231 return IKS_OK;
01232 }
01233
01234
01235
01236
01237
01238
01239
01240 static int aji_tls_handshake(struct aji_client *client)
01241 {
01242 int ret;
01243 int sock;
01244
01245 ast_debug(1, "Starting TLS handshake\n");
01246
01247
01248 client->ssl_method = SSLv3_method();
01249 if (!(client->ssl_context = SSL_CTX_new((SSL_METHOD *) client->ssl_method))) {
01250 return IKS_NET_TLSFAIL;
01251 }
01252
01253
01254 if (!(client->ssl_session = SSL_new(client->ssl_context))) {
01255 return IKS_NET_TLSFAIL;
01256 }
01257
01258
01259 sock = iks_fd(client->p);
01260 if (!(ret = SSL_set_fd(client->ssl_session, sock))) {
01261 return IKS_NET_TLSFAIL;
01262 }
01263
01264
01265 if (!(ret = SSL_connect(client->ssl_session))) {
01266 return IKS_NET_TLSFAIL;
01267 }
01268
01269 client->stream_flags &= (~TRY_SECURE);
01270 client->stream_flags |= SECURE;
01271
01272
01273 if ((ret = aji_send_header(client, client->jid->server)) != IKS_OK) {
01274 return IKS_NET_TLSFAIL;
01275 }
01276
01277 ast_debug(1, "TLS started with server\n");
01278
01279 return IKS_OK;
01280 }
01281 #endif
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294 static int aji_io_recv(struct aji_client *client, char *buffer, size_t buf_len, int timeout)
01295 {
01296 struct pollfd pfd = { .events = POLLIN };
01297 int len, res;
01298
01299 #ifdef HAVE_OPENSSL
01300 if (aji_is_secure(client)) {
01301 pfd.fd = SSL_get_fd(client->ssl_session);
01302 if (pfd.fd < 0) {
01303 return -1;
01304 }
01305 } else
01306 #endif
01307 pfd.fd = iks_fd(client->p);
01308
01309 res = ast_poll(&pfd, 1, timeout > 0 ? timeout * 1000 : -1);
01310 if (res > 0) {
01311 #ifdef HAVE_OPENSSL
01312 if (aji_is_secure(client)) {
01313 len = SSL_read(client->ssl_session, buffer, buf_len);
01314 } else
01315 #endif
01316 len = recv(pfd.fd, buffer, buf_len, 0);
01317
01318 if (len > 0) {
01319 return len;
01320 } else if (len <= 0) {
01321 return -1;
01322 }
01323 }
01324 return res;
01325 }
01326
01327
01328
01329
01330
01331
01332
01333
01334
01335
01336
01337
01338
01339 static int aji_recv (struct aji_client *client, int timeout)
01340 {
01341 int len, ret;
01342 char buf[NET_IO_BUF_SIZE - 1];
01343 char newbuf[NET_IO_BUF_SIZE - 1];
01344 int pos = 0;
01345 int newbufpos = 0;
01346 unsigned char c;
01347
01348 memset(buf, 0, sizeof(buf));
01349 memset(newbuf, 0, sizeof(newbuf));
01350
01351 while (1) {
01352 len = aji_io_recv(client, buf, NET_IO_BUF_SIZE - 2, timeout);
01353 if (len < 0) return IKS_NET_RWERR;
01354 if (len == 0) return IKS_NET_EXPIRED;
01355 buf[len] = '\0';
01356
01357
01358
01359
01360 while (pos < len) {
01361 c = buf[pos];
01362
01363
01364 if (c == '>') {
01365 while (isspace(buf[pos+1])) {
01366 pos++;
01367 }
01368 }
01369 newbuf[newbufpos] = c;
01370 newbufpos ++;
01371 pos++;
01372 }
01373 pos = 0;
01374 newbufpos = 0;
01375
01376
01377
01378 aji_log_hook(client, buf, len, 1);
01379
01380
01381
01382 ret = iks_parse(client->p, newbuf, 0, 0);
01383 memset(newbuf, 0, sizeof(newbuf));
01384
01385 switch (ret) {
01386 case IKS_NOMEM:
01387 ast_log(LOG_WARNING, "Parsing failure: Out of memory.\n");
01388 break;
01389 case IKS_BADXML:
01390 ast_log(LOG_WARNING, "Parsing failure: Invalid XML.\n");
01391 break;
01392 case IKS_HOOK:
01393 ast_log(LOG_WARNING, "Parsing failure: Hook returned an error.\n");
01394 break;
01395 }
01396 if (ret != IKS_OK) {
01397 return ret;
01398 }
01399 ast_debug(3, "XML parsing successful\n");
01400 }
01401 return IKS_OK;
01402 }
01403
01404
01405
01406
01407
01408
01409
01410
01411 static int aji_send_header(struct aji_client *client, const char *to)
01412 {
01413 char *msg;
01414 int len, err;
01415
01416 len = 91 + strlen(client->name_space) + 6 + strlen(to) + 16 + 1;
01417 msg = iks_malloc(len);
01418 if (!msg)
01419 return IKS_NOMEM;
01420 sprintf(msg, "<?xml version='1.0'?>"
01421 "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='"
01422 "%s' to='%s' version='1.0'>", client->name_space, to);
01423 err = aji_send_raw(client, msg);
01424 iks_free(msg);
01425 if (err != IKS_OK)
01426 return err;
01427
01428 return IKS_OK;
01429 }
01430
01431
01432
01433
01434
01435
01436
01437 int ast_aji_send(struct aji_client *client, iks *x)
01438 {
01439 return aji_send_raw(client, iks_string(iks_stack(x), x));
01440 }
01441
01442
01443
01444
01445
01446
01447
01448
01449
01450
01451 static int aji_send_raw(struct aji_client *client, const char *xmlstr)
01452 {
01453 int ret;
01454 #ifdef HAVE_OPENSSL
01455 int len = strlen(xmlstr);
01456
01457 if (aji_is_secure(client)) {
01458 ret = SSL_write(client->ssl_session, xmlstr, len);
01459 if (ret) {
01460
01461
01462 aji_log_hook(client, xmlstr, len, 0);
01463 return IKS_OK;
01464 }
01465 }
01466 #endif
01467
01468
01469 ret = iks_send_raw(client->p, xmlstr);
01470 if (ret != IKS_OK) {
01471 return ret;
01472 }
01473
01474 return IKS_OK;
01475 }
01476
01477
01478
01479
01480
01481
01482
01483
01484
01485 static void aji_log_hook(void *data, const char *xmpp, size_t size, int is_incoming)
01486 {
01487 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01488
01489 if (!ast_strlen_zero(xmpp)) {
01490 manager_event(EVENT_FLAG_USER, "JabberEvent", "Account: %s\r\nPacket: %s\r\n", client->name, xmpp);
01491 }
01492
01493 if (client->debug) {
01494 if (is_incoming) {
01495 ast_verbose("\nJABBER: %s INCOMING: %s\n", client->name, xmpp);
01496 } else {
01497 if (strlen(xmpp) == 1) {
01498 if (option_debug > 2 && xmpp[0] == ' ') {
01499 ast_verbose("\nJABBER: Keep alive packet\n");
01500 }
01501 } else {
01502 ast_verbose("\nJABBER: %s OUTGOING: %s\n", client->name, xmpp);
01503 }
01504 }
01505
01506 }
01507 ASTOBJ_UNREF(client, ast_aji_client_destroy);
01508 }
01509
01510
01511
01512
01513
01514
01515
01516
01517
01518
01519
01520 static int aji_start_sasl(struct aji_client *client, enum ikssasltype type, char *username, char *pass)
01521 {
01522 iks *x = NULL;
01523 int len;
01524 char *s;
01525 char *base64;
01526
01527
01528
01529
01530 if ((type & IKS_STREAM_SASL_MD5) && !aji_is_secure(client))
01531 return iks_start_sasl(client->p, IKS_SASL_DIGEST_MD5, username, pass);
01532 if (!(type & IKS_STREAM_SASL_PLAIN)) {
01533 ast_log(LOG_ERROR, "Server does not support SASL PLAIN authentication\n");
01534 return IKS_NET_NOTSUPP;
01535 }
01536
01537 x = iks_new("auth");
01538 if (!x) {
01539 ast_log(LOG_ERROR, "Out of memory.\n");
01540 return IKS_NET_NOTSUPP;
01541 }
01542
01543 iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_SASL);
01544 len = strlen(username) + strlen(pass) + 3;
01545 s = ast_alloca(len);
01546 base64 = ast_alloca((len + 2) * 4 / 3);
01547 iks_insert_attrib(x, "mechanism", "PLAIN");
01548 snprintf(s, len, "%c%s%c%s", 0, username, 0, pass);
01549
01550
01551
01552
01553
01554 ast_base64encode(base64, (const unsigned char *) s, len - 1, (len + 2) * 4 / 3);
01555 iks_insert_cdata(x, base64, 0);
01556 ast_aji_send(client, x);
01557 iks_delete(x);
01558
01559 return IKS_OK;
01560 }
01561
01562
01563
01564
01565
01566
01567
01568
01569
01570 static int aji_act_hook(void *data, int type, iks *node)
01571 {
01572 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01573 ikspak *pak = NULL;
01574 iks *auth = NULL;
01575 int features = 0;
01576
01577 if (!node) {
01578 ast_log(LOG_ERROR, "aji_act_hook was called with out a packet\n");
01579 ASTOBJ_UNREF(client, ast_aji_client_destroy);
01580 return IKS_HOOK;
01581 }
01582
01583 if (client->state == AJI_DISCONNECTING) {
01584 ASTOBJ_UNREF(client, ast_aji_client_destroy);
01585 return IKS_HOOK;
01586 }
01587
01588 pak = iks_packet(node);
01589
01590
01591
01592
01593 if (iks_has_children(node) && strchr(iks_name(iks_child(node)), ':')) {
01594 char *node_ns = NULL;
01595 char attr[AJI_MAX_ATTRLEN];
01596 char *node_name = iks_name(iks_child(node));
01597 char *aux = strchr(node_name, ':') + 1;
01598 snprintf(attr, strlen("xmlns:") + (strlen(node_name) - strlen(aux)), "xmlns:%s", node_name);
01599 node_ns = iks_find_attrib(iks_child(node), attr);
01600 if (node_ns) {
01601 pak->ns = node_ns;
01602 pak->query = iks_child(node);
01603 }
01604 }
01605
01606
01607 if (!client->component) {
01608 switch (type) {
01609 case IKS_NODE_START:
01610 if (client->usetls && !aji_is_secure(client)) {
01611 #ifndef HAVE_OPENSSL
01612 ast_log(LOG_ERROR, "TLS connection cannot be established. Please install OpenSSL and its development libraries on this system, or disable the TLS option in your configuration file\n");
01613 ASTOBJ_UNREF(client, ast_aji_client_destroy);
01614 return IKS_HOOK;
01615 #else
01616 if (aji_start_tls(client) == IKS_NET_TLSFAIL) {
01617 ast_log(LOG_ERROR, "Could not start TLS\n");
01618 ASTOBJ_UNREF(client, ast_aji_client_destroy);
01619 return IKS_HOOK;
01620 }
01621 #endif
01622 break;
01623 }
01624 if (!client->usesasl) {
01625 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);
01626 auth = jabber_make_auth(client->jid, client->password, iks_find_attrib(node, "id"));
01627 if (auth) {
01628 iks_insert_attrib(auth, "id", client->mid);
01629 iks_insert_attrib(auth, "to", client->jid->server);
01630 ast_aji_increment_mid(client->mid);
01631 ast_aji_send(client, auth);
01632 iks_delete(auth);
01633 } else {
01634 ast_log(LOG_ERROR, "Out of memory.\n");
01635 }
01636 }
01637 break;
01638
01639 case IKS_NODE_NORMAL:
01640 #ifdef HAVE_OPENSSL
01641 if (client->stream_flags & TRY_SECURE) {
01642 if (!strcmp("proceed", iks_name(node))) {
01643 return aji_tls_handshake(client);
01644 }
01645 }
01646 #endif
01647 if (!strcmp("stream:features", iks_name(node))) {
01648 features = iks_stream_features(node);
01649 if (client->usesasl) {
01650 if (client->usetls && !aji_is_secure(client)) {
01651 break;
01652 }
01653 if (client->authorized) {
01654 if (features & IKS_STREAM_BIND) {
01655 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);
01656 auth = iks_make_resource_bind(client->jid);
01657 if (auth) {
01658 iks_insert_attrib(auth, "id", client->mid);
01659 ast_aji_increment_mid(client->mid);
01660 ast_aji_send(client, auth);
01661 iks_delete(auth);
01662 } else {
01663 ast_log(LOG_ERROR, "Out of memory.\n");
01664 break;
01665 }
01666 }
01667 if (features & IKS_STREAM_SESSION) {
01668 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);
01669 auth = iks_make_session();
01670 if (auth) {
01671 iks_insert_attrib(auth, "id", "auth");
01672 ast_aji_increment_mid(client->mid);
01673 ast_aji_send(client, auth);
01674 iks_delete(auth);
01675 } else {
01676 ast_log(LOG_ERROR, "Out of memory.\n");
01677 }
01678 }
01679 } else {
01680 int ret;
01681 if (!client->jid->user) {
01682 ast_log(LOG_ERROR, "Malformed Jabber ID : %s (domain missing?)\n", client->jid->full);
01683 break;
01684 }
01685
01686 ret = aji_start_sasl(client, features, client->jid->user, client->password);
01687 if (ret != IKS_OK) {
01688 ASTOBJ_UNREF(client, ast_aji_client_destroy);
01689 return IKS_HOOK;
01690 }
01691 break;
01692 }
01693 }
01694 } else if (!strcmp("failure", iks_name(node))) {
01695 ast_log(LOG_ERROR, "JABBER: encryption failure. possible bad password.\n");
01696 } else if (!strcmp("success", iks_name(node))) {
01697 client->authorized = 1;
01698 aji_send_header(client, client->jid->server);
01699 }
01700 break;
01701 case IKS_NODE_ERROR:
01702 ast_log(LOG_ERROR, "JABBER: Node Error\n");
01703 ASTOBJ_UNREF(client, ast_aji_client_destroy);
01704 return IKS_HOOK;
01705 break;
01706 case IKS_NODE_STOP:
01707 ast_log(LOG_WARNING, "JABBER: Disconnected\n");
01708 ASTOBJ_UNREF(client, ast_aji_client_destroy);
01709 return IKS_HOOK;
01710 break;
01711 }
01712 } else if (client->state != AJI_CONNECTED && client->component) {
01713 switch (type) {
01714 case IKS_NODE_START:
01715 if (client->state == AJI_DISCONNECTED) {
01716 char secret[160], shasum[320], *handshake;
01717
01718 sprintf(secret, "%s%s", pak->id, client->password);
01719 ast_sha1_hash(shasum, secret);
01720 if (ast_asprintf(&handshake, "<handshake>%s</handshake>", shasum) >= 0) {
01721 aji_send_raw(client, handshake);
01722 ast_free(handshake);
01723 }
01724 client->state = AJI_CONNECTING;
01725 if (aji_recv(client, 1) == 2)
01726 client->state = AJI_CONNECTED;
01727 else
01728 ast_log(LOG_WARNING, "Jabber didn't seem to handshake, failed to authenticate.\n");
01729 break;
01730 }
01731 break;
01732
01733 case IKS_NODE_NORMAL:
01734 break;
01735
01736 case IKS_NODE_ERROR:
01737 ast_log(LOG_ERROR, "JABBER: Node Error\n");
01738 ASTOBJ_UNREF(client, ast_aji_client_destroy);
01739 return IKS_HOOK;
01740
01741 case IKS_NODE_STOP:
01742 ast_log(LOG_WARNING, "JABBER: Disconnected\n");
01743 ASTOBJ_UNREF(client, ast_aji_client_destroy);
01744 return IKS_HOOK;
01745 }
01746 }
01747
01748 switch (pak->type) {
01749 case IKS_PAK_NONE:
01750 ast_debug(1, "JABBER: I don't know what to do with paktype NONE.\n");
01751 break;
01752 case IKS_PAK_MESSAGE:
01753 aji_handle_message(client, pak);
01754 ast_debug(1, "JABBER: Handling paktype MESSAGE.\n");
01755 break;
01756 case IKS_PAK_PRESENCE:
01757 aji_handle_presence(client, pak);
01758 ast_debug(1, "JABBER: Handling paktype PRESENCE\n");
01759 break;
01760 case IKS_PAK_S10N:
01761 aji_handle_subscribe(client, pak);
01762 ast_debug(1, "JABBER: Handling paktype S10N\n");
01763 break;
01764 case IKS_PAK_IQ:
01765 ast_debug(1, "JABBER: Handling paktype IQ\n");
01766 aji_handle_iq(client, node);
01767 break;
01768 default:
01769 ast_debug(1, "JABBER: I don't know anything about paktype '%d'\n", pak->type);
01770 break;
01771 }
01772
01773 iks_filter_packet(client->f, pak);
01774
01775 if (node)
01776 iks_delete(node);
01777
01778 ASTOBJ_UNREF(client, ast_aji_client_destroy);
01779 return IKS_OK;
01780 }
01781
01782
01783
01784
01785
01786
01787
01788 static int aji_register_approve_handler(void *data, ikspak *pak)
01789 {
01790 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01791 iks *iq = NULL, *presence = NULL, *x = NULL;
01792
01793 iq = iks_new("iq");
01794 presence = iks_new("presence");
01795 x = iks_new("x");
01796 if (client && iq && presence && x) {
01797 if (!iks_find(pak->query, "remove")) {
01798 iks_insert_attrib(iq, "from", client->jid->full);
01799 iks_insert_attrib(iq, "to", pak->from->full);
01800 iks_insert_attrib(iq, "id", pak->id);
01801 iks_insert_attrib(iq, "type", "result");
01802 ast_aji_send(client, iq);
01803
01804 iks_insert_attrib(presence, "from", client->jid->full);
01805 iks_insert_attrib(presence, "to", pak->from->partial);
01806 iks_insert_attrib(presence, "id", client->mid);
01807 ast_aji_increment_mid(client->mid);
01808 iks_insert_attrib(presence, "type", "subscribe");
01809 iks_insert_attrib(x, "xmlns", "vcard-temp:x:update");
01810 iks_insert_node(presence, x);
01811 ast_aji_send(client, presence);
01812 }
01813 } else {
01814 ast_log(LOG_ERROR, "Out of memory.\n");
01815 }
01816
01817 iks_delete(iq);
01818 iks_delete(presence);
01819 iks_delete(x);
01820
01821 ASTOBJ_UNREF(client, ast_aji_client_destroy);
01822 return IKS_FILTER_EAT;
01823 }
01824
01825
01826
01827
01828
01829
01830
01831 static int aji_register_query_handler(void *data, ikspak *pak)
01832 {
01833 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01834 struct aji_buddy *buddy = NULL;
01835 char *node = NULL;
01836 iks *iq = NULL, *query = NULL;
01837
01838 client = (struct aji_client *) data;
01839
01840 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
01841 if (!buddy) {
01842 iks *error = NULL, *notacceptable = NULL;
01843
01844 ast_log(LOG_ERROR, "Someone.... %s tried to register but they aren't allowed\n", pak->from->partial);
01845 iq = iks_new("iq");
01846 query = iks_new("query");
01847 error = iks_new("error");
01848 notacceptable = iks_new("not-acceptable");
01849 if (iq && query && error && notacceptable) {
01850 iks_insert_attrib(iq, "type", "error");
01851 iks_insert_attrib(iq, "from", client->user);
01852 iks_insert_attrib(iq, "to", pak->from->full);
01853 iks_insert_attrib(iq, "id", pak->id);
01854 iks_insert_attrib(query, "xmlns", "jabber:iq:register");
01855 iks_insert_attrib(error, "code" , "406");
01856 iks_insert_attrib(error, "type", "modify");
01857 iks_insert_attrib(notacceptable, "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas");
01858 iks_insert_node(iq, query);
01859 iks_insert_node(iq, error);
01860 iks_insert_node(error, notacceptable);
01861 ast_aji_send(client, iq);
01862 } else {
01863 ast_log(LOG_ERROR, "Out of memory.\n");
01864 }
01865
01866 iks_delete(error);
01867 iks_delete(notacceptable);
01868 } else if (!(node = iks_find_attrib(pak->query, "node"))) {
01869 iks *instructions = NULL;
01870 char *explain = "Welcome to Asterisk - the Open Source PBX.\n";
01871 iq = iks_new("iq");
01872 query = iks_new("query");
01873 instructions = iks_new("instructions");
01874 if (iq && query && instructions && client) {
01875 iks_insert_attrib(iq, "from", client->user);
01876 iks_insert_attrib(iq, "to", pak->from->full);
01877 iks_insert_attrib(iq, "id", pak->id);
01878 iks_insert_attrib(iq, "type", "result");
01879 iks_insert_attrib(query, "xmlns", "jabber:iq:register");
01880 iks_insert_cdata(instructions, explain, 0);
01881 iks_insert_node(iq, query);
01882 iks_insert_node(query, instructions);
01883 ast_aji_send(client, iq);
01884 } else {
01885 ast_log(LOG_ERROR, "Out of memory.\n");
01886 }
01887
01888 iks_delete(instructions);
01889 }
01890 iks_delete(iq);
01891 iks_delete(query);
01892 ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
01893 ASTOBJ_UNREF(client, ast_aji_client_destroy);
01894 return IKS_FILTER_EAT;
01895 }
01896
01897
01898
01899
01900
01901
01902
01903
01904 static int aji_ditems_handler(void *data, ikspak *pak)
01905 {
01906 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
01907 char *node = NULL;
01908
01909 if (!(node = iks_find_attrib(pak->query, "node"))) {
01910 iks *iq = NULL, *query = NULL, *item = NULL;
01911 iq = iks_new("iq");
01912 query = iks_new("query");
01913 item = iks_new("item");
01914
01915 if (iq && query && item) {
01916 iks_insert_attrib(iq, "from", client->user);
01917 iks_insert_attrib(iq, "to", pak->from->full);
01918 iks_insert_attrib(iq, "id", pak->id);
01919 iks_insert_attrib(iq, "type", "result");
01920 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01921 iks_insert_attrib(item, "node", "http://jabber.org/protocol/commands");
01922 iks_insert_attrib(item, "name", "Million Dollar Asterisk Commands");
01923 iks_insert_attrib(item, "jid", client->user);
01924
01925 iks_insert_node(iq, query);
01926 iks_insert_node(query, item);
01927 ast_aji_send(client, iq);
01928 } else {
01929 ast_log(LOG_ERROR, "Out of memory.\n");
01930 }
01931
01932 iks_delete(iq);
01933 iks_delete(query);
01934 iks_delete(item);
01935
01936 } else if (!strcasecmp(node, "http://jabber.org/protocol/commands")) {
01937 iks *iq, *query, *confirm;
01938 iq = iks_new("iq");
01939 query = iks_new("query");
01940 confirm = iks_new("item");
01941 if (iq && query && confirm && client) {
01942 iks_insert_attrib(iq, "from", client->user);
01943 iks_insert_attrib(iq, "to", pak->from->full);
01944 iks_insert_attrib(iq, "id", pak->id);
01945 iks_insert_attrib(iq, "type", "result");
01946 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01947 iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
01948 iks_insert_attrib(confirm, "node", "confirmaccount");
01949 iks_insert_attrib(confirm, "name", "Confirm AIM account");
01950 iks_insert_attrib(confirm, "jid", "blog.astjab.org");
01951
01952 iks_insert_node(iq, query);
01953 iks_insert_node(query, confirm);
01954 ast_aji_send(client, iq);
01955 } else {
01956 ast_log(LOG_ERROR, "Out of memory.\n");
01957 }
01958
01959 iks_delete(iq);
01960 iks_delete(query);
01961 iks_delete(confirm);
01962
01963 } else if (!strcasecmp(node, "confirmaccount")) {
01964 iks *iq = NULL, *query = NULL, *feature = NULL;
01965
01966 iq = iks_new("iq");
01967 query = iks_new("query");
01968 feature = iks_new("feature");
01969
01970 if (iq && query && feature && client) {
01971 iks_insert_attrib(iq, "from", client->user);
01972 iks_insert_attrib(iq, "to", pak->from->full);
01973 iks_insert_attrib(iq, "id", pak->id);
01974 iks_insert_attrib(iq, "type", "result");
01975 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
01976 iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
01977 iks_insert_node(iq, query);
01978 iks_insert_node(query, feature);
01979 ast_aji_send(client, iq);
01980 } else {
01981 ast_log(LOG_ERROR, "Out of memory.\n");
01982 }
01983
01984 iks_delete(iq);
01985 iks_delete(query);
01986 iks_delete(feature);
01987 }
01988
01989 ASTOBJ_UNREF(client, ast_aji_client_destroy);
01990 return IKS_FILTER_EAT;
01991
01992 }
01993
01994
01995
01996
01997
01998
01999
02000
02001 static int aji_client_info_handler(void *data, ikspak *pak)
02002 {
02003 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
02004 struct aji_resource *resource = NULL;
02005 struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
02006
02007 if (!buddy) {
02008 ast_log(LOG_NOTICE, "JABBER: Received client info from unknown buddy: %s.\n", pak->from->full);
02009 ASTOBJ_UNREF(client, ast_aji_client_destroy);
02010 return IKS_FILTER_EAT;
02011 }
02012
02013 resource = aji_find_resource(buddy, pak->from->resource);
02014 if (pak->subtype == IKS_TYPE_RESULT) {
02015 if (!resource) {
02016 ast_log(LOG_NOTICE, "JABBER: Received client info from %s when not requested.\n", pak->from->full);
02017 ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
02018 ASTOBJ_UNREF(client, ast_aji_client_destroy);
02019 return IKS_FILTER_EAT;
02020 }
02021 if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
02022 resource->cap->jingle = 1;
02023 } else {
02024 resource->cap->jingle = 0;
02025 }
02026 } else if (pak->subtype == IKS_TYPE_GET) {
02027 iks *iq, *disco, *ident, *google, *query;
02028 iq = iks_new("iq");
02029 query = iks_new("query");
02030 ident = iks_new("identity");
02031 disco = iks_new("feature");
02032 google = iks_new("feature");
02033 if (iq && ident && disco && google) {
02034 iks_insert_attrib(iq, "from", client->jid->full);
02035 iks_insert_attrib(iq, "to", pak->from->full);
02036 iks_insert_attrib(iq, "type", "result");
02037 iks_insert_attrib(iq, "id", pak->id);
02038 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
02039 iks_insert_attrib(ident, "category", "client");
02040 iks_insert_attrib(ident, "type", "pc");
02041 iks_insert_attrib(ident, "name", "asterisk");
02042 iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco#info");
02043 iks_insert_attrib(google, "var", "http://www.google.com/xmpp/protocol/voice/v1");
02044 iks_insert_node(iq, query);
02045 iks_insert_node(query, ident);
02046 iks_insert_node(query, google);
02047 iks_insert_node(query, disco);
02048 ast_aji_send(client, iq);
02049 } else {
02050 ast_log(LOG_ERROR, "Out of Memory.\n");
02051 }
02052
02053 iks_delete(iq);
02054 iks_delete(query);
02055 iks_delete(ident);
02056 iks_delete(google);
02057 iks_delete(disco);
02058 } else if (pak->subtype == IKS_TYPE_ERROR) {
02059 ast_log(LOG_NOTICE, "User %s does not support discovery.\n", pak->from->full);
02060 }
02061 ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
02062 ASTOBJ_UNREF(client, ast_aji_client_destroy);
02063 return IKS_FILTER_EAT;
02064 }
02065
02066
02067
02068
02069
02070
02071
02072
02073 static int aji_dinfo_handler(void *data, ikspak *pak)
02074 {
02075 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
02076 char *node = NULL;
02077 struct aji_resource *resource = NULL;
02078 struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
02079
02080 if (!buddy) {
02081 ast_log(LOG_NOTICE, "JABBER: Received client info from unknown buddy: %s.\n", pak->from->full);
02082 ASTOBJ_UNREF(client, ast_aji_client_destroy);
02083 return IKS_FILTER_EAT;
02084 }
02085
02086 if (pak->subtype == IKS_TYPE_ERROR) {
02087 ast_log(LOG_WARNING, "Received error from a client, turn on jabber debug!\n");
02088 ASTOBJ_UNREF(client, ast_aji_client_destroy);
02089 return IKS_FILTER_EAT;
02090 }
02091 resource = aji_find_resource(buddy, pak->from->resource);
02092 if (pak->subtype == IKS_TYPE_RESULT) {
02093 if (!resource) {
02094 ast_log(LOG_NOTICE, "JABBER: Received client info from %s when not requested.\n", pak->from->full);
02095 ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
02096 ASTOBJ_UNREF(client, ast_aji_client_destroy);
02097 return IKS_FILTER_EAT;
02098 }
02099 if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
02100 resource->cap->jingle = 1;
02101 } else {
02102 resource->cap->jingle = 0;
02103 }
02104 } else if (pak->subtype == IKS_TYPE_GET && !(node = iks_find_attrib(pak->query, "node"))) {
02105 iks *iq, *query, *identity, *disco, *reg, *commands, *gateway, *version, *vcard, *search;
02106
02107 iq = iks_new("iq");
02108 query = iks_new("query");
02109 identity = iks_new("identity");
02110 disco = iks_new("feature");
02111 reg = iks_new("feature");
02112 commands = iks_new("feature");
02113 gateway = iks_new("feature");
02114 version = iks_new("feature");
02115 vcard = iks_new("feature");
02116 search = iks_new("feature");
02117 if (iq && query && identity && disco && reg && commands && gateway && version && vcard && search && client) {
02118 iks_insert_attrib(iq, "from", client->user);
02119 iks_insert_attrib(iq, "to", pak->from->full);
02120 iks_insert_attrib(iq, "id", pak->id);
02121 iks_insert_attrib(iq, "type", "result");
02122 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
02123 iks_insert_attrib(identity, "category", "gateway");
02124 iks_insert_attrib(identity, "type", "pstn");
02125 iks_insert_attrib(identity, "name", "Asterisk The Open Source PBX");
02126 iks_insert_attrib(disco, "var", "http://jabber.org/protocol/disco");
02127 iks_insert_attrib(reg, "var", "jabber:iq:register");
02128 iks_insert_attrib(commands, "var", "http://jabber.org/protocol/commands");
02129 iks_insert_attrib(gateway, "var", "jabber:iq:gateway");
02130 iks_insert_attrib(version, "var", "jabber:iq:version");
02131 iks_insert_attrib(vcard, "var", "vcard-temp");
02132 iks_insert_attrib(search, "var", "jabber:iq:search");
02133
02134 iks_insert_node(iq, query);
02135 iks_insert_node(query, identity);
02136 iks_insert_node(query, disco);
02137 iks_insert_node(query, reg);
02138 iks_insert_node(query, commands);
02139 iks_insert_node(query, gateway);
02140 iks_insert_node(query, version);
02141 iks_insert_node(query, vcard);
02142 iks_insert_node(query, search);
02143 ast_aji_send(client, iq);
02144 } else {
02145 ast_log(LOG_ERROR, "Out of memory.\n");
02146 }
02147
02148 iks_delete(iq);
02149 iks_delete(query);
02150 iks_delete(identity);
02151 iks_delete(disco);
02152 iks_delete(reg);
02153 iks_delete(commands);
02154 iks_delete(gateway);
02155 iks_delete(version);
02156 iks_delete(vcard);
02157 iks_delete(search);
02158 } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "http://jabber.org/protocol/commands")) {
02159 iks *iq, *query, *confirm;
02160 iq = iks_new("iq");
02161 query = iks_new("query");
02162 confirm = iks_new("item");
02163
02164 if (iq && query && confirm && client) {
02165 iks_insert_attrib(iq, "from", client->user);
02166 iks_insert_attrib(iq, "to", pak->from->full);
02167 iks_insert_attrib(iq, "id", pak->id);
02168 iks_insert_attrib(iq, "type", "result");
02169 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
02170 iks_insert_attrib(query, "node", "http://jabber.org/protocol/commands");
02171 iks_insert_attrib(confirm, "node", "confirmaccount");
02172 iks_insert_attrib(confirm, "name", "Confirm AIM account");
02173 iks_insert_attrib(confirm, "jid", client->user);
02174 iks_insert_node(iq, query);
02175 iks_insert_node(query, confirm);
02176 ast_aji_send(client, iq);
02177 } else {
02178 ast_log(LOG_ERROR, "Out of memory.\n");
02179 }
02180
02181 iks_delete(iq);
02182 iks_delete(query);
02183 iks_delete(confirm);
02184
02185 } else if (pak->subtype == IKS_TYPE_GET && !strcasecmp(node, "confirmaccount")) {
02186 iks *iq, *query, *feature;
02187
02188 iq = iks_new("iq");
02189 query = iks_new("query");
02190 feature = iks_new("feature");
02191
02192 if (iq && query && feature && client) {
02193 iks_insert_attrib(iq, "from", client->user);
02194 iks_insert_attrib(iq, "to", pak->from->full);
02195 iks_insert_attrib(iq, "id", pak->id);
02196 iks_insert_attrib(iq, "type", "result");
02197 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
02198 iks_insert_attrib(feature, "var", "http://jabber.org/protocol/commands");
02199 iks_insert_node(iq, query);
02200 iks_insert_node(query, feature);
02201 ast_aji_send(client, iq);
02202 } else {
02203 ast_log(LOG_ERROR, "Out of memory.\n");
02204 }
02205
02206 iks_delete(iq);
02207 iks_delete(query);
02208 iks_delete(feature);
02209 }
02210
02211 ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
02212 ASTOBJ_UNREF(client, ast_aji_client_destroy);
02213 return IKS_FILTER_EAT;
02214 }
02215
02216
02217
02218
02219
02220
02221
02222
02223 static void aji_handle_iq(struct aji_client *client, iks *node)
02224 {
02225
02226 }
02227
02228
02229
02230
02231
02232
02233
02234
02235 static void aji_handle_message(struct aji_client *client, ikspak *pak)
02236 {
02237 struct aji_message *insert;
02238 int deleted = 0;
02239
02240 ast_debug(3, "client %s received a message\n", client->name);
02241
02242 if (!(insert = ast_calloc(1, sizeof(*insert)))) {
02243 return;
02244 }
02245
02246 insert->arrived = ast_tvnow();
02247
02248
02249 ast_mutex_lock(&messagelock);
02250 ast_cond_broadcast(&message_received_condition);
02251 ast_mutex_unlock(&messagelock);
02252
02253 if (iks_find_cdata(pak->x, "body")) {
02254 insert->message = ast_strdup(iks_find_cdata(pak->x, "body"));
02255 }
02256 if (pak->id) {
02257 ast_copy_string(insert->id, pak->id, sizeof(insert->id));
02258 }
02259 if (pak->from){
02260
02261 insert->from = ast_strdup(pak->from->full);
02262 if (!insert->from) {
02263 ast_free(insert);
02264 ast_log(LOG_ERROR, "Memory allocation failure\n");
02265 return;
02266 }
02267 ast_debug(3, "message comes from %s\n", insert->from);
02268 }
02269
02270
02271
02272 deleted = delete_old_messages(client, pak->from->partial);
02273 ast_debug(3, "Deleted %d messages for client %s from JID %s\n", deleted, client->name, pak->from->partial);
02274 AST_LIST_LOCK(&client->messages);
02275 AST_LIST_INSERT_HEAD(&client->messages, insert, list);
02276 AST_LIST_UNLOCK(&client->messages);
02277 }
02278
02279
02280
02281
02282
02283
02284
02285 static void aji_handle_presence(struct aji_client *client, ikspak *pak)
02286 {
02287 int status, priority;
02288 struct aji_buddy *buddy;
02289 struct aji_resource *tmp = NULL, *last = NULL, *found = NULL;
02290 char *ver, *node, *descrip, *type;
02291
02292 if (client->state != AJI_CONNECTED)
02293 aji_create_buddy(pak->from->partial, client);
02294
02295 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
02296 if (!buddy && pak->from->partial) {
02297
02298 if (!strcmp((const char *)pak->from->partial, (const char *)client->jid->partial))
02299 aji_create_buddy(pak->from->partial, client);
02300 else
02301 ast_log(LOG_NOTICE, "Got presence packet from %s, someone not in our roster!!!!\n", pak->from->partial);
02302 return;
02303 }
02304 type = iks_find_attrib(pak->x, "type");
02305 if (client->component && type &&!strcasecmp("probe", type)) {
02306 aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), client->status, client->statusmessage);
02307 ast_verbose("what i was looking for \n");
02308 }
02309 ASTOBJ_WRLOCK(buddy);
02310 status = (pak->show) ? pak->show : 6;
02311 priority = atoi((iks_find_cdata(pak->x, "priority")) ? iks_find_cdata(pak->x, "priority") : "0");
02312 tmp = buddy->resources;
02313 descrip = ast_strdup(iks_find_cdata(pak->x, "status"));
02314
02315 while (tmp && pak->from->resource) {
02316 if (!strcasecmp(tmp->resource, pak->from->resource)) {
02317 tmp->status = status;
02318 if (tmp->description) {
02319 ast_free(tmp->description);
02320 }
02321 tmp->description = descrip;
02322 found = tmp;
02323 if (status == 6) {
02324 if (last && found->next) {
02325 last->next = found->next;
02326 } else if (!last) {
02327 if (found->next) {
02328 buddy->resources = found->next;
02329 } else {
02330 buddy->resources = NULL;
02331 }
02332 } else if (!found->next) {
02333 if (last) {
02334 last->next = NULL;
02335 } else {
02336 buddy->resources = NULL;
02337 }
02338 }
02339 ast_free(found);
02340 found = NULL;
02341 break;
02342 }
02343
02344 if (tmp->priority != priority) {
02345 found->priority = priority;
02346 if (!last && !found->next) {
02347
02348
02349 break;
02350 }
02351
02352
02353 if (last) {
02354 last->next = found->next;
02355 } else {
02356 buddy->resources = found->next;
02357 }
02358
02359 last = NULL;
02360 tmp = buddy->resources;
02361 if (!buddy->resources) {
02362 buddy->resources = found;
02363 }
02364
02365 while (tmp) {
02366
02367
02368 if (found->priority > tmp->priority) {
02369 if (last) {
02370
02371 last->next = found;
02372 }
02373 found->next = tmp;
02374 if (!last) {
02375
02376 buddy->resources = found;
02377 }
02378 break;
02379 }
02380 if (!tmp->next) {
02381
02382 tmp->next = found;
02383 found->next = NULL;
02384 break;
02385 }
02386 last = tmp;
02387 tmp = tmp->next;
02388 }
02389 }
02390 break;
02391 }
02392 last = tmp;
02393 tmp = tmp->next;
02394 }
02395
02396
02397 if (!found && status != 6 && pak->from->resource) {
02398 found = ast_calloc(1, sizeof(*found));
02399
02400 if (!found) {
02401 ast_log(LOG_ERROR, "Out of memory!\n");
02402 ASTOBJ_UNLOCK(buddy);
02403 ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
02404 return;
02405 }
02406 ast_copy_string(found->resource, pak->from->resource, sizeof(found->resource));
02407 found->status = status;
02408 found->description = descrip;
02409 found->priority = priority;
02410 found->next = NULL;
02411 last = NULL;
02412 tmp = buddy->resources;
02413 while (tmp) {
02414 if (found->priority > tmp->priority) {
02415 if (last) {
02416 last->next = found;
02417 }
02418 found->next = tmp;
02419 if (!last) {
02420 buddy->resources = found;
02421 }
02422 break;
02423 }
02424 if (!tmp->next) {
02425 tmp->next = found;
02426 break;
02427 }
02428 last = tmp;
02429 tmp = tmp->next;
02430 }
02431 if (!tmp) {
02432 buddy->resources = found;
02433 }
02434 }
02435
02436 ASTOBJ_UNLOCK(buddy);
02437 ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
02438
02439 node = iks_find_attrib(iks_find(pak->x, "c"), "node");
02440 ver = iks_find_attrib(iks_find(pak->x, "c"), "ver");
02441
02442
02443 if (!node && !ver) {
02444 node = iks_find_attrib(iks_find(pak->x, "caps:c"), "node");
02445 ver = iks_find_attrib(iks_find(pak->x, "caps:c"), "ver");
02446 }
02447
02448
02449 if (status != 6 && found && !found->cap) {
02450 found->cap = aji_find_version(node, ver, pak);
02451 if (gtalk_yuck(pak->x)) {
02452 found->cap->jingle = 1;
02453 }
02454 if (found->cap->jingle) {
02455 ast_debug(1, "Special case for google till they support discover.\n");
02456 } else {
02457 iks *iq, *query;
02458 iq = iks_new("iq");
02459 query = iks_new("query");
02460 if (query && iq) {
02461 iks_insert_attrib(iq, "type", "get");
02462 iks_insert_attrib(iq, "to", pak->from->full);
02463 iks_insert_attrib(iq, "from", client->jid->full);
02464 iks_insert_attrib(iq, "id", client->mid);
02465 ast_aji_increment_mid(client->mid);
02466 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
02467 iks_insert_node(iq, query);
02468 ast_aji_send(client, iq);
02469 } else {
02470 ast_log(LOG_ERROR, "Out of memory.\n");
02471 }
02472 iks_delete(query);
02473 iks_delete(iq);
02474 }
02475 }
02476 switch (pak->subtype) {
02477 case IKS_TYPE_AVAILABLE:
02478 ast_debug(3, "JABBER: I am available ^_* %i\n", pak->subtype);
02479 break;
02480 case IKS_TYPE_UNAVAILABLE:
02481 ast_debug(3, "JABBER: I am unavailable ^_* %i\n", pak->subtype);
02482 break;
02483 default:
02484 ast_debug(3, "JABBER: Ohh sexy and the wrong type: %i\n", pak->subtype);
02485 }
02486 switch (pak->show) {
02487 case IKS_SHOW_UNAVAILABLE:
02488 ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
02489 break;
02490 case IKS_SHOW_AVAILABLE:
02491 ast_debug(3, "JABBER: type is available\n");
02492 break;
02493 case IKS_SHOW_CHAT:
02494 ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
02495 break;
02496 case IKS_SHOW_AWAY:
02497 ast_debug(3, "JABBER: type is away\n");
02498 break;
02499 case IKS_SHOW_XA:
02500 ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
02501 break;
02502 case IKS_SHOW_DND:
02503 ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
02504 break;
02505 default:
02506 ast_debug(3, "JABBER: Kinky! how did that happen %i\n", pak->show);
02507 }
02508
02509 if (found) {
02510 manager_event(EVENT_FLAG_USER, "JabberStatus",
02511 "Account: %s\r\nJID: %s\r\nResource: %s\r\nStatus: %d\r\nPriority: %d"
02512 "\r\nDescription: %s\r\n",
02513 client->name, pak->from->partial, found->resource, found->status,
02514 found->priority, S_OR(found->description, ""));
02515 } else {
02516 manager_event(EVENT_FLAG_USER, "JabberStatus",
02517 "Account: %s\r\nJID: %s\r\nStatus: %d\r\n",
02518 client->name, pak->from->partial, pak->show ? pak->show : IKS_SHOW_UNAVAILABLE);
02519 }
02520 }
02521
02522
02523
02524
02525
02526
02527
02528
02529 static void aji_handle_subscribe(struct aji_client *client, ikspak *pak)
02530 {
02531 iks *presence = NULL, *status = NULL;
02532 struct aji_buddy* buddy = NULL;
02533
02534 switch (pak->subtype) {
02535 case IKS_TYPE_SUBSCRIBE:
02536 if (ast_test_flag(&client->flags, AJI_AUTOACCEPT)) {
02537 presence = iks_new("presence");
02538 status = iks_new("status");
02539 if (presence && status) {
02540 iks_insert_attrib(presence, "type", "subscribed");
02541 iks_insert_attrib(presence, "to", pak->from->full);
02542 iks_insert_attrib(presence, "from", client->jid->full);
02543 if (pak->id)
02544 iks_insert_attrib(presence, "id", pak->id);
02545 iks_insert_cdata(status, "Asterisk has approved subscription", 0);
02546 iks_insert_node(presence, status);
02547 ast_aji_send(client, presence);
02548 } else {
02549 ast_log(LOG_ERROR, "Unable to allocate nodes\n");
02550 }
02551
02552 iks_delete(presence);
02553 iks_delete(status);
02554 }
02555
02556 if (client->component)
02557 aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), client->status, client->statusmessage);
02558 case IKS_TYPE_SUBSCRIBED:
02559 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
02560 if (!buddy && pak->from->partial) {
02561 aji_create_buddy(pak->from->partial, client);
02562 } else if (buddy) {
02563 ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
02564 }
02565 default:
02566 if (option_verbose > 4) {
02567 ast_verbose(VERBOSE_PREFIX_3 "JABBER: This is a subcription of type %i\n", pak->subtype);
02568 }
02569 }
02570 }
02571
02572
02573
02574
02575
02576
02577
02578
02579
02580 int ast_aji_send_chat(struct aji_client *client, const char *address, const char *message)
02581 {
02582 return aji_send_raw_chat(client, 0, NULL, address, message);
02583 }
02584
02585
02586
02587
02588
02589
02590
02591
02592
02593
02594 int ast_aji_send_groupchat(struct aji_client *client, const char *nick, const char *address, const char *message) {
02595 return aji_send_raw_chat(client, 1, nick, address, message);
02596 }
02597
02598
02599
02600
02601
02602
02603
02604
02605
02606
02607 static int aji_send_raw_chat(struct aji_client *client, int groupchat, const char *nick, const char *address, const char *message)
02608 {
02609 int res = 0;
02610 iks *message_packet = NULL;
02611 char from[AJI_MAX_JIDLEN];
02612
02613 if (nick && client->component) {
02614 snprintf(from, AJI_MAX_JIDLEN, "%s@%s/%s", nick, client->jid->full, nick);
02615 } else {
02616 snprintf(from, AJI_MAX_JIDLEN, "%s", client->jid->full);
02617 }
02618
02619 if (client->state != AJI_CONNECTED) {
02620 ast_log(LOG_WARNING, "JABBER: Not connected can't send\n");
02621 return -1;
02622 }
02623
02624 message_packet = iks_make_msg(groupchat ? IKS_TYPE_GROUPCHAT : IKS_TYPE_CHAT, address, message);
02625 if (!message_packet) {
02626 ast_log(LOG_ERROR, "Out of memory.\n");
02627 return -1;
02628 }
02629 iks_insert_attrib(message_packet, "from", from);
02630 res = ast_aji_send(client, message_packet);
02631 iks_delete(message_packet);
02632
02633 return res;
02634 }
02635
02636
02637
02638
02639
02640
02641
02642
02643
02644 int ast_aji_create_chat(struct aji_client *client, char *room, char *server, char *topic)
02645 {
02646 int res = 0;
02647 iks *iq = NULL;
02648 iq = iks_new("iq");
02649
02650 if (iq && client) {
02651 iks_insert_attrib(iq, "type", "get");
02652 iks_insert_attrib(iq, "to", server);
02653 iks_insert_attrib(iq, "id", client->mid);
02654 ast_aji_increment_mid(client->mid);
02655 ast_aji_send(client, iq);
02656 } else {
02657 ast_log(LOG_ERROR, "Out of memory.\n");
02658 }
02659
02660 iks_delete(iq);
02661
02662 return res;
02663 }
02664
02665
02666
02667
02668
02669
02670
02671
02672 int ast_aji_join_chat(struct aji_client *client, char *room, char *nick)
02673 {
02674 return aji_set_group_presence(client, room, IKS_SHOW_AVAILABLE, nick, NULL);
02675 }
02676
02677
02678
02679
02680
02681
02682
02683
02684 int ast_aji_leave_chat(struct aji_client *client, char *room, char *nick)
02685 {
02686 return aji_set_group_presence(client, room, IKS_SHOW_UNAVAILABLE, nick, NULL);
02687 }
02688
02689
02690
02691
02692
02693
02694
02695
02696 int ast_aji_invite_chat(struct aji_client *client, char *user, char *room, char *message)
02697 {
02698 int res = 0;
02699 iks *invite, *body, *namespace;
02700
02701 invite = iks_new("message");
02702 body = iks_new("body");
02703 namespace = iks_new("x");
02704 if (client && invite && body && namespace) {
02705 iks_insert_attrib(invite, "to", user);
02706 iks_insert_attrib(invite, "id", client->mid);
02707 ast_aji_increment_mid(client->mid);
02708 iks_insert_cdata(body, message, 0);
02709 iks_insert_attrib(namespace, "xmlns", "jabber:x:conference");
02710 iks_insert_attrib(namespace, "jid", room);
02711 iks_insert_node(invite, body);
02712 iks_insert_node(invite, namespace);
02713 res = ast_aji_send(client, invite);
02714 } else {
02715 ast_log(LOG_ERROR, "Out of memory.\n");
02716 }
02717
02718 iks_delete(body);
02719 iks_delete(namespace);
02720 iks_delete(invite);
02721
02722 return res;
02723 }
02724
02725
02726
02727
02728
02729
02730
02731 static void *aji_recv_loop(void *data)
02732 {
02733 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
02734 int res = IKS_HOOK;
02735
02736 while (res != IKS_OK) {
02737 ast_debug(3, "JABBER: Connecting.\n");
02738 res = aji_reconnect(client);
02739 sleep(4);
02740 }
02741
02742 do {
02743 if (res == IKS_NET_RWERR || client->timeout == 0) {
02744 while (res != IKS_OK) {
02745 ast_debug(3, "JABBER: reconnecting.\n");
02746 res = aji_reconnect(client);
02747 sleep(4);
02748 }
02749 }
02750
02751 res = aji_recv(client, 1);
02752
02753 if (client->state == AJI_DISCONNECTING) {
02754 ast_debug(2, "Ending our Jabber client's thread due to a disconnect\n");
02755 pthread_exit(NULL);
02756 }
02757
02758
02759
02760 if (res == IKS_NET_EXPIRED) {
02761 client->timeout--;
02762 delete_old_messages_all(client);
02763 }
02764 if (res == IKS_HOOK) {
02765 ast_log(LOG_WARNING, "JABBER: Got hook event.\n");
02766 } else if (res == IKS_NET_TLSFAIL) {
02767 ast_log(LOG_ERROR, "JABBER: Failure in TLS.\n");
02768 } else if (client->timeout == 0 && client->state == AJI_CONNECTED) {
02769 res = client->keepalive ? aji_send_raw(client, " ") : IKS_OK;
02770 if (res == IKS_OK) {
02771 client->timeout = 50;
02772 } else {
02773 ast_log(LOG_WARNING, "JABBER: Network Timeout\n");
02774 }
02775 } else if (res == IKS_NET_RWERR) {
02776 ast_log(LOG_WARNING, "JABBER: socket read error\n");
02777 }
02778 } while (client);
02779 ASTOBJ_UNREF(client, ast_aji_client_destroy);
02780 return 0;
02781 }
02782
02783
02784
02785
02786
02787
02788 void ast_aji_increment_mid(char *mid)
02789 {
02790 int i = 0;
02791
02792 for (i = strlen(mid) - 1; i >= 0; i--) {
02793 if (mid[i] != 'z') {
02794 mid[i] = mid[i] + 1;
02795 i = 0;
02796 } else
02797 mid[i] = 'a';
02798 }
02799 }
02800
02801 #if 0
02802
02803
02804
02805
02806
02807
02808 static int aji_register_transport(void *data, ikspak *pak)
02809 {
02810 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
02811 int res = 0;
02812 struct aji_buddy *buddy = NULL;
02813 iks *send = iks_make_iq(IKS_TYPE_GET, "jabber:iq:register");
02814
02815 if (client && send) {
02816 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02817 ASTOBJ_RDLOCK(iterator);
02818 if (iterator->btype == AJI_TRANS) {
02819 buddy = iterator;
02820 }
02821 ASTOBJ_UNLOCK(iterator);
02822 });
02823 iks_filter_remove_hook(client->f, aji_register_transport);
02824 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);
02825 iks_insert_attrib(send, "to", buddy->host);
02826 iks_insert_attrib(send, "id", client->mid);
02827 ast_aji_increment_mid(client->mid);
02828 iks_insert_attrib(send, "from", client->user);
02829 res = ast_aji_send(client, send);
02830 } else
02831 ast_log(LOG_ERROR, "Out of memory.\n");
02832
02833 if (send)
02834 iks_delete(send);
02835 ASTOBJ_UNREF(client, ast_aji_client_destroy);
02836 return IKS_FILTER_EAT;
02837
02838 }
02839
02840
02841
02842
02843
02844
02845 static int aji_register_transport2(void *data, ikspak *pak)
02846 {
02847 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
02848 int res = 0;
02849 struct aji_buddy *buddy = NULL;
02850
02851 iks *regiq = iks_new("iq");
02852 iks *regquery = iks_new("query");
02853 iks *reguser = iks_new("username");
02854 iks *regpass = iks_new("password");
02855
02856 if (client && regquery && reguser && regpass && regiq) {
02857 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02858 ASTOBJ_RDLOCK(iterator);
02859 if (iterator->btype == AJI_TRANS)
02860 buddy = iterator; ASTOBJ_UNLOCK(iterator);
02861 });
02862 iks_filter_remove_hook(client->f, aji_register_transport2);
02863 iks_insert_attrib(regiq, "to", buddy->host);
02864 iks_insert_attrib(regiq, "type", "set");
02865 iks_insert_attrib(regiq, "id", client->mid);
02866 ast_aji_increment_mid(client->mid);
02867 iks_insert_attrib(regiq, "from", client->user);
02868 iks_insert_attrib(regquery, "xmlns", "jabber:iq:register");
02869 iks_insert_cdata(reguser, buddy->user, 0);
02870 iks_insert_cdata(regpass, buddy->pass, 0);
02871 iks_insert_node(regiq, regquery);
02872 iks_insert_node(regquery, reguser);
02873 iks_insert_node(regquery, regpass);
02874 res = ast_aji_send(client, regiq);
02875 } else
02876 ast_log(LOG_ERROR, "Out of memory.\n");
02877 if (regiq)
02878 iks_delete(regiq);
02879 if (regquery)
02880 iks_delete(regquery);
02881 if (reguser)
02882 iks_delete(reguser);
02883 if (regpass)
02884 iks_delete(regpass);
02885 ASTOBJ_UNREF(client, ast_aji_client_destroy);
02886 return IKS_FILTER_EAT;
02887 }
02888 #endif
02889
02890
02891
02892
02893
02894
02895
02896
02897 static void aji_pruneregister(struct aji_client *client)
02898 {
02899 iks *removeiq = iks_new("iq");
02900 iks *removequery = iks_new("query");
02901 iks *removeitem = iks_new("item");
02902 iks *send = iks_make_iq(IKS_TYPE_GET, "http://jabber.org/protocol/disco#items");
02903 if (!client || !removeiq || !removequery || !removeitem || !send) {
02904 ast_log(LOG_ERROR, "Out of memory.\n");
02905 goto safeout;
02906 }
02907
02908 iks_insert_node(removeiq, removequery);
02909 iks_insert_node(removequery, removeitem);
02910 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02911 ASTOBJ_RDLOCK(iterator);
02912
02913
02914 if (ast_test_flag(&iterator->flags, AJI_AUTOPRUNE)) {
02915 ast_aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBE, iterator->name,
02916 "GoodBye. Your status is no longer needed by Asterisk the Open Source PBX"
02917 " so I am no longer subscribing to your presence.\n"));
02918 ast_aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBED, iterator->name,
02919 "GoodBye. You are no longer in the Asterisk config file so I am removing"
02920 " your access to my presence.\n"));
02921 iks_insert_attrib(removeiq, "from", client->jid->full);
02922 iks_insert_attrib(removeiq, "type", "set");
02923 iks_insert_attrib(removequery, "xmlns", "jabber:iq:roster");
02924 iks_insert_attrib(removeitem, "jid", iterator->name);
02925 iks_insert_attrib(removeitem, "subscription", "remove");
02926 ast_aji_send(client, removeiq);
02927 } else if (ast_test_flag(&iterator->flags, AJI_AUTOREGISTER)) {
02928 ast_aji_send(client, iks_make_s10n(IKS_TYPE_SUBSCRIBE, iterator->name,
02929 "Greetings! I am the Asterisk Open Source PBX and I want to subscribe to your presence\n"));
02930 ast_clear_flag(&iterator->flags, AJI_AUTOREGISTER);
02931 }
02932 ASTOBJ_UNLOCK(iterator);
02933 });
02934
02935 safeout:
02936 iks_delete(removeiq);
02937 iks_delete(removequery);
02938 iks_delete(removeitem);
02939 iks_delete(send);
02940
02941 ASTOBJ_CONTAINER_PRUNE_MARKED(&client->buddies, ast_aji_buddy_destroy);
02942 }
02943
02944
02945
02946
02947
02948
02949
02950
02951 static int aji_filter_roster(void *data, ikspak *pak)
02952 {
02953 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
02954 int flag = 0;
02955 iks *x = NULL;
02956 struct aji_buddy *buddy;
02957
02958 client->state = AJI_CONNECTED;
02959 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02960 ASTOBJ_RDLOCK(iterator);
02961 x = iks_child(pak->query);
02962 flag = 0;
02963 while (x) {
02964 if (!iks_strcmp(iks_name(x), "item")) {
02965 if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid"))) {
02966 flag = 1;
02967 ast_clear_flag(&iterator->flags, AJI_AUTOPRUNE | AJI_AUTOREGISTER);
02968 }
02969 }
02970 x = iks_next(x);
02971 }
02972 if (!flag) {
02973 ast_copy_flags(&iterator->flags, &client->flags, AJI_AUTOREGISTER);
02974 }
02975 iks_delete(x);
02976
02977 ASTOBJ_UNLOCK(iterator);
02978 });
02979
02980 x = iks_child(pak->query);
02981 while (x) {
02982 flag = 0;
02983 if (iks_strcmp(iks_name(x), "item") == 0) {
02984 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02985 ASTOBJ_RDLOCK(iterator);
02986 if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid")))
02987 flag = 1;
02988 ASTOBJ_UNLOCK(iterator);
02989 });
02990
02991 if (flag) {
02992
02993 x = iks_next(x);
02994 continue;
02995 }
02996
02997 buddy = ast_calloc(1, sizeof(*buddy));
02998 if (!buddy) {
02999 ast_log(LOG_WARNING, "Out of memory\n");
03000 ASTOBJ_UNREF(client, ast_aji_client_destroy);
03001 return 0;
03002 }
03003 ASTOBJ_INIT(buddy);
03004 ASTOBJ_WRLOCK(buddy);
03005 ast_copy_string(buddy->name, iks_find_attrib(x, "jid"), sizeof(buddy->name));
03006 ast_clear_flag(&buddy->flags, AST_FLAGS_ALL);
03007 if (ast_test_flag(&client->flags, AJI_AUTOPRUNE)) {
03008 ast_set_flag(&buddy->flags, AJI_AUTOPRUNE);
03009 ASTOBJ_MARK(buddy);
03010 } else if (ast_test_flag(&client->flags, AJI_AUTOREGISTER)) {
03011 if (!iks_strcmp(iks_find_attrib(x, "subscription"), "none") || !iks_strcmp(iks_find_attrib(x, "subscription"), "from")) {
03012
03013
03014 ast_set_flag(&buddy->flags, AJI_AUTOREGISTER);
03015 }
03016 }
03017 ASTOBJ_UNLOCK(buddy);
03018 if (buddy) {
03019 ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
03020 ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
03021 }
03022 }
03023 x = iks_next(x);
03024 }
03025
03026 iks_delete(x);
03027 aji_pruneregister(client);
03028
03029 ASTOBJ_UNREF(client, ast_aji_client_destroy);
03030 return IKS_FILTER_EAT;
03031 }
03032
03033
03034
03035
03036
03037
03038
03039 static int aji_reconnect(struct aji_client *client)
03040 {
03041 int res = 0;
03042
03043 if (client->state) {
03044 client->state = AJI_DISCONNECTED;
03045 }
03046 client->timeout = 50;
03047 if (client->p) {
03048 iks_parser_reset(client->p);
03049 }
03050 if (client->authorized) {
03051 client->authorized = 0;
03052 }
03053
03054 res = aji_initialize(client);
03055
03056 return res;
03057 }
03058
03059
03060
03061
03062
03063
03064
03065 static int aji_get_roster(struct aji_client *client)
03066 {
03067 iks *roster = NULL;
03068 roster = iks_make_iq(IKS_TYPE_GET, IKS_NS_ROSTER);
03069
03070 if (roster) {
03071 iks_insert_attrib(roster, "id", "roster");
03072 aji_set_presence(client, NULL, client->jid->full, client->status, client->statusmessage);
03073 ast_aji_send(client, roster);
03074 }
03075
03076 iks_delete(roster);
03077
03078 return 1;
03079 }
03080
03081
03082
03083
03084
03085
03086
03087
03088 static int aji_client_connect(void *data, ikspak *pak)
03089 {
03090 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
03091 int res = IKS_FILTER_PASS;
03092
03093 if (client) {
03094 if (client->state == AJI_DISCONNECTED) {
03095 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);
03096 client->state = AJI_CONNECTING;
03097 client->jid = (iks_find_cdata(pak->query, "jid")) ? iks_id_new(client->stack, iks_find_cdata(pak->query, "jid")) : client->jid;
03098 if (!client->component) {
03099 aji_get_roster(client);
03100 }
03101 if (client->distribute_events) {
03102 aji_init_event_distribution(client);
03103 }
03104
03105 iks_filter_remove_hook(client->f, aji_client_connect);
03106
03107 res = IKS_FILTER_EAT;
03108 }
03109 } else {
03110 ast_log(LOG_ERROR, "Out of memory.\n");
03111 }
03112
03113 ASTOBJ_UNREF(client, ast_aji_client_destroy);
03114 return res;
03115 }
03116
03117
03118
03119
03120
03121
03122
03123 static int aji_initialize(struct aji_client *client)
03124 {
03125 int connected = IKS_NET_NOCONN;
03126
03127 #ifdef HAVE_OPENSSL
03128
03129 client->stream_flags = 0;
03130 #endif
03131
03132 connected = iks_connect_via(client->p, S_OR(client->serverhost, client->jid->server), client->port, client->component ? client->user : client->jid->server);
03133
03134 if (connected == IKS_NET_NOCONN) {
03135 ast_log(LOG_ERROR, "JABBER ERROR: No Connection\n");
03136 return IKS_HOOK;
03137 } else if (connected == IKS_NET_NODNS) {
03138 ast_log(LOG_ERROR, "JABBER ERROR: No DNS %s for client to %s\n", client->name,
03139 S_OR(client->serverhost, client->jid->server));
03140 return IKS_HOOK;
03141 }
03142
03143 return IKS_OK;
03144 }
03145
03146
03147
03148
03149
03150
03151 int ast_aji_disconnect(struct aji_client *client)
03152 {
03153 if (client) {
03154 ast_verb(4, "JABBER: Disconnecting\n");
03155 #ifdef HAVE_OPENSSL
03156 if (client->stream_flags & SECURE) {
03157 SSL_shutdown(client->ssl_session);
03158 SSL_CTX_free(client->ssl_context);
03159 SSL_free(client->ssl_session);
03160 }
03161 #endif
03162 iks_disconnect(client->p);
03163 iks_parser_delete(client->p);
03164 ASTOBJ_UNREF(client, ast_aji_client_destroy);
03165 }
03166
03167 return 1;
03168 }
03169
03170
03171
03172
03173
03174
03175
03176 static void aji_mwi_cb(const struct ast_event *ast_event, void *data)
03177 {
03178 const char *mailbox;
03179 const char *context;
03180 char oldmsgs[10];
03181 char newmsgs[10];
03182 struct aji_client *client;
03183 if (ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(ast_event, AST_EVENT_IE_EID)))
03184 {
03185
03186 ast_log(LOG_DEBUG, "Returning here\n");
03187 return;
03188 }
03189
03190 client = ASTOBJ_REF((struct aji_client *) data);
03191 mailbox = ast_event_get_ie_str(ast_event, AST_EVENT_IE_MAILBOX);
03192 context = ast_event_get_ie_str(ast_event, AST_EVENT_IE_CONTEXT);
03193 snprintf(oldmsgs, sizeof(oldmsgs), "%d",
03194 ast_event_get_ie_uint(ast_event, AST_EVENT_IE_OLDMSGS));
03195 snprintf(newmsgs, sizeof(newmsgs), "%d",
03196 ast_event_get_ie_uint(ast_event, AST_EVENT_IE_NEWMSGS));
03197 aji_publish_mwi(client, mailbox, context, oldmsgs, newmsgs);
03198 ASTOBJ_UNREF(client, ast_aji_client_destroy);
03199
03200 }
03201
03202
03203
03204
03205
03206
03207 static void aji_devstate_cb(const struct ast_event *ast_event, void *data)
03208 {
03209 const char *device;
03210 const char *device_state;
03211 struct aji_client *client;
03212 if (ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(ast_event, AST_EVENT_IE_EID)))
03213 {
03214
03215 ast_log(LOG_DEBUG, "Returning here\n");
03216 return;
03217 }
03218
03219 client = ASTOBJ_REF((struct aji_client *) data);
03220 device = ast_event_get_ie_str(ast_event, AST_EVENT_IE_DEVICE);
03221 device_state = ast_devstate_str(ast_event_get_ie_uint(ast_event, AST_EVENT_IE_STATE));
03222 aji_publish_device_state(client, device, device_state);
03223 ASTOBJ_UNREF(client, ast_aji_client_destroy);
03224 }
03225
03226
03227
03228
03229
03230
03231 static void aji_init_event_distribution(struct aji_client *client)
03232 {
03233 if (!mwi_sub) {
03234 mwi_sub = ast_event_subscribe(AST_EVENT_MWI, aji_mwi_cb, "aji_mwi_subscription",
03235 client, AST_EVENT_IE_END);
03236 }
03237 if (!device_state_sub) {
03238 if (ast_enable_distributed_devstate()) {
03239 return;
03240 }
03241 device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE_CHANGE,
03242 aji_devstate_cb, "aji_devstate_subscription", client, AST_EVENT_IE_END);
03243 ast_event_dump_cache(device_state_sub);
03244 }
03245
03246 aji_pubsub_subscribe(client, "device_state");
03247 aji_pubsub_subscribe(client, "message_waiting");
03248 iks_filter_add_rule(client->f, aji_handle_pubsub_event, client, IKS_RULE_TYPE,
03249 IKS_PAK_MESSAGE, IKS_RULE_FROM, client->pubsub_node, IKS_RULE_DONE);
03250 iks_filter_add_rule(client->f, aji_handle_pubsub_error, client, IKS_RULE_TYPE,
03251 IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_ERROR, IKS_RULE_DONE);
03252
03253 }
03254
03255
03256
03257
03258
03259
03260 static int aji_handle_pubsub_event(void *data, ikspak *pak)
03261 {
03262 char *item_id, *device_state, *context;
03263 int oldmsgs, newmsgs;
03264 iks *item, *item_content;
03265 struct ast_eid pubsub_eid;
03266 struct ast_event *event;
03267 item = iks_find(iks_find(iks_find(pak->x, "event"), "items"), "item");
03268 if (!item) {
03269 ast_log(LOG_ERROR, "Could not parse incoming PubSub event\n");
03270 return IKS_FILTER_EAT;
03271 }
03272 item_id = iks_find_attrib(item, "id");
03273 item_content = iks_child(item);
03274 ast_str_to_eid(&pubsub_eid, iks_find_attrib(item_content, "eid"));
03275 if (!ast_eid_cmp(&ast_eid_default, &pubsub_eid)) {
03276 ast_log(LOG_DEBUG, "Returning here, eid of incoming event matches ours!\n");
03277 return IKS_FILTER_EAT;
03278 }
03279 if (!strcasecmp(iks_name(item_content), "state")) {
03280 device_state = iks_find_cdata(item, "state");
03281 if (!(event = ast_event_new(AST_EVENT_DEVICE_STATE_CHANGE,
03282 AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, item_id, AST_EVENT_IE_STATE,
03283 AST_EVENT_IE_PLTYPE_UINT, ast_devstate_val(device_state), AST_EVENT_IE_EID,
03284 AST_EVENT_IE_PLTYPE_RAW, &pubsub_eid, sizeof(pubsub_eid),
03285 AST_EVENT_IE_END))) {
03286 return IKS_FILTER_EAT;
03287 }
03288 } else if (!strcasecmp(iks_name(item_content), "mailbox")) {
03289 context = strsep(&item_id, "@");
03290 sscanf(iks_find_cdata(item_content, "OLDMSGS"), "%10d", &oldmsgs);
03291 sscanf(iks_find_cdata(item_content, "NEWMSGS"), "%10d", &newmsgs);
03292 if (!(event = ast_event_new(AST_EVENT_MWI, AST_EVENT_IE_MAILBOX,
03293 AST_EVENT_IE_PLTYPE_STR, item_id, AST_EVENT_IE_CONTEXT,
03294 AST_EVENT_IE_PLTYPE_STR, context, AST_EVENT_IE_OLDMSGS,
03295 AST_EVENT_IE_PLTYPE_UINT, oldmsgs, AST_EVENT_IE_NEWMSGS,
03296 AST_EVENT_IE_PLTYPE_UINT, newmsgs, AST_EVENT_IE_EID, AST_EVENT_IE_PLTYPE_RAW,
03297 &pubsub_eid, sizeof(pubsub_eid), AST_EVENT_IE_END))) {
03298 return IKS_FILTER_EAT;
03299 }
03300 } else {
03301 ast_log(LOG_DEBUG, "Don't know how to handle PubSub event of type %s\n",
03302 iks_name(item_content));
03303 return IKS_FILTER_EAT;
03304 }
03305 ast_event_queue_and_cache(event);
03306 return IKS_FILTER_EAT;
03307 }
03308
03309
03310
03311
03312
03313
03314
03315 static void aji_create_affiliations(struct aji_client *client, const char *node)
03316 {
03317 iks *modify_affiliates = aji_pubsub_iq_create(client, "set");
03318 iks *pubsub, *affiliations, *affiliate;
03319 pubsub = iks_insert(modify_affiliates, "pubsub");
03320 iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub#owner");
03321 affiliations = iks_insert(pubsub, "affiliations");
03322 iks_insert_attrib(affiliations, "node", node);
03323 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
03324 ASTOBJ_RDLOCK(iterator);
03325 affiliate = iks_insert(affiliations, "affiliation");
03326 iks_insert_attrib(affiliate, "jid", iterator->name);
03327 iks_insert_attrib(affiliate, "affiliation", "owner");
03328 ASTOBJ_UNLOCK(iterator);
03329 });
03330 ast_aji_send(client, modify_affiliates);
03331 iks_delete(modify_affiliates);
03332 }
03333
03334
03335
03336
03337
03338
03339
03340 static void aji_pubsub_subscribe(struct aji_client *client, const char *node)
03341 {
03342 iks *request = aji_pubsub_iq_create(client, "set");
03343 iks *pubsub, *subscribe;
03344
03345 pubsub = iks_insert(request, "pubsub");
03346 iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
03347 subscribe = iks_insert(pubsub, "subscribe");
03348 iks_insert_attrib(subscribe, "jid", client->jid->partial);
03349 iks_insert_attrib(subscribe, "node", node);
03350 if (ast_test_flag(&globalflags, AJI_XEP0248)) {
03351 iks *options, *x, *sub_options, *sub_type, *sub_depth;
03352 options = iks_insert(pubsub, "options");
03353 x = iks_insert(options, "x");
03354 iks_insert_attrib(x, "xmlns", "jabber:x:data");
03355 iks_insert_attrib(x, "type", "submit");
03356 sub_options = iks_insert(x, "field");
03357 iks_insert_attrib(sub_options, "var", "FORM_TYPE");
03358 iks_insert_attrib(sub_options, "type", "hidden");
03359 iks_insert_cdata(iks_insert(sub_options, "value"),
03360 "http://jabber.org/protocol/pubsub#subscribe_options", 51);
03361 sub_type = iks_insert(x, "field");
03362 iks_insert_attrib(sub_type, "var", "pubsub#subscription_type");
03363 iks_insert_cdata(iks_insert(sub_type, "value"), "items", 5);
03364 sub_depth = iks_insert(x, "field");
03365 iks_insert_attrib(sub_type, "var", "pubsub#subscription_depth");
03366 iks_insert_cdata(iks_insert(sub_depth, "value"), "all", 3);
03367 }
03368 ast_aji_send(client, request);
03369 iks_delete(request);
03370 }
03371
03372
03373
03374
03375
03376
03377
03378
03379 static iks* aji_build_publish_skeleton(struct aji_client *client, const char *node,
03380 const char *event_type)
03381 {
03382 iks *request = aji_pubsub_iq_create(client, "set");
03383 iks *pubsub, *publish, *item;
03384 pubsub = iks_insert(request, "pubsub");
03385 iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
03386 publish = iks_insert(pubsub, "publish");
03387 if (ast_test_flag(&globalflags, AJI_XEP0248)) {
03388 iks_insert_attrib(publish, "node", node);
03389 } else {
03390 iks_insert_attrib(publish, "node", event_type);
03391 }
03392 item = iks_insert(publish, "item");
03393 iks_insert_attrib(item, "id", node);
03394 return item;
03395
03396 }
03397
03398
03399
03400
03401
03402
03403
03404
03405 static void aji_publish_device_state(struct aji_client *client, const char *device,
03406 const char *device_state)
03407 {
03408 iks *request = aji_build_publish_skeleton(client, device, "device_state");
03409 iks *state;
03410 char eid_str[20];
03411 if (ast_test_flag(&pubsubflags, AJI_PUBSUB_AUTOCREATE)) {
03412 if (ast_test_flag(&pubsubflags, AJI_XEP0248)) {
03413 aji_create_pubsub_node(client, "leaf", device, "device_state");
03414 } else {
03415 aji_create_pubsub_node(client, NULL, device, NULL);
03416 }
03417 }
03418 ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
03419 state = iks_insert(request, "state");
03420 iks_insert_attrib(state, "xmlns", "http://asterisk.org");
03421 iks_insert_attrib(state, "eid", eid_str);
03422 iks_insert_cdata(state, device_state, strlen(device_state));
03423 ast_aji_send(client, iks_root(request));
03424 iks_delete(request);
03425 }
03426
03427
03428
03429
03430
03431
03432
03433
03434 static void aji_publish_mwi(struct aji_client *client, const char *mailbox,
03435 const char *context, const char *oldmsgs, const char *newmsgs)
03436 {
03437 char full_mailbox[AST_MAX_EXTENSION+AST_MAX_CONTEXT];
03438 char eid_str[20];
03439 iks *mailbox_node, *request;
03440 snprintf(full_mailbox, sizeof(full_mailbox), "%s@%s", mailbox, context);
03441 request = aji_build_publish_skeleton(client, full_mailbox, "message_waiting");
03442 ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
03443 mailbox_node = iks_insert(request, "mailbox");
03444 iks_insert_attrib(mailbox_node, "xmlns", "http://asterisk.org");
03445 iks_insert_attrib(mailbox_node, "eid", eid_str);
03446 iks_insert_cdata(iks_insert(mailbox_node, "NEWMSGS"), newmsgs, strlen(newmsgs));
03447 iks_insert_cdata(iks_insert(mailbox_node, "OLDMSGS"), oldmsgs, strlen(oldmsgs));
03448 ast_aji_send(client, iks_root(request));
03449 iks_delete(request);
03450 }
03451
03452
03453
03454
03455
03456
03457
03458 static iks* aji_pubsub_iq_create(struct aji_client *client, const char *type)
03459 {
03460 iks *request = iks_new("iq");
03461
03462 iks_insert_attrib(request, "to", client->pubsub_node);
03463 iks_insert_attrib(request, "from", client->jid->full);
03464 iks_insert_attrib(request, "type", type);
03465 ast_aji_increment_mid(client->mid);
03466 iks_insert_attrib(request, "id", client->mid);
03467 return request;
03468 }
03469
03470 static int aji_handle_pubsub_error(void *data, ikspak *pak)
03471 {
03472 char *node_name;
03473 char *error;
03474 int error_num;
03475 iks *orig_request;
03476 iks *orig_pubsub = iks_find(pak->x, "pubsub");
03477 struct aji_client *client;
03478 if (!orig_pubsub) {
03479 ast_log(LOG_ERROR, "Error isn't a PubSub error, why are we here?\n");
03480 return IKS_FILTER_EAT;
03481 }
03482 orig_request = iks_child(orig_pubsub);
03483 error = iks_find_attrib(iks_find(pak->x, "error"), "code");
03484 node_name = iks_find_attrib(orig_request, "node");
03485 if (!sscanf(error, "%30d", &error_num)) {
03486 return IKS_FILTER_EAT;
03487 }
03488 if (error_num > 399 && error_num < 500 && error_num != 404) {
03489 ast_log(LOG_ERROR,
03490 "Error performing operation on PubSub node %s, %s.\n", node_name, error);
03491 return IKS_FILTER_EAT;
03492 } else if (error_num > 499 && error_num < 600) {
03493 ast_log(LOG_ERROR, "PubSub Server error, %s\n", error);
03494 return IKS_FILTER_EAT;
03495 }
03496
03497 client = ASTOBJ_REF((struct aji_client *) data);
03498
03499 if (!strcasecmp(iks_name(orig_request), "publish")) {
03500 iks *request;
03501 if (ast_test_flag(&pubsubflags, AJI_XEP0248)) {
03502 if (iks_find(iks_find(orig_request, "item"), "state")) {
03503 aji_create_pubsub_leaf(client, "device_state", node_name);
03504 } else if (iks_find(iks_find(orig_request, "item"), "mailbox")) {
03505 aji_create_pubsub_leaf(client, "message_waiting", node_name);
03506 }
03507 } else {
03508 aji_create_pubsub_node(client, NULL, node_name, NULL);
03509 }
03510 request = aji_pubsub_iq_create(client, "set");
03511 iks_insert_node(request, orig_pubsub);
03512 ast_aji_send(client, request);
03513 iks_delete(request);
03514 ASTOBJ_UNREF(client, ast_aji_client_destroy);
03515 return IKS_FILTER_EAT;
03516 } else if (!strcasecmp(iks_name(orig_request), "subscribe")) {
03517 if (ast_test_flag(&pubsubflags, AJI_XEP0248)) {
03518 aji_create_pubsub_collection(client, node_name);
03519 } else {
03520 aji_create_pubsub_node(client, NULL, node_name, NULL);
03521 }
03522 }
03523 ASTOBJ_UNREF(client, ast_aji_client_destroy);
03524 return IKS_FILTER_EAT;
03525 }
03526
03527
03528
03529
03530
03531
03532
03533 static void aji_request_pubsub_nodes(struct aji_client *client, const char *collection)
03534 {
03535 iks *request = aji_build_node_request(client, collection);
03536
03537 iks_filter_add_rule(client->f, aji_receive_node_list, client, IKS_RULE_TYPE,
03538 IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->mid,
03539 IKS_RULE_DONE);
03540 ast_aji_send(client, request);
03541 iks_delete(request);
03542
03543 }
03544
03545
03546
03547
03548
03549
03550
03551 static iks* aji_build_node_request(struct aji_client *client, const char *collection)
03552 {
03553 iks *request = aji_pubsub_iq_create(client, "get");
03554 iks *query;
03555 query = iks_insert(request, "query");
03556 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
03557 if (collection) {
03558 iks_insert_attrib(query, "node", collection);
03559 }
03560 return request;
03561 }
03562
03563
03564
03565
03566
03567
03568
03569 static int aji_receive_node_list(void *data, ikspak* pak)
03570 {
03571
03572 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
03573 iks *item = NULL;
03574 if (iks_has_children(pak->query)) {
03575 item = iks_first_tag(pak->query);
03576 ast_verbose("Connection %s: %s\nNode name: %s\n", client->name, client->jid->partial,
03577 iks_find_attrib(item, "node"));
03578 while ((item = iks_next_tag(item))) {
03579 ast_verbose("Node name: %s\n", iks_find_attrib(item, "node"));
03580 }
03581 }
03582 if (item) {
03583 iks_delete(item);
03584 }
03585 ASTOBJ_UNREF(client, ast_aji_client_destroy);
03586 return IKS_FILTER_EAT;
03587 }
03588
03589
03590
03591
03592
03593
03594
03595
03596
03597 static char *aji_cli_list_pubsub_nodes(struct ast_cli_entry *e, int cmd, struct
03598 ast_cli_args *a)
03599 {
03600 struct aji_client *client;
03601 const char *name = NULL;
03602 const char *collection = NULL;
03603
03604 switch (cmd) {
03605 case CLI_INIT:
03606 e->command = "jabber list nodes";
03607 e->usage =
03608 "Usage: jabber list nodes <connection> [collection]\n"
03609 " Lists the user's nodes on the respective connection\n"
03610 " ([connection] as configured in jabber.conf.)\n";
03611 return NULL;
03612 case CLI_GENERATE:
03613 return NULL;
03614 }
03615
03616 if (a->argc > 5 || a->argc < 4) {
03617 return CLI_SHOWUSAGE;
03618 } else if (a->argc == 4 || a->argc == 5) {
03619 name = a->argv[3];
03620 }
03621 if (a->argc == 5) {
03622 collection = a->argv[4];
03623 }
03624 if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
03625 ast_cli(a->fd, "Unable to find client '%s'!\n", name);
03626 return CLI_FAILURE;
03627 }
03628
03629 ast_cli(a->fd, "Listing pubsub nodes.\n");
03630 aji_request_pubsub_nodes(client, collection);
03631 ASTOBJ_UNREF(client, ast_aji_client_destroy);
03632 return CLI_SUCCESS;
03633 }
03634
03635
03636
03637
03638
03639
03640
03641
03642 static char *aji_cli_purge_pubsub_nodes(struct ast_cli_entry *e, int cmd, struct
03643 ast_cli_args *a)
03644 {
03645 struct aji_client *client;
03646 const char *name;
03647
03648 switch (cmd) {
03649 case CLI_INIT:
03650 e->command = "jabber purge nodes";
03651 e->usage =
03652 "Usage: jabber purge nodes <connection> <node>\n"
03653 " Purges nodes on PubSub server\n"
03654 " as configured in jabber.conf.\n";
03655 return NULL;
03656 case CLI_GENERATE:
03657 return NULL;
03658 }
03659
03660 if (a->argc != 5) {
03661 return CLI_SHOWUSAGE;
03662 }
03663 name = a->argv[3];
03664
03665 if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
03666 ast_cli(a->fd, "Unable to find client '%s'!\n", name);
03667 return CLI_FAILURE;
03668 }
03669 if (ast_test_flag(&pubsubflags, AJI_XEP0248)) {
03670 aji_pubsub_purge_nodes(client, a->argv[4]);
03671 } else {
03672 aji_delete_pubsub_node(client, a->argv[4]);
03673 }
03674 ASTOBJ_UNREF(client, ast_aji_client_destroy);
03675 return CLI_SUCCESS;
03676 }
03677
03678 static void aji_pubsub_purge_nodes(struct aji_client *client, const char* collection_name)
03679 {
03680 iks *request = aji_build_node_request(client, collection_name);
03681 ast_aji_send(client, request);
03682 iks_filter_add_rule(client->f, aji_delete_node_list, client, IKS_RULE_TYPE,
03683 IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->mid,
03684 IKS_RULE_DONE);
03685 ast_aji_send(client, request);
03686 iks_delete(request);
03687 }
03688
03689
03690
03691
03692
03693
03694
03695 static int aji_delete_node_list(void *data, ikspak* pak)
03696 {
03697
03698 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
03699 iks *item = NULL;
03700 if (iks_has_children(pak->query)) {
03701 item = iks_first_tag(pak->query);
03702 ast_log(LOG_WARNING, "Connection: %s Node name: %s\n", client->jid->partial,
03703 iks_find_attrib(item, "node"));
03704 while ((item = iks_next_tag(item))) {
03705 aji_delete_pubsub_node(client, iks_find_attrib(item, "node"));
03706 }
03707 }
03708 if (item) {
03709 iks_delete(item);
03710 }
03711 return IKS_FILTER_EAT;
03712 }
03713
03714
03715
03716
03717
03718
03719
03720
03721
03722 static char *aji_cli_delete_pubsub_node(struct ast_cli_entry *e, int cmd, struct
03723 ast_cli_args *a)
03724 {
03725 struct aji_client *client;
03726 const char *name;
03727
03728 switch (cmd) {
03729 case CLI_INIT:
03730 e->command = "jabber delete node";
03731 e->usage =
03732 "Usage: jabber delete node <connection> <node>\n"
03733 " Deletes a node on PubSub server\n"
03734 " as configured in jabber.conf.\n";
03735 return NULL;
03736 case CLI_GENERATE:
03737 return NULL;
03738 }
03739
03740 if (a->argc != 5) {
03741 return CLI_SHOWUSAGE;
03742 }
03743 name = a->argv[3];
03744
03745 if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
03746 ast_cli(a->fd, "Unable to find client '%s'!\n", name);
03747 return CLI_FAILURE;
03748 }
03749 aji_delete_pubsub_node(client, a->argv[4]);
03750 ASTOBJ_UNREF(client, ast_aji_client_destroy);
03751 return CLI_SUCCESS;
03752 }
03753
03754
03755
03756
03757
03758
03759
03760 static void aji_delete_pubsub_node(struct aji_client *client, const char *node_name)
03761 {
03762 iks *request = aji_pubsub_iq_create(client, "set");
03763 iks *pubsub, *delete;
03764 pubsub = iks_insert(request, "pubsub");
03765 iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub#owner");
03766 delete = iks_insert(pubsub, "delete");
03767 iks_insert_attrib(delete, "node", node_name);
03768 ast_aji_send(client, request);
03769 }
03770
03771
03772
03773
03774
03775
03776
03777 static void aji_create_pubsub_collection(struct aji_client *client, const char
03778 *collection_name)
03779 {
03780 aji_create_pubsub_node(client, "collection", collection_name, NULL);
03781 }
03782
03783
03784
03785
03786
03787
03788
03789
03790 static void aji_create_pubsub_leaf(struct aji_client *client, const char *collection_name,
03791 const char *leaf_name)
03792 {
03793 aji_create_pubsub_node(client, "leaf", leaf_name, collection_name);
03794 }
03795
03796
03797
03798
03799
03800
03801
03802
03803 static iks* aji_create_pubsub_node(struct aji_client *client, const char *node_type, const
03804 char *name, const char *collection_name)
03805 {
03806 iks *node = aji_pubsub_iq_create(client, "set");
03807 iks *pubsub, *create;
03808 pubsub = iks_insert(node, "pubsub");
03809 iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
03810 create = iks_insert(pubsub, "create");
03811 iks_insert_attrib(create, "node", name);
03812 aji_build_node_config(pubsub, node_type, collection_name);
03813 ast_aji_send(client, node);
03814 aji_create_affiliations(client, name);
03815 iks_delete(node);
03816 return 0;
03817 }
03818
03819
03820
03821 static iks* aji_build_node_config(iks *pubsub, const char *node_type, const char *collection_name)
03822 {
03823 iks *configure, *x, *field_owner, *field_node_type, *field_node_config,
03824 *field_deliver_payload, *field_persist_items, *field_access_model,
03825 *field_pubsub_collection;
03826 configure = iks_insert(pubsub, "configure");
03827 x = iks_insert(configure, "x");
03828 iks_insert_attrib(x, "xmlns", "jabber:x:data");
03829 iks_insert_attrib(x, "type", "submit");
03830 field_owner = iks_insert(x, "field");
03831 iks_insert_attrib(field_owner, "var", "FORM_TYPE");
03832 iks_insert_attrib(field_owner, "type", "hidden");
03833 iks_insert_cdata(iks_insert(field_owner, "value"),
03834 "http://jabber.org/protocol/pubsub#owner", 39);
03835 if (node_type) {
03836 field_node_type = iks_insert(x, "field");
03837 iks_insert_attrib(field_node_type, "var", "pubsub#node_type");
03838 iks_insert_cdata(iks_insert(field_node_type, "value"), node_type, strlen(node_type));
03839 }
03840 field_node_config = iks_insert(x, "field");
03841 iks_insert_attrib(field_node_config, "var", "FORM_TYPE");
03842 iks_insert_attrib(field_node_config, "type", "hidden");
03843 iks_insert_cdata(iks_insert(field_node_config, "value"),
03844 "http://jabber.org/protocol/pubsub#node_config", 45);
03845 field_deliver_payload = iks_insert(x, "field");
03846 iks_insert_attrib(field_deliver_payload, "var", "pubsub#deliver_payloads");
03847 iks_insert_cdata(iks_insert(field_deliver_payload, "value"), "1", 1);
03848 field_persist_items = iks_insert(x, "field");
03849 iks_insert_attrib(field_persist_items, "var", "pubsub#persist_items");
03850 iks_insert_cdata(iks_insert(field_persist_items, "value"), "1", 1);
03851 field_access_model = iks_insert(x, "field");
03852 iks_insert_attrib(field_access_model, "var", "pubsub#access_model");
03853 iks_insert_cdata(iks_insert(field_access_model, "value"), "whitelist", 9);
03854 if (node_type && !strcasecmp(node_type, "leaf")) {
03855 field_pubsub_collection = iks_insert(x, "field");
03856 iks_insert_attrib(field_pubsub_collection, "var", "pubsub#collection");
03857 iks_insert_cdata(iks_insert(field_pubsub_collection, "value"), collection_name,
03858 strlen(collection_name));
03859 }
03860 return configure;
03861 }
03862
03863
03864
03865
03866
03867
03868
03869 static char *aji_cli_create_collection(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03870 {
03871 struct aji_client *client;
03872 const char *name;
03873 const char *collection_name;
03874
03875 switch (cmd) {
03876 case CLI_INIT:
03877 e->command = "jabber create collection";
03878 e->usage =
03879 "Usage: jabber create collection <connection> <collection>\n"
03880 " Creates a PubSub collection node using the account\n"
03881 " as configured in jabber.conf.\n";
03882 return NULL;
03883 case CLI_GENERATE:
03884 return NULL;
03885 }
03886
03887 if (a->argc != 5) {
03888 return CLI_SHOWUSAGE;
03889 }
03890 name = a->argv[3];
03891 collection_name = a->argv[4];
03892
03893 if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
03894 ast_cli(a->fd, "Unable to find client '%s'!\n", name);
03895 return CLI_FAILURE;
03896 }
03897
03898 ast_cli(a->fd, "Creating test PubSub node collection.\n");
03899 aji_create_pubsub_collection(client, collection_name);
03900 ASTOBJ_UNREF(client, ast_aji_client_destroy);
03901 return CLI_SUCCESS;
03902 }
03903
03904
03905
03906
03907
03908 static char *aji_cli_create_leafnode(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03909 {
03910 struct aji_client *client;
03911 const char *name;
03912 const char *collection_name;
03913 const char *leaf_name;
03914
03915 switch (cmd) {
03916 case CLI_INIT:
03917 e->command = "jabber create leaf";
03918 e->usage =
03919 "Usage: jabber create leaf <connection> <collection> <leaf>\n"
03920 " Creates a PubSub leaf node using the account\n"
03921 " as configured in jabber.conf.\n";
03922 return NULL;
03923 case CLI_GENERATE:
03924 return NULL;
03925 }
03926
03927 if (a->argc != 6) {
03928 return CLI_SHOWUSAGE;
03929 }
03930 name = a->argv[3];
03931 collection_name = a->argv[4];
03932 leaf_name = a->argv[5];
03933
03934 if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
03935 ast_cli(a->fd, "Unable to find client '%s'!\n", name);
03936 return CLI_FAILURE;
03937 }
03938
03939 ast_cli(a->fd, "Creating test PubSub node collection.\n");
03940 aji_create_pubsub_leaf(client, collection_name, leaf_name);
03941 ASTOBJ_UNREF(client, ast_aji_client_destroy);
03942 return CLI_SUCCESS;
03943 }
03944
03945
03946
03947
03948
03949
03950
03951
03952
03953
03954
03955
03956
03957 static void aji_set_presence(struct aji_client *client, char *to, char *from, int level, char *desc)
03958 {
03959 iks *presence = iks_make_pres(level, desc);
03960 iks *cnode = iks_new("c");
03961 iks *priority = iks_new("priority");
03962 char priorityS[10];
03963
03964 if (presence && cnode && client && priority) {
03965 if (to) {
03966 iks_insert_attrib(presence, "to", to);
03967 }
03968 if (from) {
03969 iks_insert_attrib(presence, "from", from);
03970 }
03971 snprintf(priorityS, sizeof(priorityS), "%d", client->priority);
03972 iks_insert_cdata(priority, priorityS, strlen(priorityS));
03973 iks_insert_node(presence, priority);
03974 iks_insert_attrib(cnode, "node", "http://www.asterisk.org/xmpp/client/caps");
03975 iks_insert_attrib(cnode, "ver", "asterisk-xmpp");
03976 iks_insert_attrib(cnode, "ext", "voice-v1");
03977 iks_insert_attrib(cnode, "xmlns", "http://jabber.org/protocol/caps");
03978 iks_insert_node(presence, cnode);
03979 ast_aji_send(client, presence);
03980 } else {
03981 ast_log(LOG_ERROR, "Out of memory.\n");
03982 }
03983
03984 iks_delete(cnode);
03985 iks_delete(presence);
03986 iks_delete(priority);
03987 }
03988
03989
03990
03991
03992
03993
03994
03995
03996
03997
03998
03999 static int aji_set_group_presence(struct aji_client *client, char *room, int level, char *nick, char *desc)
04000 {
04001 int res = 0;
04002 iks *presence = NULL, *x = NULL;
04003 char from[AJI_MAX_JIDLEN];
04004 char roomid[AJI_MAX_JIDLEN];
04005
04006 presence = iks_make_pres(level, NULL);
04007 x = iks_new("x");
04008
04009 if (client->component) {
04010 snprintf(from, AJI_MAX_JIDLEN, "%s@%s/%s", nick, client->jid->full, nick);
04011 snprintf(roomid, AJI_MAX_JIDLEN, "%s/%s", room, nick);
04012 } else {
04013 snprintf(from, AJI_MAX_JIDLEN, "%s", client->jid->full);
04014 snprintf(roomid, AJI_MAX_JIDLEN, "%s/%s", room, nick ? nick : client->jid->user);
04015 }
04016
04017 if (!presence || !x || !client) {
04018 ast_log(LOG_ERROR, "Out of memory.\n");
04019 res = -1;
04020 goto safeout;
04021 } else {
04022 iks_insert_attrib(presence, "to", roomid);
04023 iks_insert_attrib(presence, "from", from);
04024 iks_insert_attrib(x, "xmlns", MUC_NS);
04025 iks_insert_node(presence, x);
04026 res = ast_aji_send(client, presence);
04027 }
04028
04029 safeout:
04030 iks_delete(presence);
04031 iks_delete(x);
04032 return res;
04033 }
04034
04035
04036
04037
04038
04039
04040 static char *aji_do_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04041 {
04042 switch (cmd) {
04043 case CLI_INIT:
04044 e->command = "jabber set debug {on|off}";
04045 e->usage =
04046 "Usage: jabber set debug {on|off}\n"
04047 " Enables/disables dumping of XMPP/Jabber packets for debugging purposes.\n";
04048 return NULL;
04049 case CLI_GENERATE:
04050 return NULL;
04051 }
04052
04053 if (a->argc != e->args) {
04054 return CLI_SHOWUSAGE;
04055 }
04056
04057 if (!strncasecmp(a->argv[e->args - 1], "on", 2)) {
04058 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04059 ASTOBJ_RDLOCK(iterator);
04060 iterator->debug = 1;
04061 ASTOBJ_UNLOCK(iterator);
04062 });
04063 ast_cli(a->fd, "Jabber Debugging Enabled.\n");
04064 return CLI_SUCCESS;
04065 } else if (!strncasecmp(a->argv[e->args - 1], "off", 3)) {
04066 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04067 ASTOBJ_RDLOCK(iterator);
04068 iterator->debug = 0;
04069 ASTOBJ_UNLOCK(iterator);
04070 });
04071 ast_cli(a->fd, "Jabber Debugging Disabled.\n");
04072 return CLI_SUCCESS;
04073 }
04074 return CLI_SHOWUSAGE;
04075 }
04076
04077
04078
04079
04080
04081
04082 static char *aji_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04083 {
04084 switch (cmd) {
04085 case CLI_INIT:
04086 e->command = "jabber reload";
04087 e->usage =
04088 "Usage: jabber reload\n"
04089 " Reloads the Jabber module.\n";
04090 return NULL;
04091 case CLI_GENERATE:
04092 return NULL;
04093 }
04094
04095 aji_reload(1);
04096 ast_cli(a->fd, "Jabber Reloaded.\n");
04097 return CLI_SUCCESS;
04098 }
04099
04100
04101
04102
04103
04104
04105 static char *aji_show_clients(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04106 {
04107 char *status;
04108 int count = 0;
04109
04110 switch (cmd) {
04111 case CLI_INIT:
04112 e->command = "jabber show connections";
04113 e->usage =
04114 "Usage: jabber show connections\n"
04115 " Shows state of client and component connections\n";
04116 return NULL;
04117 case CLI_GENERATE:
04118 return NULL;
04119 }
04120
04121 ast_cli(a->fd, "Jabber Users and their status:\n");
04122 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04123 ASTOBJ_RDLOCK(iterator);
04124 count++;
04125 switch (iterator->state) {
04126 case AJI_DISCONNECTED:
04127 status = "Disconnected";
04128 break;
04129 case AJI_CONNECTING:
04130 status = "Connecting";
04131 break;
04132 case AJI_CONNECTED:
04133 status = "Connected";
04134 break;
04135 default:
04136 status = "Unknown";
04137 }
04138 ast_cli(a->fd, " [%s] %s - %s\n", iterator->name, iterator->user, status);
04139 ASTOBJ_UNLOCK(iterator);
04140 });
04141 ast_cli(a->fd, "----\n");
04142 ast_cli(a->fd, " Number of users: %d\n", count);
04143 return CLI_SUCCESS;
04144 }
04145
04146
04147
04148
04149
04150
04151 static char *aji_show_buddies(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04152 {
04153 struct aji_resource *resource;
04154 struct aji_client *client;
04155
04156 switch (cmd) {
04157 case CLI_INIT:
04158 e->command = "jabber show buddies";
04159 e->usage =
04160 "Usage: jabber show buddies\n"
04161 " Shows buddy lists of our clients\n";
04162 return NULL;
04163 case CLI_GENERATE:
04164 return NULL;
04165 }
04166
04167 ast_cli(a->fd, "Jabber buddy lists\n");
04168 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04169 ast_cli(a->fd, "Client: %s\n", iterator->user);
04170 client = iterator;
04171 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
04172 ASTOBJ_RDLOCK(iterator);
04173 ast_cli(a->fd, "\tBuddy:\t%s\n", iterator->name);
04174 if (!iterator->resources)
04175 ast_cli(a->fd, "\t\tResource: None\n");
04176 for (resource = iterator->resources; resource; resource = resource->next) {
04177 ast_cli(a->fd, "\t\tResource: %s\n", resource->resource);
04178 if (resource->cap) {
04179 ast_cli(a->fd, "\t\t\tnode: %s\n", resource->cap->parent->node);
04180 ast_cli(a->fd, "\t\t\tversion: %s\n", resource->cap->version);
04181 ast_cli(a->fd, "\t\t\tJingle capable: %s\n", resource->cap->jingle ? "yes" : "no");
04182 }
04183 ast_cli(a->fd, "\t\tStatus: %d\n", resource->status);
04184 ast_cli(a->fd, "\t\tPriority: %d\n", resource->priority);
04185 }
04186 ASTOBJ_UNLOCK(iterator);
04187 });
04188 iterator = client;
04189 });
04190 return CLI_SUCCESS;
04191 }
04192
04193
04194
04195
04196
04197
04198
04199
04200
04201 static int aji_create_client(char *label, struct ast_variable *var, int debug)
04202 {
04203 char *resource;
04204 struct aji_client *client = NULL;
04205 int flag = 0;
04206
04207 client = ASTOBJ_CONTAINER_FIND(&clients, label);
04208 if (!client) {
04209 flag = 1;
04210 client = ast_calloc(1, sizeof(*client));
04211 if (!client) {
04212 ast_log(LOG_ERROR, "Out of memory!\n");
04213 return 0;
04214 }
04215 ASTOBJ_INIT(client);
04216 ASTOBJ_WRLOCK(client);
04217 ASTOBJ_CONTAINER_INIT(&client->buddies);
04218 } else {
04219 ASTOBJ_WRLOCK(client);
04220 ASTOBJ_UNMARK(client);
04221 }
04222 ASTOBJ_CONTAINER_MARKALL(&client->buddies);
04223 ast_copy_string(client->name, label, sizeof(client->name));
04224 ast_copy_string(client->mid, "aaaaa", sizeof(client->mid));
04225
04226
04227 client->debug = debug;
04228 ast_copy_flags(&client->flags, &globalflags, AST_FLAGS_ALL);
04229 client->port = 5222;
04230 client->usetls = 1;
04231 client->usesasl = 1;
04232 client->forcessl = 0;
04233 client->keepalive = 1;
04234 client->timeout = 50;
04235 client->message_timeout = 5;
04236 client->distribute_events = 0;
04237 AST_LIST_HEAD_INIT(&client->messages);
04238 client->component = 0;
04239 ast_copy_string(client->statusmessage, "Online and Available", sizeof(client->statusmessage));
04240 client->priority = 0;
04241 client->status = IKS_SHOW_AVAILABLE;
04242
04243 if (flag) {
04244 client->authorized = 0;
04245 client->state = AJI_DISCONNECTED;
04246 }
04247 while (var) {
04248 if (!strcasecmp(var->name, "username")) {
04249 ast_copy_string(client->user, var->value, sizeof(client->user));
04250 } else if (!strcasecmp(var->name, "serverhost")) {
04251 ast_copy_string(client->serverhost, var->value, sizeof(client->serverhost));
04252 } else if (!strcasecmp(var->name, "secret")) {
04253 ast_copy_string(client->password, var->value, sizeof(client->password));
04254 } else if (!strcasecmp(var->name, "statusmessage")) {
04255 ast_copy_string(client->statusmessage, var->value, sizeof(client->statusmessage));
04256 } else if (!strcasecmp(var->name, "port")) {
04257 client->port = atoi(var->value);
04258 } else if (!strcasecmp(var->name, "timeout")) {
04259 client->message_timeout = atoi(var->value);
04260 } else if (!strcasecmp(var->name, "debug")) {
04261 client->debug = (ast_false(var->value)) ? 0 : 1;
04262 } else if (!strcasecmp(var->name, "type")) {
04263 if (!strcasecmp(var->value, "component")) {
04264 client->component = 1;
04265 if (client->distribute_events) {
04266 ast_log(LOG_ERROR, "Client cannot be configured to be both a component and to distribute events! Event distribution will be disabled.\n");
04267 client->distribute_events = 0;
04268 }
04269 }
04270 } else if (!strcasecmp(var->name, "distribute_events")) {
04271 if (ast_true(var->value)) {
04272 if (client->component) {
04273 ast_log(LOG_ERROR, "Client cannot be configured to be both a component and to distribute events! Event distribution will be disabled.\n");
04274 } else {
04275 if (ast_test_flag(&pubsubflags, AJI_PUBSUB)) {
04276 ast_log(LOG_ERROR, "Only one connection can be configured for distributed events.\n");
04277 } else {
04278 ast_set_flag(&pubsubflags, AJI_PUBSUB);
04279 client->distribute_events = 1;
04280 }
04281 }
04282 }
04283 } else if (!strcasecmp(var->name, "pubsub_node")) {
04284 ast_copy_string(client->pubsub_node, var->value, sizeof(client->pubsub_node));
04285 } else if (!strcasecmp(var->name, "usetls")) {
04286 client->usetls = (ast_false(var->value)) ? 0 : 1;
04287 } else if (!strcasecmp(var->name, "usesasl")) {
04288 client->usesasl = (ast_false(var->value)) ? 0 : 1;
04289 } else if (!strcasecmp(var->name, "forceoldssl")) {
04290 client->forcessl = (ast_false(var->value)) ? 0 : 1;
04291 } else if (!strcasecmp(var->name, "keepalive")) {
04292 client->keepalive = (ast_false(var->value)) ? 0 : 1;
04293 } else if (!strcasecmp(var->name, "autoprune")) {
04294 ast_set2_flag(&client->flags, ast_true(var->value), AJI_AUTOPRUNE);
04295 } else if (!strcasecmp(var->name, "autoregister")) {
04296 ast_set2_flag(&client->flags, ast_true(var->value), AJI_AUTOREGISTER);
04297 } else if (!strcasecmp(var->name, "auth_policy")) {
04298 if (!strcasecmp(var->value, "accept")) {
04299 ast_set_flag(&client->flags, AJI_AUTOACCEPT);
04300 } else {
04301 ast_clear_flag(&client->flags, AJI_AUTOACCEPT);
04302 }
04303 } else if (!strcasecmp(var->name, "buddy")) {
04304 aji_create_buddy((char *)var->value, client);
04305 } else if (!strcasecmp(var->name, "priority")) {
04306 client->priority = atoi(var->value);
04307 } else if (!strcasecmp(var->name, "status")) {
04308 if (!strcasecmp(var->value, "unavailable")) {
04309 client->status = IKS_SHOW_UNAVAILABLE;
04310 } else if (!strcasecmp(var->value, "available")
04311 || !strcasecmp(var->value, "online")) {
04312 client->status = IKS_SHOW_AVAILABLE;
04313 } else if (!strcasecmp(var->value, "chat")
04314 || !strcasecmp(var->value, "chatty")) {
04315 client->status = IKS_SHOW_CHAT;
04316 } else if (!strcasecmp(var->value, "away")) {
04317 client->status = IKS_SHOW_AWAY;
04318 } else if (!strcasecmp(var->value, "xa")
04319 || !strcasecmp(var->value, "xaway")) {
04320 client->status = IKS_SHOW_XA;
04321 } else if (!strcasecmp(var->value, "dnd")) {
04322 client->status = IKS_SHOW_DND;
04323 } else if (!strcasecmp(var->value, "invisible")) {
04324 #ifdef IKS_SHOW_INVISIBLE
04325 client->status = IKS_SHOW_INVISIBLE;
04326 #else
04327 ast_log(LOG_WARNING, "Your iksemel doesn't support invisible status: falling back to DND\n");
04328 client->status = IKS_SHOW_DND;
04329 #endif
04330 } else {
04331 ast_log(LOG_WARNING, "Unknown presence status: %s\n", var->value);
04332 }
04333 }
04334
04335
04336
04337
04338 var = var->next;
04339 }
04340 if (!flag) {
04341 ASTOBJ_UNLOCK(client);
04342 ASTOBJ_UNREF(client, ast_aji_client_destroy);
04343 return 1;
04344 }
04345
04346 ast_copy_string(client->name_space, (client->component) ? "jabber:component:accept" : "jabber:client", sizeof(client->name_space));
04347 client->p = iks_stream_new(client->name_space, client, aji_act_hook);
04348 if (!client->p) {
04349 ast_log(LOG_ERROR, "Failed to create stream for client '%s'!\n", client->name);
04350 return 0;
04351 }
04352 client->stack = iks_stack_new(8192, 8192);
04353 if (!client->stack) {
04354 ast_log(LOG_ERROR, "Failed to allocate stack for client '%s'\n", client->name);
04355 return 0;
04356 }
04357 client->f = iks_filter_new();
04358 if (!client->f) {
04359 ast_log(LOG_ERROR, "Failed to create filter for client '%s'\n", client->name);
04360 return 0;
04361 }
04362 if (!strchr(client->user, '/') && !client->component) {
04363 if (ast_asprintf(&resource, "%s/asterisk", client->user) >= 0) {
04364 client->jid = iks_id_new(client->stack, resource);
04365 ast_free(resource);
04366 }
04367 } else {
04368 client->jid = iks_id_new(client->stack, client->user);
04369 }
04370 if (client->component) {
04371 iks_filter_add_rule(client->f, aji_dinfo_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
04372 iks_filter_add_rule(client->f, aji_ditems_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#items", IKS_RULE_DONE);
04373 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);
04374 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);
04375 } else {
04376 iks_filter_add_rule(client->f, aji_client_info_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
04377 }
04378
04379 iks_set_log_hook(client->p, aji_log_hook);
04380 ASTOBJ_UNLOCK(client);
04381 ASTOBJ_CONTAINER_LINK(&clients, client);
04382 return 1;
04383 }
04384
04385
04386
04387 #if 0
04388
04389
04390
04391
04392
04393
04394 static int aji_create_transport(char *label, struct aji_client *client)
04395 {
04396 char *server = NULL, *buddyname = NULL, *user = NULL, *pass = NULL;
04397 struct aji_buddy *buddy = NULL;
04398 int needs_unref = 1;
04399
04400 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies,label);
04401 if (!buddy) {
04402 needs_unref = 0;
04403 buddy = ast_calloc(1, sizeof(*buddy));
04404 if (!buddy) {
04405 ast_log(LOG_WARNING, "Out of memory\n");
04406 return 0;
04407 }
04408 ASTOBJ_INIT(buddy);
04409 }
04410 ASTOBJ_WRLOCK(buddy);
04411 server = label;
04412 if ((buddyname = strchr(label, ','))) {
04413 *buddyname = '\0';
04414 buddyname++;
04415 if (buddyname && buddyname[0] != '\0') {
04416 if ((user = strchr(buddyname, ','))) {
04417 *user = '\0';
04418 user++;
04419 if (user && user[0] != '\0') {
04420 if ((pass = strchr(user, ','))) {
04421 *pass = '\0';
04422 pass++;
04423 ast_copy_string(buddy->pass, pass, sizeof(buddy->pass));
04424 ast_copy_string(buddy->user, user, sizeof(buddy->user));
04425 ast_copy_string(buddy->name, buddyname, sizeof(buddy->name));
04426 ast_copy_string(buddy->server, server, sizeof(buddy->server));
04427 if (needs_unref) {
04428 ASTOBJ_UNMARK(buddy);
04429 ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
04430 }
04431 return 1;
04432 }
04433 }
04434 }
04435 }
04436 }
04437 ASTOBJ_UNLOCK(buddy);
04438 if (needs_unref) {
04439 ASTOBJ_UNMARK(buddy);
04440 ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
04441 } else {
04442 ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
04443 }
04444 return 0;
04445 }
04446 #endif
04447
04448
04449
04450
04451
04452
04453
04454
04455 static int aji_create_buddy(char *label, struct aji_client *client)
04456 {
04457 struct aji_buddy *buddy = NULL;
04458 int needs_unref = 1;
04459 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, label);
04460 if (!buddy) {
04461 needs_unref = 0;
04462 buddy = ast_calloc(1, sizeof(*buddy));
04463 if (!buddy) {
04464 ast_log(LOG_WARNING, "Out of memory\n");
04465 return 0;
04466 }
04467 ASTOBJ_INIT(buddy);
04468 }
04469 ASTOBJ_WRLOCK(buddy);
04470 ast_copy_string(buddy->name, label, sizeof(buddy->name));
04471 ASTOBJ_UNLOCK(buddy);
04472 if (needs_unref) {
04473 ASTOBJ_UNMARK(buddy);
04474 ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
04475 } else {
04476 ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
04477 }
04478 return 1;
04479 }
04480
04481
04482 static int aji_load_config(int reload)
04483 {
04484 char *cat = NULL;
04485 int debug = 0;
04486 struct ast_config *cfg = NULL;
04487 struct ast_variable *var = NULL;
04488 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
04489
04490 if ((cfg = ast_config_load(JABBER_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
04491 return -1;
04492 }
04493
04494
04495 ast_set_flag(&globalflags, AJI_AUTOREGISTER | AJI_AUTOACCEPT);
04496
04497 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
04498 ast_log(LOG_WARNING, "No such configuration file %s\n", JABBER_CONFIG);
04499 return 0;
04500 }
04501
04502 cat = ast_category_browse(cfg, NULL);
04503 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
04504 if (!strcasecmp(var->name, "debug")) {
04505 debug = (ast_false(ast_variable_retrieve(cfg, "general", "debug"))) ? 0 : 1;
04506 } else if (!strcasecmp(var->name, "autoprune")) {
04507 ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOPRUNE);
04508 } else if (!strcasecmp(var->name, "autoregister")) {
04509 ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOREGISTER);
04510 } else if (!strcasecmp(var->name, "collection_nodes")) {
04511 ast_set2_flag(&pubsubflags, ast_true(var->value), AJI_XEP0248);
04512 } else if (!strcasecmp(var->name, "pubsub_autocreate")) {
04513 ast_set2_flag(&pubsubflags, ast_true(var->value), AJI_PUBSUB_AUTOCREATE);
04514 } else if (!strcasecmp(var->name, "auth_policy")) {
04515 if (!strcasecmp(var->value, "accept")) {
04516 ast_set_flag(&globalflags, AJI_AUTOACCEPT);
04517 } else {
04518 ast_clear_flag(&globalflags, AJI_AUTOACCEPT);
04519 }
04520 }
04521 }
04522
04523 while (cat) {
04524 if (strcasecmp(cat, "general")) {
04525 var = ast_variable_browse(cfg, cat);
04526 aji_create_client(cat, var, debug);
04527 }
04528 cat = ast_category_browse(cfg, cat);
04529 }
04530 ast_config_destroy(cfg);
04531 return 1;
04532 }
04533
04534
04535
04536
04537
04538
04539
04540 struct aji_client *ast_aji_get_client(const char *name)
04541 {
04542 struct aji_client *client = NULL;
04543 char *aux = NULL;
04544
04545 client = ASTOBJ_CONTAINER_FIND(&clients, name);
04546 if (!client && strchr(name, '@')) {
04547 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04548 aux = ast_strdupa(iterator->user);
04549 if (strchr(aux, '/')) {
04550
04551 aux = strsep(&aux, "/");
04552 }
04553 if (!strncasecmp(aux, name, strlen(aux))) {
04554 client = ASTOBJ_REF(iterator);
04555 }
04556 });
04557 }
04558
04559 return client;
04560 }
04561
04562 struct aji_client_container *ast_aji_get_clients(void)
04563 {
04564 return &clients;
04565 }
04566
04567
04568
04569
04570
04571
04572
04573
04574 static int manager_jabber_send(struct mansession *s, const struct message *m)
04575 {
04576 struct aji_client *client = NULL;
04577 const char *id = astman_get_header(m, "ActionID");
04578 const char *jabber = astman_get_header(m, "Jabber");
04579 const char *screenname = astman_get_header(m, "ScreenName");
04580 const char *message = astman_get_header(m, "Message");
04581
04582 if (ast_strlen_zero(jabber)) {
04583 astman_send_error(s, m, "No transport specified");
04584 return 0;
04585 }
04586 if (ast_strlen_zero(screenname)) {
04587 astman_send_error(s, m, "No ScreenName specified");
04588 return 0;
04589 }
04590 if (ast_strlen_zero(message)) {
04591 astman_send_error(s, m, "No Message specified");
04592 return 0;
04593 }
04594
04595 astman_send_ack(s, m, "Attempting to send Jabber Message");
04596 client = ast_aji_get_client(jabber);
04597 if (!client) {
04598 astman_send_error(s, m, "Could not find Sender");
04599 return 0;
04600 }
04601 if (strchr(screenname, '@') && message) {
04602 ast_aji_send_chat(client, screenname, message);
04603 astman_append(s, "Response: Success\r\n");
04604 } else {
04605 astman_append(s, "Response: Error\r\n");
04606 }
04607 ASTOBJ_UNREF(client, ast_aji_client_destroy);
04608 if (!ast_strlen_zero(id)) {
04609 astman_append(s, "ActionID: %s\r\n", id);
04610 }
04611 astman_append(s, "\r\n");
04612 return 0;
04613 }
04614
04615
04616
04617
04618
04619 static int aji_reload(int reload)
04620 {
04621 int res;
04622
04623 ASTOBJ_CONTAINER_MARKALL(&clients);
04624 if (!(res = aji_load_config(reload))) {
04625 ast_log(LOG_ERROR, "JABBER: Failed to load config.\n");
04626 return 0;
04627 } else if (res == -1)
04628 return 1;
04629
04630 ASTOBJ_CONTAINER_PRUNE_MARKED(&clients, ast_aji_client_destroy);
04631 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04632 ASTOBJ_RDLOCK(iterator);
04633 if (iterator->state == AJI_DISCONNECTED) {
04634 if (!iterator->thread)
04635 ast_pthread_create_background(&iterator->thread, NULL, aji_recv_loop, iterator);
04636 } else if (iterator->state == AJI_CONNECTING) {
04637 aji_get_roster(iterator);
04638 if (iterator->distribute_events) {
04639 aji_init_event_distribution(iterator);
04640 }
04641 }
04642
04643 ASTOBJ_UNLOCK(iterator);
04644 });
04645
04646 return 1;
04647 }
04648
04649
04650
04651
04652
04653 static int unload_module(void)
04654 {
04655
04656 ast_cli_unregister_multiple(aji_cli, ARRAY_LEN(aji_cli));
04657 ast_unregister_application(app_ajisend);
04658 ast_unregister_application(app_ajisendgroup);
04659 ast_unregister_application(app_ajistatus);
04660 ast_unregister_application(app_ajijoin);
04661 ast_unregister_application(app_ajileave);
04662 ast_manager_unregister("JabberSend");
04663 ast_custom_function_unregister(&jabberstatus_function);
04664 if (mwi_sub) {
04665 ast_event_unsubscribe(mwi_sub);
04666 }
04667 if (device_state_sub) {
04668 ast_event_unsubscribe(device_state_sub);
04669 }
04670 ast_custom_function_unregister(&jabberreceive_function);
04671
04672 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04673 ASTOBJ_WRLOCK(iterator);
04674 ast_debug(3, "JABBER: Releasing and disconnecting client: %s\n", iterator->name);
04675 iterator->state = AJI_DISCONNECTING;
04676 ASTOBJ_UNLOCK(iterator);
04677 pthread_join(iterator->thread, NULL);
04678 ast_aji_disconnect(iterator);
04679 });
04680
04681 ASTOBJ_CONTAINER_DESTROYALL(&clients, ast_aji_client_destroy);
04682 ASTOBJ_CONTAINER_DESTROY(&clients);
04683
04684 ast_cond_destroy(&message_received_condition);
04685 ast_mutex_destroy(&messagelock);
04686
04687 return 0;
04688 }
04689
04690
04691
04692
04693
04694 static int load_module(void)
04695 {
04696 ASTOBJ_CONTAINER_INIT(&clients);
04697 if (!aji_reload(0))
04698 return AST_MODULE_LOAD_DECLINE;
04699 ast_manager_register_xml("JabberSend", EVENT_FLAG_SYSTEM, manager_jabber_send);
04700 ast_register_application_xml(app_ajisend, aji_send_exec);
04701 ast_register_application_xml(app_ajisendgroup, aji_sendgroup_exec);
04702 ast_register_application_xml(app_ajistatus, aji_status_exec);
04703 ast_register_application_xml(app_ajijoin, aji_join_exec);
04704 ast_register_application_xml(app_ajileave, aji_leave_exec);
04705 ast_cli_register_multiple(aji_cli, ARRAY_LEN(aji_cli));
04706 ast_custom_function_register(&jabberstatus_function);
04707 ast_custom_function_register(&jabberreceive_function);
04708
04709 ast_mutex_init(&messagelock);
04710 ast_cond_init(&message_received_condition, NULL);
04711 return 0;
04712 }
04713
04714
04715
04716
04717
04718 static int reload(void)
04719 {
04720 aji_reload(1);
04721 return 0;
04722 }
04723
04724 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "AJI - Asterisk Jabber Interface",
04725 .load = load_module,
04726 .unload = unload_module,
04727 .reload = reload,
04728 .load_pri = AST_MODPRI_CHANNEL_DEPEND,
04729 );