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