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