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