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: 366880 $")
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_free(insert);
02256 ast_log(LOG_ERROR, "Memory allocation failure\n");
02257 return;
02258 }
02259 ast_debug(3, "message comes from %s\n", insert->from);
02260 }
02261
02262
02263
02264 deleted = delete_old_messages(client, pak->from->partial);
02265 ast_debug(3, "Deleted %d messages for client %s from JID %s\n", deleted, client->name, pak->from->partial);
02266 AST_LIST_LOCK(&client->messages);
02267 AST_LIST_INSERT_HEAD(&client->messages, insert, list);
02268 AST_LIST_UNLOCK(&client->messages);
02269 }
02270
02271
02272
02273
02274
02275
02276
02277 static void aji_handle_presence(struct aji_client *client, ikspak *pak)
02278 {
02279 int status, priority;
02280 struct aji_buddy *buddy;
02281 struct aji_resource *tmp = NULL, *last = NULL, *found = NULL;
02282 char *ver, *node, *descrip, *type;
02283
02284 if (client->state != AJI_CONNECTED)
02285 aji_create_buddy(pak->from->partial, client);
02286
02287 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
02288 if (!buddy && pak->from->partial) {
02289
02290 if (!strcmp((const char *)pak->from->partial, (const char *)client->jid->partial))
02291 aji_create_buddy(pak->from->partial, client);
02292 else
02293 ast_log(LOG_NOTICE, "Got presence packet from %s, someone not in our roster!!!!\n", pak->from->partial);
02294 return;
02295 }
02296 type = iks_find_attrib(pak->x, "type");
02297 if (client->component && type &&!strcasecmp("probe", type)) {
02298 aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), client->status, client->statusmessage);
02299 ast_verbose("what i was looking for \n");
02300 }
02301 ASTOBJ_WRLOCK(buddy);
02302 status = (pak->show) ? pak->show : 6;
02303 priority = atoi((iks_find_cdata(pak->x, "priority")) ? iks_find_cdata(pak->x, "priority") : "0");
02304 tmp = buddy->resources;
02305 descrip = ast_strdup(iks_find_cdata(pak->x, "status"));
02306
02307 while (tmp && pak->from->resource) {
02308 if (!strcasecmp(tmp->resource, pak->from->resource)) {
02309 tmp->status = status;
02310 if (tmp->description) {
02311 ast_free(tmp->description);
02312 }
02313 tmp->description = descrip;
02314 found = tmp;
02315 if (status == 6) {
02316 if (last && found->next) {
02317 last->next = found->next;
02318 } else if (!last) {
02319 if (found->next) {
02320 buddy->resources = found->next;
02321 } else {
02322 buddy->resources = NULL;
02323 }
02324 } else if (!found->next) {
02325 if (last) {
02326 last->next = NULL;
02327 } else {
02328 buddy->resources = NULL;
02329 }
02330 }
02331 ast_free(found);
02332 found = NULL;
02333 break;
02334 }
02335
02336 if (tmp->priority != priority) {
02337 found->priority = priority;
02338 if (!last && !found->next) {
02339
02340
02341 break;
02342 }
02343
02344
02345 if (last) {
02346 last->next = found->next;
02347 } else {
02348 buddy->resources = found->next;
02349 }
02350
02351 last = NULL;
02352 tmp = buddy->resources;
02353 if (!buddy->resources) {
02354 buddy->resources = found;
02355 }
02356
02357 while (tmp) {
02358
02359
02360 if (found->priority > tmp->priority) {
02361 if (last) {
02362
02363 last->next = found;
02364 }
02365 found->next = tmp;
02366 if (!last) {
02367
02368 buddy->resources = found;
02369 }
02370 break;
02371 }
02372 if (!tmp->next) {
02373
02374 tmp->next = found;
02375 found->next = NULL;
02376 break;
02377 }
02378 last = tmp;
02379 tmp = tmp->next;
02380 }
02381 }
02382 break;
02383 }
02384 last = tmp;
02385 tmp = tmp->next;
02386 }
02387
02388
02389 if (!found && status != 6 && pak->from->resource) {
02390 found = ast_calloc(1, sizeof(*found));
02391
02392 if (!found) {
02393 ast_log(LOG_ERROR, "Out of memory!\n");
02394 ASTOBJ_UNLOCK(buddy);
02395 ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
02396 return;
02397 }
02398 ast_copy_string(found->resource, pak->from->resource, sizeof(found->resource));
02399 found->status = status;
02400 found->description = descrip;
02401 found->priority = priority;
02402 found->next = NULL;
02403 last = NULL;
02404 tmp = buddy->resources;
02405 while (tmp) {
02406 if (found->priority > tmp->priority) {
02407 if (last) {
02408 last->next = found;
02409 }
02410 found->next = tmp;
02411 if (!last) {
02412 buddy->resources = found;
02413 }
02414 break;
02415 }
02416 if (!tmp->next) {
02417 tmp->next = found;
02418 break;
02419 }
02420 last = tmp;
02421 tmp = tmp->next;
02422 }
02423 if (!tmp) {
02424 buddy->resources = found;
02425 }
02426 }
02427
02428 ASTOBJ_UNLOCK(buddy);
02429 ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
02430
02431 node = iks_find_attrib(iks_find(pak->x, "c"), "node");
02432 ver = iks_find_attrib(iks_find(pak->x, "c"), "ver");
02433
02434
02435 if (!node && !ver) {
02436 node = iks_find_attrib(iks_find(pak->x, "caps:c"), "node");
02437 ver = iks_find_attrib(iks_find(pak->x, "caps:c"), "ver");
02438 }
02439
02440
02441 if (status != 6 && found && !found->cap) {
02442 found->cap = aji_find_version(node, ver, pak);
02443 if (gtalk_yuck(pak->x)) {
02444 found->cap->jingle = 1;
02445 }
02446 if (found->cap->jingle) {
02447 ast_debug(1, "Special case for google till they support discover.\n");
02448 } else {
02449 iks *iq, *query;
02450 iq = iks_new("iq");
02451 query = iks_new("query");
02452 if (query && iq) {
02453 iks_insert_attrib(iq, "type", "get");
02454 iks_insert_attrib(iq, "to", pak->from->full);
02455 iks_insert_attrib(iq, "from", client->jid->full);
02456 iks_insert_attrib(iq, "id", client->mid);
02457 ast_aji_increment_mid(client->mid);
02458 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
02459 iks_insert_node(iq, query);
02460 ast_aji_send(client, iq);
02461 } else {
02462 ast_log(LOG_ERROR, "Out of memory.\n");
02463 }
02464 iks_delete(query);
02465 iks_delete(iq);
02466 }
02467 }
02468 switch (pak->subtype) {
02469 case IKS_TYPE_AVAILABLE:
02470 ast_debug(3, "JABBER: I am available ^_* %i\n", pak->subtype);
02471 break;
02472 case IKS_TYPE_UNAVAILABLE:
02473 ast_debug(3, "JABBER: I am unavailable ^_* %i\n", pak->subtype);
02474 break;
02475 default:
02476 ast_debug(3, "JABBER: Ohh sexy and the wrong type: %i\n", pak->subtype);
02477 }
02478 switch (pak->show) {
02479 case IKS_SHOW_UNAVAILABLE:
02480 ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
02481 break;
02482 case IKS_SHOW_AVAILABLE:
02483 ast_debug(3, "JABBER: type is available\n");
02484 break;
02485 case IKS_SHOW_CHAT:
02486 ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
02487 break;
02488 case IKS_SHOW_AWAY:
02489 ast_debug(3, "JABBER: type is away\n");
02490 break;
02491 case IKS_SHOW_XA:
02492 ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
02493 break;
02494 case IKS_SHOW_DND:
02495 ast_debug(3, "JABBER: type: %i subtype %i\n", pak->subtype, pak->show);
02496 break;
02497 default:
02498 ast_debug(3, "JABBER: Kinky! how did that happen %i\n", pak->show);
02499 }
02500
02501 if (found) {
02502 manager_event(EVENT_FLAG_USER, "JabberStatus",
02503 "Account: %s\r\nJID: %s\r\nResource: %s\r\nStatus: %d\r\nPriority: %d"
02504 "\r\nDescription: %s\r\n",
02505 client->name, pak->from->partial, found->resource, found->status,
02506 found->priority, S_OR(found->description, ""));
02507 } else {
02508 manager_event(EVENT_FLAG_USER, "JabberStatus",
02509 "Account: %s\r\nJID: %s\r\nStatus: %d\r\n",
02510 client->name, pak->from->partial, pak->show ? pak->show : IKS_SHOW_UNAVAILABLE);
02511 }
02512 }
02513
02514
02515
02516
02517
02518
02519
02520
02521 static void aji_handle_subscribe(struct aji_client *client, ikspak *pak)
02522 {
02523 iks *presence = NULL, *status = NULL;
02524 struct aji_buddy* buddy = NULL;
02525
02526 switch (pak->subtype) {
02527 case IKS_TYPE_SUBSCRIBE:
02528 if (ast_test_flag(&client->flags, AJI_AUTOACCEPT)) {
02529 presence = iks_new("presence");
02530 status = iks_new("status");
02531 if (presence && status) {
02532 iks_insert_attrib(presence, "type", "subscribed");
02533 iks_insert_attrib(presence, "to", pak->from->full);
02534 iks_insert_attrib(presence, "from", client->jid->full);
02535 if (pak->id)
02536 iks_insert_attrib(presence, "id", pak->id);
02537 iks_insert_cdata(status, "Asterisk has approved subscription", 0);
02538 iks_insert_node(presence, status);
02539 ast_aji_send(client, presence);
02540 } else {
02541 ast_log(LOG_ERROR, "Unable to allocate nodes\n");
02542 }
02543
02544 iks_delete(presence);
02545 iks_delete(status);
02546 }
02547
02548 if (client->component)
02549 aji_set_presence(client, pak->from->full, iks_find_attrib(pak->x, "to"), client->status, client->statusmessage);
02550 case IKS_TYPE_SUBSCRIBED:
02551 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
02552 if (!buddy && pak->from->partial) {
02553 aji_create_buddy(pak->from->partial, client);
02554 } else if (buddy) {
02555 ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
02556 }
02557 default:
02558 if (option_verbose > 4) {
02559 ast_verbose(VERBOSE_PREFIX_3 "JABBER: This is a subcription of type %i\n", pak->subtype);
02560 }
02561 }
02562 }
02563
02564
02565
02566
02567
02568
02569
02570
02571
02572 int ast_aji_send_chat(struct aji_client *client, const char *address, const char *message)
02573 {
02574 return aji_send_raw_chat(client, 0, NULL, address, message);
02575 }
02576
02577
02578
02579
02580
02581
02582
02583
02584
02585
02586 int ast_aji_send_groupchat(struct aji_client *client, const char *nick, const char *address, const char *message) {
02587 return aji_send_raw_chat(client, 1, nick, address, message);
02588 }
02589
02590
02591
02592
02593
02594
02595
02596
02597
02598
02599 static int aji_send_raw_chat(struct aji_client *client, int groupchat, const char *nick, const char *address, const char *message)
02600 {
02601 int res = 0;
02602 iks *message_packet = NULL;
02603 char from[AJI_MAX_JIDLEN];
02604
02605 if (nick && client->component) {
02606 snprintf(from, AJI_MAX_JIDLEN, "%s@%s/%s", nick, client->jid->full, nick);
02607 } else {
02608 snprintf(from, AJI_MAX_JIDLEN, "%s", client->jid->full);
02609 }
02610
02611 if (client->state != AJI_CONNECTED) {
02612 ast_log(LOG_WARNING, "JABBER: Not connected can't send\n");
02613 return -1;
02614 }
02615
02616 message_packet = iks_make_msg(groupchat ? IKS_TYPE_GROUPCHAT : IKS_TYPE_CHAT, address, message);
02617 if (!message_packet) {
02618 ast_log(LOG_ERROR, "Out of memory.\n");
02619 return -1;
02620 }
02621 iks_insert_attrib(message_packet, "from", from);
02622 res = ast_aji_send(client, message_packet);
02623 iks_delete(message_packet);
02624
02625 return res;
02626 }
02627
02628
02629
02630
02631
02632
02633
02634
02635
02636 int ast_aji_create_chat(struct aji_client *client, char *room, char *server, char *topic)
02637 {
02638 int res = 0;
02639 iks *iq = NULL;
02640 iq = iks_new("iq");
02641
02642 if (iq && client) {
02643 iks_insert_attrib(iq, "type", "get");
02644 iks_insert_attrib(iq, "to", server);
02645 iks_insert_attrib(iq, "id", client->mid);
02646 ast_aji_increment_mid(client->mid);
02647 ast_aji_send(client, iq);
02648 } else {
02649 ast_log(LOG_ERROR, "Out of memory.\n");
02650 }
02651
02652 iks_delete(iq);
02653
02654 return res;
02655 }
02656
02657
02658
02659
02660
02661
02662
02663
02664 int ast_aji_join_chat(struct aji_client *client, char *room, char *nick)
02665 {
02666 return aji_set_group_presence(client, room, IKS_SHOW_AVAILABLE, nick, NULL);
02667 }
02668
02669
02670
02671
02672
02673
02674
02675
02676 int ast_aji_leave_chat(struct aji_client *client, char *room, char *nick)
02677 {
02678 return aji_set_group_presence(client, room, IKS_SHOW_UNAVAILABLE, nick, NULL);
02679 }
02680
02681
02682
02683
02684
02685
02686
02687
02688 int ast_aji_invite_chat(struct aji_client *client, char *user, char *room, char *message)
02689 {
02690 int res = 0;
02691 iks *invite, *body, *namespace;
02692
02693 invite = iks_new("message");
02694 body = iks_new("body");
02695 namespace = iks_new("x");
02696 if (client && invite && body && namespace) {
02697 iks_insert_attrib(invite, "to", user);
02698 iks_insert_attrib(invite, "id", client->mid);
02699 ast_aji_increment_mid(client->mid);
02700 iks_insert_cdata(body, message, 0);
02701 iks_insert_attrib(namespace, "xmlns", "jabber:x:conference");
02702 iks_insert_attrib(namespace, "jid", room);
02703 iks_insert_node(invite, body);
02704 iks_insert_node(invite, namespace);
02705 res = ast_aji_send(client, invite);
02706 } else {
02707 ast_log(LOG_ERROR, "Out of memory.\n");
02708 }
02709
02710 iks_delete(body);
02711 iks_delete(namespace);
02712 iks_delete(invite);
02713
02714 return res;
02715 }
02716
02717
02718
02719
02720
02721
02722
02723 static void *aji_recv_loop(void *data)
02724 {
02725 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
02726 int res = IKS_HOOK;
02727
02728 while (res != IKS_OK) {
02729 ast_debug(3, "JABBER: Connecting.\n");
02730 res = aji_reconnect(client);
02731 sleep(4);
02732 }
02733
02734 do {
02735 if (res == IKS_NET_RWERR || client->timeout == 0) {
02736 while (res != IKS_OK) {
02737 ast_debug(3, "JABBER: reconnecting.\n");
02738 res = aji_reconnect(client);
02739 sleep(4);
02740 }
02741 }
02742
02743 res = aji_recv(client, 1);
02744
02745 if (client->state == AJI_DISCONNECTING) {
02746 ast_debug(2, "Ending our Jabber client's thread due to a disconnect\n");
02747 pthread_exit(NULL);
02748 }
02749
02750
02751
02752 if (res == IKS_NET_EXPIRED) {
02753 client->timeout--;
02754 delete_old_messages_all(client);
02755 }
02756 if (res == IKS_HOOK) {
02757 ast_log(LOG_WARNING, "JABBER: Got hook event.\n");
02758 } else if (res == IKS_NET_TLSFAIL) {
02759 ast_log(LOG_ERROR, "JABBER: Failure in TLS.\n");
02760 } else if (client->timeout == 0 && client->state == AJI_CONNECTED) {
02761 res = client->keepalive ? aji_send_raw(client, " ") : IKS_OK;
02762 if (res == IKS_OK) {
02763 client->timeout = 50;
02764 } else {
02765 ast_log(LOG_WARNING, "JABBER: Network Timeout\n");
02766 }
02767 } else if (res == IKS_NET_RWERR) {
02768 ast_log(LOG_WARNING, "JABBER: socket read error\n");
02769 }
02770 } while (client);
02771 ASTOBJ_UNREF(client, ast_aji_client_destroy);
02772 return 0;
02773 }
02774
02775
02776
02777
02778
02779
02780 void ast_aji_increment_mid(char *mid)
02781 {
02782 int i = 0;
02783
02784 for (i = strlen(mid) - 1; i >= 0; i--) {
02785 if (mid[i] != 'z') {
02786 mid[i] = mid[i] + 1;
02787 i = 0;
02788 } else
02789 mid[i] = 'a';
02790 }
02791 }
02792
02793 #if 0
02794
02795
02796
02797
02798
02799
02800 static int aji_register_transport(void *data, ikspak *pak)
02801 {
02802 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
02803 int res = 0;
02804 struct aji_buddy *buddy = NULL;
02805 iks *send = iks_make_iq(IKS_TYPE_GET, "jabber:iq:register");
02806
02807 if (client && send) {
02808 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02809 ASTOBJ_RDLOCK(iterator);
02810 if (iterator->btype == AJI_TRANS) {
02811 buddy = iterator;
02812 }
02813 ASTOBJ_UNLOCK(iterator);
02814 });
02815 iks_filter_remove_hook(client->f, aji_register_transport);
02816 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);
02817 iks_insert_attrib(send, "to", buddy->host);
02818 iks_insert_attrib(send, "id", client->mid);
02819 ast_aji_increment_mid(client->mid);
02820 iks_insert_attrib(send, "from", client->user);
02821 res = ast_aji_send(client, send);
02822 } else
02823 ast_log(LOG_ERROR, "Out of memory.\n");
02824
02825 if (send)
02826 iks_delete(send);
02827 ASTOBJ_UNREF(client, ast_aji_client_destroy);
02828 return IKS_FILTER_EAT;
02829
02830 }
02831
02832
02833
02834
02835
02836
02837 static int aji_register_transport2(void *data, ikspak *pak)
02838 {
02839 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
02840 int res = 0;
02841 struct aji_buddy *buddy = NULL;
02842
02843 iks *regiq = iks_new("iq");
02844 iks *regquery = iks_new("query");
02845 iks *reguser = iks_new("username");
02846 iks *regpass = iks_new("password");
02847
02848 if (client && regquery && reguser && regpass && regiq) {
02849 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02850 ASTOBJ_RDLOCK(iterator);
02851 if (iterator->btype == AJI_TRANS)
02852 buddy = iterator; ASTOBJ_UNLOCK(iterator);
02853 });
02854 iks_filter_remove_hook(client->f, aji_register_transport2);
02855 iks_insert_attrib(regiq, "to", buddy->host);
02856 iks_insert_attrib(regiq, "type", "set");
02857 iks_insert_attrib(regiq, "id", client->mid);
02858 ast_aji_increment_mid(client->mid);
02859 iks_insert_attrib(regiq, "from", client->user);
02860 iks_insert_attrib(regquery, "xmlns", "jabber:iq:register");
02861 iks_insert_cdata(reguser, buddy->user, 0);
02862 iks_insert_cdata(regpass, buddy->pass, 0);
02863 iks_insert_node(regiq, regquery);
02864 iks_insert_node(regquery, reguser);
02865 iks_insert_node(regquery, regpass);
02866 res = ast_aji_send(client, regiq);
02867 } else
02868 ast_log(LOG_ERROR, "Out of memory.\n");
02869 if (regiq)
02870 iks_delete(regiq);
02871 if (regquery)
02872 iks_delete(regquery);
02873 if (reguser)
02874 iks_delete(reguser);
02875 if (regpass)
02876 iks_delete(regpass);
02877 ASTOBJ_UNREF(client, ast_aji_client_destroy);
02878 return IKS_FILTER_EAT;
02879 }
02880 #endif
02881
02882
02883
02884
02885
02886
02887
02888
02889 static void aji_pruneregister(struct aji_client *client)
02890 {
02891 iks *removeiq = iks_new("iq");
02892 iks *removequery = iks_new("query");
02893 iks *removeitem = iks_new("item");
02894 iks *send = iks_make_iq(IKS_TYPE_GET, "http://jabber.org/protocol/disco#items");
02895 if (!client || !removeiq || !removequery || !removeitem || !send) {
02896 ast_log(LOG_ERROR, "Out of memory.\n");
02897 goto safeout;
02898 }
02899
02900 iks_insert_node(removeiq, removequery);
02901 iks_insert_node(removequery, removeitem);
02902 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02903 ASTOBJ_RDLOCK(iterator);
02904
02905
02906 if (ast_test_flag(&iterator->flags, AJI_AUTOPRUNE)) {
02907 ast_aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBE, iterator->name,
02908 "GoodBye. Your status is no longer needed by Asterisk the Open Source PBX"
02909 " so I am no longer subscribing to your presence.\n"));
02910 ast_aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBED, iterator->name,
02911 "GoodBye. You are no longer in the Asterisk config file so I am removing"
02912 " your access to my presence.\n"));
02913 iks_insert_attrib(removeiq, "from", client->jid->full);
02914 iks_insert_attrib(removeiq, "type", "set");
02915 iks_insert_attrib(removequery, "xmlns", "jabber:iq:roster");
02916 iks_insert_attrib(removeitem, "jid", iterator->name);
02917 iks_insert_attrib(removeitem, "subscription", "remove");
02918 ast_aji_send(client, removeiq);
02919 } else if (ast_test_flag(&iterator->flags, AJI_AUTOREGISTER)) {
02920 ast_aji_send(client, iks_make_s10n(IKS_TYPE_SUBSCRIBE, iterator->name,
02921 "Greetings! I am the Asterisk Open Source PBX and I want to subscribe to your presence\n"));
02922 ast_clear_flag(&iterator->flags, AJI_AUTOREGISTER);
02923 }
02924 ASTOBJ_UNLOCK(iterator);
02925 });
02926
02927 safeout:
02928 iks_delete(removeiq);
02929 iks_delete(removequery);
02930 iks_delete(removeitem);
02931 iks_delete(send);
02932
02933 ASTOBJ_CONTAINER_PRUNE_MARKED(&client->buddies, ast_aji_buddy_destroy);
02934 }
02935
02936
02937
02938
02939
02940
02941
02942
02943 static int aji_filter_roster(void *data, ikspak *pak)
02944 {
02945 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
02946 int flag = 0;
02947 iks *x = NULL;
02948 struct aji_buddy *buddy;
02949
02950 client->state = AJI_CONNECTED;
02951 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02952 ASTOBJ_RDLOCK(iterator);
02953 x = iks_child(pak->query);
02954 flag = 0;
02955 while (x) {
02956 if (!iks_strcmp(iks_name(x), "item")) {
02957 if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid"))) {
02958 flag = 1;
02959 ast_clear_flag(&iterator->flags, AJI_AUTOPRUNE | AJI_AUTOREGISTER);
02960 }
02961 }
02962 x = iks_next(x);
02963 }
02964 if (!flag) {
02965 ast_copy_flags(&iterator->flags, &client->flags, AJI_AUTOREGISTER);
02966 }
02967 iks_delete(x);
02968
02969 ASTOBJ_UNLOCK(iterator);
02970 });
02971
02972 x = iks_child(pak->query);
02973 while (x) {
02974 flag = 0;
02975 if (iks_strcmp(iks_name(x), "item") == 0) {
02976 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
02977 ASTOBJ_RDLOCK(iterator);
02978 if (!strcasecmp(iterator->name, iks_find_attrib(x, "jid")))
02979 flag = 1;
02980 ASTOBJ_UNLOCK(iterator);
02981 });
02982
02983 if (flag) {
02984
02985 x = iks_next(x);
02986 continue;
02987 }
02988
02989 buddy = ast_calloc(1, sizeof(*buddy));
02990 if (!buddy) {
02991 ast_log(LOG_WARNING, "Out of memory\n");
02992 ASTOBJ_UNREF(client, ast_aji_client_destroy);
02993 return 0;
02994 }
02995 ASTOBJ_INIT(buddy);
02996 ASTOBJ_WRLOCK(buddy);
02997 ast_copy_string(buddy->name, iks_find_attrib(x, "jid"), sizeof(buddy->name));
02998 ast_clear_flag(&buddy->flags, AST_FLAGS_ALL);
02999 if (ast_test_flag(&client->flags, AJI_AUTOPRUNE)) {
03000 ast_set_flag(&buddy->flags, AJI_AUTOPRUNE);
03001 ASTOBJ_MARK(buddy);
03002 } else if (ast_test_flag(&client->flags, AJI_AUTOREGISTER)) {
03003 if (!iks_strcmp(iks_find_attrib(x, "subscription"), "none") || !iks_strcmp(iks_find_attrib(x, "subscription"), "from")) {
03004
03005
03006 ast_set_flag(&buddy->flags, AJI_AUTOREGISTER);
03007 }
03008 }
03009 ASTOBJ_UNLOCK(buddy);
03010 if (buddy) {
03011 ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
03012 ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
03013 }
03014 }
03015 x = iks_next(x);
03016 }
03017
03018 iks_delete(x);
03019 aji_pruneregister(client);
03020
03021 ASTOBJ_UNREF(client, ast_aji_client_destroy);
03022 return IKS_FILTER_EAT;
03023 }
03024
03025
03026
03027
03028
03029
03030
03031 static int aji_reconnect(struct aji_client *client)
03032 {
03033 int res = 0;
03034
03035 if (client->state) {
03036 client->state = AJI_DISCONNECTED;
03037 }
03038 client->timeout = 50;
03039 if (client->p) {
03040 iks_parser_reset(client->p);
03041 }
03042 if (client->authorized) {
03043 client->authorized = 0;
03044 }
03045
03046 res = aji_initialize(client);
03047
03048 return res;
03049 }
03050
03051
03052
03053
03054
03055
03056
03057 static int aji_get_roster(struct aji_client *client)
03058 {
03059 iks *roster = NULL;
03060 roster = iks_make_iq(IKS_TYPE_GET, IKS_NS_ROSTER);
03061
03062 if (roster) {
03063 iks_insert_attrib(roster, "id", "roster");
03064 aji_set_presence(client, NULL, client->jid->full, client->status, client->statusmessage);
03065 ast_aji_send(client, roster);
03066 }
03067
03068 iks_delete(roster);
03069
03070 return 1;
03071 }
03072
03073
03074
03075
03076
03077
03078
03079
03080 static int aji_client_connect(void *data, ikspak *pak)
03081 {
03082 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
03083 int res = IKS_FILTER_PASS;
03084
03085 if (client) {
03086 if (client->state == AJI_DISCONNECTED) {
03087 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);
03088 client->state = AJI_CONNECTING;
03089 client->jid = (iks_find_cdata(pak->query, "jid")) ? iks_id_new(client->stack, iks_find_cdata(pak->query, "jid")) : client->jid;
03090 if (!client->component) {
03091 aji_get_roster(client);
03092 }
03093 if (client->distribute_events) {
03094 aji_init_event_distribution(client);
03095 }
03096
03097 iks_filter_remove_hook(client->f, aji_client_connect);
03098
03099 res = IKS_FILTER_EAT;
03100 }
03101 } else {
03102 ast_log(LOG_ERROR, "Out of memory.\n");
03103 }
03104
03105 ASTOBJ_UNREF(client, ast_aji_client_destroy);
03106 return res;
03107 }
03108
03109
03110
03111
03112
03113
03114
03115 static int aji_initialize(struct aji_client *client)
03116 {
03117 int connected = IKS_NET_NOCONN;
03118
03119 #ifdef HAVE_OPENSSL
03120
03121 client->stream_flags = 0;
03122 #endif
03123
03124 connected = iks_connect_via(client->p, S_OR(client->serverhost, client->jid->server), client->port, client->component ? client->user : client->jid->server);
03125
03126 if (connected == IKS_NET_NOCONN) {
03127 ast_log(LOG_ERROR, "JABBER ERROR: No Connection\n");
03128 return IKS_HOOK;
03129 } else if (connected == IKS_NET_NODNS) {
03130 ast_log(LOG_ERROR, "JABBER ERROR: No DNS %s for client to %s\n", client->name,
03131 S_OR(client->serverhost, client->jid->server));
03132 return IKS_HOOK;
03133 }
03134
03135 return IKS_OK;
03136 }
03137
03138
03139
03140
03141
03142
03143 int ast_aji_disconnect(struct aji_client *client)
03144 {
03145 if (client) {
03146 ast_verb(4, "JABBER: Disconnecting\n");
03147 #ifdef HAVE_OPENSSL
03148 if (client->stream_flags & SECURE) {
03149 SSL_shutdown(client->ssl_session);
03150 SSL_CTX_free(client->ssl_context);
03151 SSL_free(client->ssl_session);
03152 }
03153 #endif
03154 iks_disconnect(client->p);
03155 iks_parser_delete(client->p);
03156 ASTOBJ_UNREF(client, ast_aji_client_destroy);
03157 }
03158
03159 return 1;
03160 }
03161
03162
03163
03164
03165
03166
03167
03168 static void aji_mwi_cb(const struct ast_event *ast_event, void *data)
03169 {
03170 const char *mailbox;
03171 const char *context;
03172 char oldmsgs[10];
03173 char newmsgs[10];
03174 struct aji_client *client;
03175 if (ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(ast_event, AST_EVENT_IE_EID)))
03176 {
03177
03178 ast_log(LOG_DEBUG, "Returning here\n");
03179 return;
03180 }
03181
03182 client = ASTOBJ_REF((struct aji_client *) data);
03183 mailbox = ast_event_get_ie_str(ast_event, AST_EVENT_IE_MAILBOX);
03184 context = ast_event_get_ie_str(ast_event, AST_EVENT_IE_CONTEXT);
03185 snprintf(oldmsgs, sizeof(oldmsgs), "%d",
03186 ast_event_get_ie_uint(ast_event, AST_EVENT_IE_OLDMSGS));
03187 snprintf(newmsgs, sizeof(newmsgs), "%d",
03188 ast_event_get_ie_uint(ast_event, AST_EVENT_IE_NEWMSGS));
03189 aji_publish_mwi(client, mailbox, context, oldmsgs, newmsgs);
03190 ASTOBJ_UNREF(client, ast_aji_client_destroy);
03191
03192 }
03193
03194
03195
03196
03197
03198
03199 static void aji_devstate_cb(const struct ast_event *ast_event, void *data)
03200 {
03201 const char *device;
03202 const char *device_state;
03203 struct aji_client *client;
03204 if (ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(ast_event, AST_EVENT_IE_EID)))
03205 {
03206
03207 ast_log(LOG_DEBUG, "Returning here\n");
03208 return;
03209 }
03210
03211 client = ASTOBJ_REF((struct aji_client *) data);
03212 device = ast_event_get_ie_str(ast_event, AST_EVENT_IE_DEVICE);
03213 device_state = ast_devstate_str(ast_event_get_ie_uint(ast_event, AST_EVENT_IE_STATE));
03214 aji_publish_device_state(client, device, device_state);
03215 ASTOBJ_UNREF(client, ast_aji_client_destroy);
03216 }
03217
03218
03219
03220
03221
03222
03223 static void aji_init_event_distribution(struct aji_client *client)
03224 {
03225 if (!mwi_sub) {
03226 mwi_sub = ast_event_subscribe(AST_EVENT_MWI, aji_mwi_cb, "aji_mwi_subscription",
03227 client, AST_EVENT_IE_END);
03228 }
03229 if (!device_state_sub) {
03230 if (ast_enable_distributed_devstate()) {
03231 return;
03232 }
03233 device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE_CHANGE,
03234 aji_devstate_cb, "aji_devstate_subscription", client, AST_EVENT_IE_END);
03235 ast_event_dump_cache(device_state_sub);
03236 }
03237
03238 aji_pubsub_subscribe(client, "device_state");
03239 aji_pubsub_subscribe(client, "message_waiting");
03240 iks_filter_add_rule(client->f, aji_handle_pubsub_event, client, IKS_RULE_TYPE,
03241 IKS_PAK_MESSAGE, IKS_RULE_FROM, client->pubsub_node, IKS_RULE_DONE);
03242 iks_filter_add_rule(client->f, aji_handle_pubsub_error, client, IKS_RULE_TYPE,
03243 IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_ERROR, IKS_RULE_DONE);
03244
03245 }
03246
03247
03248
03249
03250
03251
03252 static int aji_handle_pubsub_event(void *data, ikspak *pak)
03253 {
03254 char *item_id, *device_state, *context;
03255 int oldmsgs, newmsgs;
03256 iks *item, *item_content;
03257 struct ast_eid pubsub_eid;
03258 struct ast_event *event;
03259 item = iks_find(iks_find(iks_find(pak->x, "event"), "items"), "item");
03260 if (!item) {
03261 ast_log(LOG_ERROR, "Could not parse incoming PubSub event\n");
03262 return IKS_FILTER_EAT;
03263 }
03264 item_id = iks_find_attrib(item, "id");
03265 item_content = iks_child(item);
03266 ast_str_to_eid(&pubsub_eid, iks_find_attrib(item_content, "eid"));
03267 if (!ast_eid_cmp(&ast_eid_default, &pubsub_eid)) {
03268 ast_log(LOG_DEBUG, "Returning here, eid of incoming event matches ours!\n");
03269 return IKS_FILTER_EAT;
03270 }
03271 if (!strcasecmp(iks_name(item_content), "state")) {
03272 device_state = iks_find_cdata(item, "state");
03273 if (!(event = ast_event_new(AST_EVENT_DEVICE_STATE_CHANGE,
03274 AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, item_id, AST_EVENT_IE_STATE,
03275 AST_EVENT_IE_PLTYPE_UINT, ast_devstate_val(device_state), AST_EVENT_IE_EID,
03276 AST_EVENT_IE_PLTYPE_RAW, &pubsub_eid, sizeof(pubsub_eid),
03277 AST_EVENT_IE_END))) {
03278 return IKS_FILTER_EAT;
03279 }
03280 } else if (!strcasecmp(iks_name(item_content), "mailbox")) {
03281 context = strsep(&item_id, "@");
03282 sscanf(iks_find_cdata(item_content, "OLDMSGS"), "%10d", &oldmsgs);
03283 sscanf(iks_find_cdata(item_content, "NEWMSGS"), "%10d", &newmsgs);
03284 if (!(event = ast_event_new(AST_EVENT_MWI, AST_EVENT_IE_MAILBOX,
03285 AST_EVENT_IE_PLTYPE_STR, item_id, AST_EVENT_IE_CONTEXT,
03286 AST_EVENT_IE_PLTYPE_STR, context, AST_EVENT_IE_OLDMSGS,
03287 AST_EVENT_IE_PLTYPE_UINT, oldmsgs, AST_EVENT_IE_NEWMSGS,
03288 AST_EVENT_IE_PLTYPE_UINT, newmsgs, AST_EVENT_IE_EID, AST_EVENT_IE_PLTYPE_RAW,
03289 &pubsub_eid, sizeof(pubsub_eid), AST_EVENT_IE_END))) {
03290 return IKS_FILTER_EAT;
03291 }
03292 } else {
03293 ast_log(LOG_DEBUG, "Don't know how to handle PubSub event of type %s\n",
03294 iks_name(item_content));
03295 return IKS_FILTER_EAT;
03296 }
03297 ast_event_queue_and_cache(event);
03298 return IKS_FILTER_EAT;
03299 }
03300
03301
03302
03303
03304
03305
03306
03307 static void aji_create_affiliations(struct aji_client *client, const char *node)
03308 {
03309 iks *modify_affiliates = aji_pubsub_iq_create(client, "set");
03310 iks *pubsub, *affiliations, *affiliate;
03311 pubsub = iks_insert(modify_affiliates, "pubsub");
03312 iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub#owner");
03313 affiliations = iks_insert(pubsub, "affiliations");
03314 iks_insert_attrib(affiliations, "node", node);
03315 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
03316 ASTOBJ_RDLOCK(iterator);
03317 affiliate = iks_insert(affiliations, "affiliation");
03318 iks_insert_attrib(affiliate, "jid", iterator->name);
03319 iks_insert_attrib(affiliate, "affiliation", "owner");
03320 ASTOBJ_UNLOCK(iterator);
03321 });
03322 ast_aji_send(client, modify_affiliates);
03323 iks_delete(modify_affiliates);
03324 }
03325
03326
03327
03328
03329
03330
03331
03332 static void aji_pubsub_subscribe(struct aji_client *client, const char *node)
03333 {
03334 iks *request = aji_pubsub_iq_create(client, "set");
03335 iks *pubsub, *subscribe;
03336
03337 pubsub = iks_insert(request, "pubsub");
03338 iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
03339 subscribe = iks_insert(pubsub, "subscribe");
03340 iks_insert_attrib(subscribe, "jid", client->jid->partial);
03341 iks_insert_attrib(subscribe, "node", node);
03342 if (ast_test_flag(&globalflags, AJI_XEP0248)) {
03343 iks *options, *x, *sub_options, *sub_type, *sub_depth;
03344 options = iks_insert(pubsub, "options");
03345 x = iks_insert(options, "x");
03346 iks_insert_attrib(x, "xmlns", "jabber:x:data");
03347 iks_insert_attrib(x, "type", "submit");
03348 sub_options = iks_insert(x, "field");
03349 iks_insert_attrib(sub_options, "var", "FORM_TYPE");
03350 iks_insert_attrib(sub_options, "type", "hidden");
03351 iks_insert_cdata(iks_insert(sub_options, "value"),
03352 "http://jabber.org/protocol/pubsub#subscribe_options", 51);
03353 sub_type = iks_insert(x, "field");
03354 iks_insert_attrib(sub_type, "var", "pubsub#subscription_type");
03355 iks_insert_cdata(iks_insert(sub_type, "value"), "items", 5);
03356 sub_depth = iks_insert(x, "field");
03357 iks_insert_attrib(sub_type, "var", "pubsub#subscription_depth");
03358 iks_insert_cdata(iks_insert(sub_depth, "value"), "all", 3);
03359 }
03360 ast_aji_send(client, request);
03361 iks_delete(request);
03362 }
03363
03364
03365
03366
03367
03368
03369
03370
03371 static iks* aji_build_publish_skeleton(struct aji_client *client, const char *node,
03372 const char *event_type)
03373 {
03374 iks *request = aji_pubsub_iq_create(client, "set");
03375 iks *pubsub, *publish, *item;
03376 pubsub = iks_insert(request, "pubsub");
03377 iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
03378 publish = iks_insert(pubsub, "publish");
03379 if (ast_test_flag(&globalflags, AJI_XEP0248)) {
03380 iks_insert_attrib(publish, "node", node);
03381 } else {
03382 iks_insert_attrib(publish, "node", event_type);
03383 }
03384 item = iks_insert(publish, "item");
03385 iks_insert_attrib(item, "id", node);
03386 return item;
03387
03388 }
03389
03390
03391
03392
03393
03394
03395
03396
03397 static void aji_publish_device_state(struct aji_client *client, const char *device,
03398 const char *device_state)
03399 {
03400 iks *request = aji_build_publish_skeleton(client, device, "device_state");
03401 iks *state;
03402 char eid_str[20];
03403 if (ast_test_flag(&pubsubflags, AJI_PUBSUB_AUTOCREATE)) {
03404 if (ast_test_flag(&pubsubflags, AJI_XEP0248)) {
03405 aji_create_pubsub_node(client, "leaf", device, "device_state");
03406 } else {
03407 aji_create_pubsub_node(client, NULL, device, NULL);
03408 }
03409 }
03410 ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
03411 state = iks_insert(request, "state");
03412 iks_insert_attrib(state, "xmlns", "http://asterisk.org");
03413 iks_insert_attrib(state, "eid", eid_str);
03414 iks_insert_cdata(state, device_state, strlen(device_state));
03415 ast_aji_send(client, iks_root(request));
03416 iks_delete(request);
03417 }
03418
03419
03420
03421
03422
03423
03424
03425
03426 static void aji_publish_mwi(struct aji_client *client, const char *mailbox,
03427 const char *context, const char *oldmsgs, const char *newmsgs)
03428 {
03429 char full_mailbox[AST_MAX_EXTENSION+AST_MAX_CONTEXT];
03430 char eid_str[20];
03431 iks *mailbox_node, *request;
03432 snprintf(full_mailbox, sizeof(full_mailbox), "%s@%s", mailbox, context);
03433 request = aji_build_publish_skeleton(client, full_mailbox, "message_waiting");
03434 ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
03435 mailbox_node = iks_insert(request, "mailbox");
03436 iks_insert_attrib(mailbox_node, "xmlns", "http://asterisk.org");
03437 iks_insert_attrib(mailbox_node, "eid", eid_str);
03438 iks_insert_cdata(iks_insert(mailbox_node, "NEWMSGS"), newmsgs, strlen(newmsgs));
03439 iks_insert_cdata(iks_insert(mailbox_node, "OLDMSGS"), oldmsgs, strlen(oldmsgs));
03440 ast_aji_send(client, iks_root(request));
03441 iks_delete(request);
03442 }
03443
03444
03445
03446
03447
03448
03449
03450 static iks* aji_pubsub_iq_create(struct aji_client *client, const char *type)
03451 {
03452 iks *request = iks_new("iq");
03453
03454 iks_insert_attrib(request, "to", client->pubsub_node);
03455 iks_insert_attrib(request, "from", client->jid->full);
03456 iks_insert_attrib(request, "type", type);
03457 ast_aji_increment_mid(client->mid);
03458 iks_insert_attrib(request, "id", client->mid);
03459 return request;
03460 }
03461
03462 static int aji_handle_pubsub_error(void *data, ikspak *pak)
03463 {
03464 char *node_name;
03465 char *error;
03466 int error_num;
03467 iks *orig_request;
03468 iks *orig_pubsub = iks_find(pak->x, "pubsub");
03469 struct aji_client *client;
03470 if (!orig_pubsub) {
03471 ast_log(LOG_ERROR, "Error isn't a PubSub error, why are we here?\n");
03472 return IKS_FILTER_EAT;
03473 }
03474 orig_request = iks_child(orig_pubsub);
03475 error = iks_find_attrib(iks_find(pak->x, "error"), "code");
03476 node_name = iks_find_attrib(orig_request, "node");
03477 if (!sscanf(error, "%30d", &error_num)) {
03478 return IKS_FILTER_EAT;
03479 }
03480 if (error_num > 399 && error_num < 500 && error_num != 404) {
03481 ast_log(LOG_ERROR,
03482 "Error performing operation on PubSub node %s, %s.\n", node_name, error);
03483 return IKS_FILTER_EAT;
03484 } else if (error_num > 499 && error_num < 600) {
03485 ast_log(LOG_ERROR, "PubSub Server error, %s\n", error);
03486 return IKS_FILTER_EAT;
03487 }
03488
03489 client = ASTOBJ_REF((struct aji_client *) data);
03490
03491 if (!strcasecmp(iks_name(orig_request), "publish")) {
03492 iks *request;
03493 if (ast_test_flag(&pubsubflags, AJI_XEP0248)) {
03494 if (iks_find(iks_find(orig_request, "item"), "state")) {
03495 aji_create_pubsub_leaf(client, "device_state", node_name);
03496 } else if (iks_find(iks_find(orig_request, "item"), "mailbox")) {
03497 aji_create_pubsub_leaf(client, "message_waiting", node_name);
03498 }
03499 } else {
03500 aji_create_pubsub_node(client, NULL, node_name, NULL);
03501 }
03502 request = aji_pubsub_iq_create(client, "set");
03503 iks_insert_node(request, orig_pubsub);
03504 ast_aji_send(client, request);
03505 iks_delete(request);
03506 ASTOBJ_UNREF(client, ast_aji_client_destroy);
03507 return IKS_FILTER_EAT;
03508 } else if (!strcasecmp(iks_name(orig_request), "subscribe")) {
03509 if (ast_test_flag(&pubsubflags, AJI_XEP0248)) {
03510 aji_create_pubsub_collection(client, node_name);
03511 } else {
03512 aji_create_pubsub_node(client, NULL, node_name, NULL);
03513 }
03514 }
03515 ASTOBJ_UNREF(client, ast_aji_client_destroy);
03516 return IKS_FILTER_EAT;
03517 }
03518
03519
03520
03521
03522
03523
03524
03525 static void aji_request_pubsub_nodes(struct aji_client *client, const char *collection)
03526 {
03527 iks *request = aji_build_node_request(client, collection);
03528
03529 iks_filter_add_rule(client->f, aji_receive_node_list, client, IKS_RULE_TYPE,
03530 IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->mid,
03531 IKS_RULE_DONE);
03532 ast_aji_send(client, request);
03533 iks_delete(request);
03534
03535 }
03536
03537
03538
03539
03540
03541
03542
03543 static iks* aji_build_node_request(struct aji_client *client, const char *collection)
03544 {
03545 iks *request = aji_pubsub_iq_create(client, "get");
03546 iks *query;
03547 query = iks_insert(request, "query");
03548 iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#items");
03549 if (collection) {
03550 iks_insert_attrib(query, "node", collection);
03551 }
03552 return request;
03553 }
03554
03555
03556
03557
03558
03559
03560
03561 static int aji_receive_node_list(void *data, ikspak* pak)
03562 {
03563
03564 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
03565 iks *item = NULL;
03566 if (iks_has_children(pak->query)) {
03567 item = iks_first_tag(pak->query);
03568 ast_verbose("Connection %s: %s\nNode name: %s\n", client->name, client->jid->partial,
03569 iks_find_attrib(item, "node"));
03570 while ((item = iks_next_tag(item))) {
03571 ast_verbose("Node name: %s\n", iks_find_attrib(item, "node"));
03572 }
03573 }
03574 if (item) {
03575 iks_delete(item);
03576 }
03577 ASTOBJ_UNREF(client, ast_aji_client_destroy);
03578 return IKS_FILTER_EAT;
03579 }
03580
03581
03582
03583
03584
03585
03586
03587
03588
03589 static char *aji_cli_list_pubsub_nodes(struct ast_cli_entry *e, int cmd, struct
03590 ast_cli_args *a)
03591 {
03592 struct aji_client *client;
03593 const char *name = NULL;
03594 const char *collection = NULL;
03595
03596 switch (cmd) {
03597 case CLI_INIT:
03598 e->command = "jabber list nodes";
03599 e->usage =
03600 "Usage: jabber list nodes <connection> [collection]\n"
03601 " Lists the user's nodes on the respective connection\n"
03602 " ([connection] as configured in jabber.conf.)\n";
03603 return NULL;
03604 case CLI_GENERATE:
03605 return NULL;
03606 }
03607
03608 if (a->argc > 5 || a->argc < 4) {
03609 return CLI_SHOWUSAGE;
03610 } else if (a->argc == 4 || a->argc == 5) {
03611 name = a->argv[3];
03612 }
03613 if (a->argc == 5) {
03614 collection = a->argv[4];
03615 }
03616 if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
03617 ast_cli(a->fd, "Unable to find client '%s'!\n", name);
03618 return CLI_FAILURE;
03619 }
03620
03621 ast_cli(a->fd, "Listing pubsub nodes.\n");
03622 aji_request_pubsub_nodes(client, collection);
03623 ASTOBJ_UNREF(client, ast_aji_client_destroy);
03624 return CLI_SUCCESS;
03625 }
03626
03627
03628
03629
03630
03631
03632
03633
03634 static char *aji_cli_purge_pubsub_nodes(struct ast_cli_entry *e, int cmd, struct
03635 ast_cli_args *a)
03636 {
03637 struct aji_client *client;
03638 const char *name;
03639
03640 switch (cmd) {
03641 case CLI_INIT:
03642 e->command = "jabber purge nodes";
03643 e->usage =
03644 "Usage: jabber purge nodes <connection> <node>\n"
03645 " Purges nodes on PubSub server\n"
03646 " as configured in jabber.conf.\n";
03647 return NULL;
03648 case CLI_GENERATE:
03649 return NULL;
03650 }
03651
03652 if (a->argc != 5) {
03653 return CLI_SHOWUSAGE;
03654 }
03655 name = a->argv[3];
03656
03657 if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
03658 ast_cli(a->fd, "Unable to find client '%s'!\n", name);
03659 return CLI_FAILURE;
03660 }
03661 if (ast_test_flag(&pubsubflags, AJI_XEP0248)) {
03662 aji_pubsub_purge_nodes(client, a->argv[4]);
03663 } else {
03664 aji_delete_pubsub_node(client, a->argv[4]);
03665 }
03666 ASTOBJ_UNREF(client, ast_aji_client_destroy);
03667 return CLI_SUCCESS;
03668 }
03669
03670 static void aji_pubsub_purge_nodes(struct aji_client *client, const char* collection_name)
03671 {
03672 iks *request = aji_build_node_request(client, collection_name);
03673 ast_aji_send(client, request);
03674 iks_filter_add_rule(client->f, aji_delete_node_list, client, IKS_RULE_TYPE,
03675 IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->mid,
03676 IKS_RULE_DONE);
03677 ast_aji_send(client, request);
03678 iks_delete(request);
03679 }
03680
03681
03682
03683
03684
03685
03686
03687 static int aji_delete_node_list(void *data, ikspak* pak)
03688 {
03689
03690 struct aji_client *client = ASTOBJ_REF((struct aji_client *) data);
03691 iks *item = NULL;
03692 if (iks_has_children(pak->query)) {
03693 item = iks_first_tag(pak->query);
03694 ast_log(LOG_WARNING, "Connection: %s Node name: %s\n", client->jid->partial,
03695 iks_find_attrib(item, "node"));
03696 while ((item = iks_next_tag(item))) {
03697 aji_delete_pubsub_node(client, iks_find_attrib(item, "node"));
03698 }
03699 }
03700 if (item) {
03701 iks_delete(item);
03702 }
03703 return IKS_FILTER_EAT;
03704 }
03705
03706
03707
03708
03709
03710
03711
03712
03713
03714 static char *aji_cli_delete_pubsub_node(struct ast_cli_entry *e, int cmd, struct
03715 ast_cli_args *a)
03716 {
03717 struct aji_client *client;
03718 const char *name;
03719
03720 switch (cmd) {
03721 case CLI_INIT:
03722 e->command = "jabber delete node";
03723 e->usage =
03724 "Usage: jabber delete node <connection> <node>\n"
03725 " Deletes a node on PubSub server\n"
03726 " as configured in jabber.conf.\n";
03727 return NULL;
03728 case CLI_GENERATE:
03729 return NULL;
03730 }
03731
03732 if (a->argc != 5) {
03733 return CLI_SHOWUSAGE;
03734 }
03735 name = a->argv[3];
03736
03737 if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
03738 ast_cli(a->fd, "Unable to find client '%s'!\n", name);
03739 return CLI_FAILURE;
03740 }
03741 aji_delete_pubsub_node(client, a->argv[4]);
03742 ASTOBJ_UNREF(client, ast_aji_client_destroy);
03743 return CLI_SUCCESS;
03744 }
03745
03746
03747
03748
03749
03750
03751
03752 static void aji_delete_pubsub_node(struct aji_client *client, const char *node_name)
03753 {
03754 iks *request = aji_pubsub_iq_create(client, "set");
03755 iks *pubsub, *delete;
03756 pubsub = iks_insert(request, "pubsub");
03757 iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub#owner");
03758 delete = iks_insert(pubsub, "delete");
03759 iks_insert_attrib(delete, "node", node_name);
03760 ast_aji_send(client, request);
03761 }
03762
03763
03764
03765
03766
03767
03768
03769 static void aji_create_pubsub_collection(struct aji_client *client, const char
03770 *collection_name)
03771 {
03772 aji_create_pubsub_node(client, "collection", collection_name, NULL);
03773 }
03774
03775
03776
03777
03778
03779
03780
03781
03782 static void aji_create_pubsub_leaf(struct aji_client *client, const char *collection_name,
03783 const char *leaf_name)
03784 {
03785 aji_create_pubsub_node(client, "leaf", leaf_name, collection_name);
03786 }
03787
03788
03789
03790
03791
03792
03793
03794
03795 static iks* aji_create_pubsub_node(struct aji_client *client, const char *node_type, const
03796 char *name, const char *collection_name)
03797 {
03798 iks *node = aji_pubsub_iq_create(client, "set");
03799 iks *pubsub, *create;
03800 pubsub = iks_insert(node, "pubsub");
03801 iks_insert_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
03802 create = iks_insert(pubsub, "create");
03803 iks_insert_attrib(create, "node", name);
03804 aji_build_node_config(pubsub, node_type, collection_name);
03805 ast_aji_send(client, node);
03806 aji_create_affiliations(client, name);
03807 iks_delete(node);
03808 return 0;
03809 }
03810
03811
03812
03813 static iks* aji_build_node_config(iks *pubsub, const char *node_type, const char *collection_name)
03814 {
03815 iks *configure, *x, *field_owner, *field_node_type, *field_node_config,
03816 *field_deliver_payload, *field_persist_items, *field_access_model,
03817 *field_pubsub_collection;
03818 configure = iks_insert(pubsub, "configure");
03819 x = iks_insert(configure, "x");
03820 iks_insert_attrib(x, "xmlns", "jabber:x:data");
03821 iks_insert_attrib(x, "type", "submit");
03822 field_owner = iks_insert(x, "field");
03823 iks_insert_attrib(field_owner, "var", "FORM_TYPE");
03824 iks_insert_attrib(field_owner, "type", "hidden");
03825 iks_insert_cdata(iks_insert(field_owner, "value"),
03826 "http://jabber.org/protocol/pubsub#owner", 39);
03827 if (node_type) {
03828 field_node_type = iks_insert(x, "field");
03829 iks_insert_attrib(field_node_type, "var", "pubsub#node_type");
03830 iks_insert_cdata(iks_insert(field_node_type, "value"), node_type, strlen(node_type));
03831 }
03832 field_node_config = iks_insert(x, "field");
03833 iks_insert_attrib(field_node_config, "var", "FORM_TYPE");
03834 iks_insert_attrib(field_node_config, "type", "hidden");
03835 iks_insert_cdata(iks_insert(field_node_config, "value"),
03836 "http://jabber.org/protocol/pubsub#node_config", 45);
03837 field_deliver_payload = iks_insert(x, "field");
03838 iks_insert_attrib(field_deliver_payload, "var", "pubsub#deliver_payloads");
03839 iks_insert_cdata(iks_insert(field_deliver_payload, "value"), "1", 1);
03840 field_persist_items = iks_insert(x, "field");
03841 iks_insert_attrib(field_persist_items, "var", "pubsub#persist_items");
03842 iks_insert_cdata(iks_insert(field_persist_items, "value"), "1", 1);
03843 field_access_model = iks_insert(x, "field");
03844 iks_insert_attrib(field_access_model, "var", "pubsub#access_model");
03845 iks_insert_cdata(iks_insert(field_access_model, "value"), "whitelist", 9);
03846 if (node_type && !strcasecmp(node_type, "leaf")) {
03847 field_pubsub_collection = iks_insert(x, "field");
03848 iks_insert_attrib(field_pubsub_collection, "var", "pubsub#collection");
03849 iks_insert_cdata(iks_insert(field_pubsub_collection, "value"), collection_name,
03850 strlen(collection_name));
03851 }
03852 return configure;
03853 }
03854
03855
03856
03857
03858
03859
03860
03861 static char *aji_cli_create_collection(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03862 {
03863 struct aji_client *client;
03864 const char *name;
03865 const char *collection_name;
03866
03867 switch (cmd) {
03868 case CLI_INIT:
03869 e->command = "jabber create collection";
03870 e->usage =
03871 "Usage: jabber create collection <connection> <collection>\n"
03872 " Creates a PubSub collection node using the account\n"
03873 " as configured in jabber.conf.\n";
03874 return NULL;
03875 case CLI_GENERATE:
03876 return NULL;
03877 }
03878
03879 if (a->argc != 5) {
03880 return CLI_SHOWUSAGE;
03881 }
03882 name = a->argv[3];
03883 collection_name = a->argv[4];
03884
03885 if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
03886 ast_cli(a->fd, "Unable to find client '%s'!\n", name);
03887 return CLI_FAILURE;
03888 }
03889
03890 ast_cli(a->fd, "Creating test PubSub node collection.\n");
03891 aji_create_pubsub_collection(client, collection_name);
03892 ASTOBJ_UNREF(client, ast_aji_client_destroy);
03893 return CLI_SUCCESS;
03894 }
03895
03896
03897
03898
03899
03900 static char *aji_cli_create_leafnode(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03901 {
03902 struct aji_client *client;
03903 const char *name;
03904 const char *collection_name;
03905 const char *leaf_name;
03906
03907 switch (cmd) {
03908 case CLI_INIT:
03909 e->command = "jabber create leaf";
03910 e->usage =
03911 "Usage: jabber create leaf <connection> <collection> <leaf>\n"
03912 " Creates a PubSub leaf node using the account\n"
03913 " as configured in jabber.conf.\n";
03914 return NULL;
03915 case CLI_GENERATE:
03916 return NULL;
03917 }
03918
03919 if (a->argc != 6) {
03920 return CLI_SHOWUSAGE;
03921 }
03922 name = a->argv[3];
03923 collection_name = a->argv[4];
03924 leaf_name = a->argv[5];
03925
03926 if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
03927 ast_cli(a->fd, "Unable to find client '%s'!\n", name);
03928 return CLI_FAILURE;
03929 }
03930
03931 ast_cli(a->fd, "Creating test PubSub node collection.\n");
03932 aji_create_pubsub_leaf(client, collection_name, leaf_name);
03933 ASTOBJ_UNREF(client, ast_aji_client_destroy);
03934 return CLI_SUCCESS;
03935 }
03936
03937
03938
03939
03940
03941
03942
03943
03944
03945
03946
03947
03948
03949 static void aji_set_presence(struct aji_client *client, char *to, char *from, int level, char *desc)
03950 {
03951 iks *presence = iks_make_pres(level, desc);
03952 iks *cnode = iks_new("c");
03953 iks *priority = iks_new("priority");
03954 char priorityS[10];
03955
03956 if (presence && cnode && client && priority) {
03957 if (to) {
03958 iks_insert_attrib(presence, "to", to);
03959 }
03960 if (from) {
03961 iks_insert_attrib(presence, "from", from);
03962 }
03963 snprintf(priorityS, sizeof(priorityS), "%d", client->priority);
03964 iks_insert_cdata(priority, priorityS, strlen(priorityS));
03965 iks_insert_node(presence, priority);
03966 iks_insert_attrib(cnode, "node", "http://www.asterisk.org/xmpp/client/caps");
03967 iks_insert_attrib(cnode, "ver", "asterisk-xmpp");
03968 iks_insert_attrib(cnode, "ext", "voice-v1");
03969 iks_insert_attrib(cnode, "xmlns", "http://jabber.org/protocol/caps");
03970 iks_insert_node(presence, cnode);
03971 ast_aji_send(client, presence);
03972 } else {
03973 ast_log(LOG_ERROR, "Out of memory.\n");
03974 }
03975
03976 iks_delete(cnode);
03977 iks_delete(presence);
03978 iks_delete(priority);
03979 }
03980
03981
03982
03983
03984
03985
03986
03987
03988
03989
03990
03991 static int aji_set_group_presence(struct aji_client *client, char *room, int level, char *nick, char *desc)
03992 {
03993 int res = 0;
03994 iks *presence = NULL, *x = NULL;
03995 char from[AJI_MAX_JIDLEN];
03996 char roomid[AJI_MAX_JIDLEN];
03997
03998 presence = iks_make_pres(level, NULL);
03999 x = iks_new("x");
04000
04001 if (client->component) {
04002 snprintf(from, AJI_MAX_JIDLEN, "%s@%s/%s", nick, client->jid->full, nick);
04003 snprintf(roomid, AJI_MAX_JIDLEN, "%s/%s", room, nick);
04004 } else {
04005 snprintf(from, AJI_MAX_JIDLEN, "%s", client->jid->full);
04006 snprintf(roomid, AJI_MAX_JIDLEN, "%s/%s", room, nick ? nick : client->jid->user);
04007 }
04008
04009 if (!presence || !x || !client) {
04010 ast_log(LOG_ERROR, "Out of memory.\n");
04011 res = -1;
04012 goto safeout;
04013 } else {
04014 iks_insert_attrib(presence, "to", roomid);
04015 iks_insert_attrib(presence, "from", from);
04016 iks_insert_attrib(x, "xmlns", MUC_NS);
04017 iks_insert_node(presence, x);
04018 res = ast_aji_send(client, presence);
04019 }
04020
04021 safeout:
04022 iks_delete(presence);
04023 iks_delete(x);
04024 return res;
04025 }
04026
04027
04028
04029
04030
04031
04032 static char *aji_do_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04033 {
04034 switch (cmd) {
04035 case CLI_INIT:
04036 e->command = "jabber set debug {on|off}";
04037 e->usage =
04038 "Usage: jabber set debug {on|off}\n"
04039 " Enables/disables dumping of XMPP/Jabber packets for debugging purposes.\n";
04040 return NULL;
04041 case CLI_GENERATE:
04042 return NULL;
04043 }
04044
04045 if (a->argc != e->args) {
04046 return CLI_SHOWUSAGE;
04047 }
04048
04049 if (!strncasecmp(a->argv[e->args - 1], "on", 2)) {
04050 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04051 ASTOBJ_RDLOCK(iterator);
04052 iterator->debug = 1;
04053 ASTOBJ_UNLOCK(iterator);
04054 });
04055 ast_cli(a->fd, "Jabber Debugging Enabled.\n");
04056 return CLI_SUCCESS;
04057 } else if (!strncasecmp(a->argv[e->args - 1], "off", 3)) {
04058 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04059 ASTOBJ_RDLOCK(iterator);
04060 iterator->debug = 0;
04061 ASTOBJ_UNLOCK(iterator);
04062 });
04063 ast_cli(a->fd, "Jabber Debugging Disabled.\n");
04064 return CLI_SUCCESS;
04065 }
04066 return CLI_SHOWUSAGE;
04067 }
04068
04069
04070
04071
04072
04073
04074 static char *aji_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04075 {
04076 switch (cmd) {
04077 case CLI_INIT:
04078 e->command = "jabber reload";
04079 e->usage =
04080 "Usage: jabber reload\n"
04081 " Reloads the Jabber module.\n";
04082 return NULL;
04083 case CLI_GENERATE:
04084 return NULL;
04085 }
04086
04087 aji_reload(1);
04088 ast_cli(a->fd, "Jabber Reloaded.\n");
04089 return CLI_SUCCESS;
04090 }
04091
04092
04093
04094
04095
04096
04097 static char *aji_show_clients(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04098 {
04099 char *status;
04100 int count = 0;
04101
04102 switch (cmd) {
04103 case CLI_INIT:
04104 e->command = "jabber show connections";
04105 e->usage =
04106 "Usage: jabber show connections\n"
04107 " Shows state of client and component connections\n";
04108 return NULL;
04109 case CLI_GENERATE:
04110 return NULL;
04111 }
04112
04113 ast_cli(a->fd, "Jabber Users and their status:\n");
04114 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04115 ASTOBJ_RDLOCK(iterator);
04116 count++;
04117 switch (iterator->state) {
04118 case AJI_DISCONNECTED:
04119 status = "Disconnected";
04120 break;
04121 case AJI_CONNECTING:
04122 status = "Connecting";
04123 break;
04124 case AJI_CONNECTED:
04125 status = "Connected";
04126 break;
04127 default:
04128 status = "Unknown";
04129 }
04130 ast_cli(a->fd, " [%s] %s - %s\n", iterator->name, iterator->user, status);
04131 ASTOBJ_UNLOCK(iterator);
04132 });
04133 ast_cli(a->fd, "----\n");
04134 ast_cli(a->fd, " Number of users: %d\n", count);
04135 return CLI_SUCCESS;
04136 }
04137
04138
04139
04140
04141
04142
04143 static char *aji_show_buddies(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04144 {
04145 struct aji_resource *resource;
04146 struct aji_client *client;
04147
04148 switch (cmd) {
04149 case CLI_INIT:
04150 e->command = "jabber show buddies";
04151 e->usage =
04152 "Usage: jabber show buddies\n"
04153 " Shows buddy lists of our clients\n";
04154 return NULL;
04155 case CLI_GENERATE:
04156 return NULL;
04157 }
04158
04159 ast_cli(a->fd, "Jabber buddy lists\n");
04160 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04161 ast_cli(a->fd, "Client: %s\n", iterator->user);
04162 client = iterator;
04163 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
04164 ASTOBJ_RDLOCK(iterator);
04165 ast_cli(a->fd, "\tBuddy:\t%s\n", iterator->name);
04166 if (!iterator->resources)
04167 ast_cli(a->fd, "\t\tResource: None\n");
04168 for (resource = iterator->resources; resource; resource = resource->next) {
04169 ast_cli(a->fd, "\t\tResource: %s\n", resource->resource);
04170 if (resource->cap) {
04171 ast_cli(a->fd, "\t\t\tnode: %s\n", resource->cap->parent->node);
04172 ast_cli(a->fd, "\t\t\tversion: %s\n", resource->cap->version);
04173 ast_cli(a->fd, "\t\t\tJingle capable: %s\n", resource->cap->jingle ? "yes" : "no");
04174 }
04175 ast_cli(a->fd, "\t\tStatus: %d\n", resource->status);
04176 ast_cli(a->fd, "\t\tPriority: %d\n", resource->priority);
04177 }
04178 ASTOBJ_UNLOCK(iterator);
04179 });
04180 iterator = client;
04181 });
04182 return CLI_SUCCESS;
04183 }
04184
04185
04186
04187
04188
04189
04190 static char *aji_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04191 {
04192 struct aji_client *client;
04193 struct aji_resource *resource;
04194 const char *name;
04195 struct aji_message *tmp;
04196
04197 switch (cmd) {
04198 case CLI_INIT:
04199 e->command = "jabber test";
04200 e->usage =
04201 "Usage: jabber test <connection>\n"
04202 " Sends test message for debugging purposes. A specific client\n"
04203 " as configured in jabber.conf must be specified.\n";
04204 return NULL;
04205 case CLI_GENERATE:
04206 return NULL;
04207 }
04208
04209 if (a->argc != 3) {
04210 return CLI_SHOWUSAGE;
04211 }
04212 name = a->argv[2];
04213
04214 if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
04215 ast_cli(a->fd, "Unable to find client '%s'!\n", name);
04216 return CLI_FAILURE;
04217 }
04218
04219
04220 ast_aji_send_chat(client, "mogorman@astjab.org", "blahblah");
04221 ASTOBJ_CONTAINER_TRAVERSE(&client->buddies, 1, {
04222 ASTOBJ_RDLOCK(iterator);
04223 ast_verbose("User: %s\n", iterator->name);
04224 for (resource = iterator->resources; resource; resource = resource->next) {
04225 ast_verbose("Resource: %s\n", resource->resource);
04226 if (resource->cap) {
04227 ast_verbose(" client: %s\n", resource->cap->parent->node);
04228 ast_verbose(" version: %s\n", resource->cap->version);
04229 ast_verbose(" Jingle Capable: %d\n", resource->cap->jingle);
04230 }
04231 ast_verbose(" Priority: %d\n", resource->priority);
04232 ast_verbose(" Status: %d\n", resource->status);
04233 ast_verbose(" Message: %s\n", S_OR(resource->description, ""));
04234 }
04235 ASTOBJ_UNLOCK(iterator);
04236 });
04237 ast_verbose("\nOooh a working message stack!\n");
04238 AST_LIST_LOCK(&client->messages);
04239 AST_LIST_TRAVERSE(&client->messages, tmp, list) {
04240
04241 }
04242 AST_LIST_UNLOCK(&client->messages);
04243 ASTOBJ_UNREF(client, ast_aji_client_destroy);
04244
04245 return CLI_SUCCESS;
04246 }
04247
04248
04249
04250
04251
04252
04253
04254
04255
04256 static int aji_create_client(char *label, struct ast_variable *var, int debug)
04257 {
04258 char *resource;
04259 struct aji_client *client = NULL;
04260 int flag = 0;
04261
04262 client = ASTOBJ_CONTAINER_FIND(&clients, label);
04263 if (!client) {
04264 flag = 1;
04265 client = ast_calloc(1, sizeof(*client));
04266 if (!client) {
04267 ast_log(LOG_ERROR, "Out of memory!\n");
04268 return 0;
04269 }
04270 ASTOBJ_INIT(client);
04271 ASTOBJ_WRLOCK(client);
04272 ASTOBJ_CONTAINER_INIT(&client->buddies);
04273 } else {
04274 ASTOBJ_WRLOCK(client);
04275 ASTOBJ_UNMARK(client);
04276 }
04277 ASTOBJ_CONTAINER_MARKALL(&client->buddies);
04278 ast_copy_string(client->name, label, sizeof(client->name));
04279 ast_copy_string(client->mid, "aaaaa", sizeof(client->mid));
04280
04281
04282 client->debug = debug;
04283 ast_copy_flags(&client->flags, &globalflags, AST_FLAGS_ALL);
04284 client->port = 5222;
04285 client->usetls = 1;
04286 client->usesasl = 1;
04287 client->forcessl = 0;
04288 client->keepalive = 1;
04289 client->timeout = 50;
04290 client->message_timeout = 5;
04291 client->distribute_events = 0;
04292 AST_LIST_HEAD_INIT(&client->messages);
04293 client->component = 0;
04294 ast_copy_string(client->statusmessage, "Online and Available", sizeof(client->statusmessage));
04295 client->priority = 0;
04296 client->status = IKS_SHOW_AVAILABLE;
04297
04298 if (flag) {
04299 client->authorized = 0;
04300 client->state = AJI_DISCONNECTED;
04301 }
04302 while (var) {
04303 if (!strcasecmp(var->name, "username")) {
04304 ast_copy_string(client->user, var->value, sizeof(client->user));
04305 } else if (!strcasecmp(var->name, "serverhost")) {
04306 ast_copy_string(client->serverhost, var->value, sizeof(client->serverhost));
04307 } else if (!strcasecmp(var->name, "secret")) {
04308 ast_copy_string(client->password, var->value, sizeof(client->password));
04309 } else if (!strcasecmp(var->name, "statusmessage")) {
04310 ast_copy_string(client->statusmessage, var->value, sizeof(client->statusmessage));
04311 } else if (!strcasecmp(var->name, "port")) {
04312 client->port = atoi(var->value);
04313 } else if (!strcasecmp(var->name, "timeout")) {
04314 client->message_timeout = atoi(var->value);
04315 } else if (!strcasecmp(var->name, "debug")) {
04316 client->debug = (ast_false(var->value)) ? 0 : 1;
04317 } else if (!strcasecmp(var->name, "type")) {
04318 if (!strcasecmp(var->value, "component")) {
04319 client->component = 1;
04320 if (client->distribute_events) {
04321 ast_log(LOG_ERROR, "Client cannot be configured to be both a component and to distribute events! Event distribution will be disabled.\n");
04322 client->distribute_events = 0;
04323 }
04324 }
04325 } else if (!strcasecmp(var->name, "distribute_events")) {
04326 if (ast_true(var->value)) {
04327 if (client->component) {
04328 ast_log(LOG_ERROR, "Client cannot be configured to be both a component and to distribute events! Event distribution will be disabled.\n");
04329 } else {
04330 if (ast_test_flag(&pubsubflags, AJI_PUBSUB)) {
04331 ast_log(LOG_ERROR, "Only one connection can be configured for distributed events.\n");
04332 } else {
04333 ast_set_flag(&pubsubflags, AJI_PUBSUB);
04334 client->distribute_events = 1;
04335 }
04336 }
04337 }
04338 } else if (!strcasecmp(var->name, "pubsub_node")) {
04339 ast_copy_string(client->pubsub_node, var->value, sizeof(client->pubsub_node));
04340 } else if (!strcasecmp(var->name, "usetls")) {
04341 client->usetls = (ast_false(var->value)) ? 0 : 1;
04342 } else if (!strcasecmp(var->name, "usesasl")) {
04343 client->usesasl = (ast_false(var->value)) ? 0 : 1;
04344 } else if (!strcasecmp(var->name, "forceoldssl")) {
04345 client->forcessl = (ast_false(var->value)) ? 0 : 1;
04346 } else if (!strcasecmp(var->name, "keepalive")) {
04347 client->keepalive = (ast_false(var->value)) ? 0 : 1;
04348 } else if (!strcasecmp(var->name, "autoprune")) {
04349 ast_set2_flag(&client->flags, ast_true(var->value), AJI_AUTOPRUNE);
04350 } else if (!strcasecmp(var->name, "autoregister")) {
04351 ast_set2_flag(&client->flags, ast_true(var->value), AJI_AUTOREGISTER);
04352 } else if (!strcasecmp(var->name, "auth_policy")) {
04353 if (!strcasecmp(var->value, "accept")) {
04354 ast_set_flag(&client->flags, AJI_AUTOACCEPT);
04355 } else {
04356 ast_clear_flag(&client->flags, AJI_AUTOACCEPT);
04357 }
04358 } else if (!strcasecmp(var->name, "buddy")) {
04359 aji_create_buddy((char *)var->value, client);
04360 } else if (!strcasecmp(var->name, "priority")) {
04361 client->priority = atoi(var->value);
04362 } else if (!strcasecmp(var->name, "status")) {
04363 if (!strcasecmp(var->value, "unavailable")) {
04364 client->status = IKS_SHOW_UNAVAILABLE;
04365 } else if (!strcasecmp(var->value, "available")
04366 || !strcasecmp(var->value, "online")) {
04367 client->status = IKS_SHOW_AVAILABLE;
04368 } else if (!strcasecmp(var->value, "chat")
04369 || !strcasecmp(var->value, "chatty")) {
04370 client->status = IKS_SHOW_CHAT;
04371 } else if (!strcasecmp(var->value, "away")) {
04372 client->status = IKS_SHOW_AWAY;
04373 } else if (!strcasecmp(var->value, "xa")
04374 || !strcasecmp(var->value, "xaway")) {
04375 client->status = IKS_SHOW_XA;
04376 } else if (!strcasecmp(var->value, "dnd")) {
04377 client->status = IKS_SHOW_DND;
04378 } else if (!strcasecmp(var->value, "invisible")) {
04379 #ifdef IKS_SHOW_INVISIBLE
04380 client->status = IKS_SHOW_INVISIBLE;
04381 #else
04382 ast_log(LOG_WARNING, "Your iksemel doesn't support invisible status: falling back to DND\n");
04383 client->status = IKS_SHOW_DND;
04384 #endif
04385 } else {
04386 ast_log(LOG_WARNING, "Unknown presence status: %s\n", var->value);
04387 }
04388 }
04389
04390
04391
04392
04393 var = var->next;
04394 }
04395 if (!flag) {
04396 ASTOBJ_UNLOCK(client);
04397 ASTOBJ_UNREF(client, ast_aji_client_destroy);
04398 return 1;
04399 }
04400
04401 ast_copy_string(client->name_space, (client->component) ? "jabber:component:accept" : "jabber:client", sizeof(client->name_space));
04402 client->p = iks_stream_new(client->name_space, client, aji_act_hook);
04403 if (!client->p) {
04404 ast_log(LOG_ERROR, "Failed to create stream for client '%s'!\n", client->name);
04405 return 0;
04406 }
04407 client->stack = iks_stack_new(8192, 8192);
04408 if (!client->stack) {
04409 ast_log(LOG_ERROR, "Failed to allocate stack for client '%s'\n", client->name);
04410 return 0;
04411 }
04412 client->f = iks_filter_new();
04413 if (!client->f) {
04414 ast_log(LOG_ERROR, "Failed to create filter for client '%s'\n", client->name);
04415 return 0;
04416 }
04417 if (!strchr(client->user, '/') && !client->component) {
04418 resource = NULL;
04419 if (asprintf(&resource, "%s/asterisk", client->user) >= 0) {
04420 client->jid = iks_id_new(client->stack, resource);
04421 ast_free(resource);
04422 }
04423 } else {
04424 client->jid = iks_id_new(client->stack, client->user);
04425 }
04426 if (client->component) {
04427 iks_filter_add_rule(client->f, aji_dinfo_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
04428 iks_filter_add_rule(client->f, aji_ditems_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#items", IKS_RULE_DONE);
04429 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);
04430 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);
04431 } else {
04432 iks_filter_add_rule(client->f, aji_client_info_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
04433 }
04434
04435 iks_set_log_hook(client->p, aji_log_hook);
04436 ASTOBJ_UNLOCK(client);
04437 ASTOBJ_CONTAINER_LINK(&clients, client);
04438 return 1;
04439 }
04440
04441
04442
04443 #if 0
04444
04445
04446
04447
04448
04449
04450 static int aji_create_transport(char *label, struct aji_client *client)
04451 {
04452 char *server = NULL, *buddyname = NULL, *user = NULL, *pass = NULL;
04453 struct aji_buddy *buddy = NULL;
04454 int needs_unref = 1;
04455
04456 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies,label);
04457 if (!buddy) {
04458 needs_unref = 0;
04459 buddy = ast_calloc(1, sizeof(*buddy));
04460 if (!buddy) {
04461 ast_log(LOG_WARNING, "Out of memory\n");
04462 return 0;
04463 }
04464 ASTOBJ_INIT(buddy);
04465 }
04466 ASTOBJ_WRLOCK(buddy);
04467 server = label;
04468 if ((buddyname = strchr(label, ','))) {
04469 *buddyname = '\0';
04470 buddyname++;
04471 if (buddyname && buddyname[0] != '\0') {
04472 if ((user = strchr(buddyname, ','))) {
04473 *user = '\0';
04474 user++;
04475 if (user && user[0] != '\0') {
04476 if ((pass = strchr(user, ','))) {
04477 *pass = '\0';
04478 pass++;
04479 ast_copy_string(buddy->pass, pass, sizeof(buddy->pass));
04480 ast_copy_string(buddy->user, user, sizeof(buddy->user));
04481 ast_copy_string(buddy->name, buddyname, sizeof(buddy->name));
04482 ast_copy_string(buddy->server, server, sizeof(buddy->server));
04483 if (needs_unref) {
04484 ASTOBJ_UNMARK(buddy);
04485 ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
04486 }
04487 return 1;
04488 }
04489 }
04490 }
04491 }
04492 }
04493 ASTOBJ_UNLOCK(buddy);
04494 if (needs_unref) {
04495 ASTOBJ_UNMARK(buddy);
04496 ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
04497 } else {
04498 ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
04499 }
04500 return 0;
04501 }
04502 #endif
04503
04504
04505
04506
04507
04508
04509
04510
04511 static int aji_create_buddy(char *label, struct aji_client *client)
04512 {
04513 struct aji_buddy *buddy = NULL;
04514 int needs_unref = 1;
04515 buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, label);
04516 if (!buddy) {
04517 needs_unref = 0;
04518 buddy = ast_calloc(1, sizeof(*buddy));
04519 if (!buddy) {
04520 ast_log(LOG_WARNING, "Out of memory\n");
04521 return 0;
04522 }
04523 ASTOBJ_INIT(buddy);
04524 }
04525 ASTOBJ_WRLOCK(buddy);
04526 ast_copy_string(buddy->name, label, sizeof(buddy->name));
04527 ASTOBJ_UNLOCK(buddy);
04528 if (needs_unref) {
04529 ASTOBJ_UNMARK(buddy);
04530 ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
04531 } else {
04532 ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
04533 }
04534 return 1;
04535 }
04536
04537
04538 static int aji_load_config(int reload)
04539 {
04540 char *cat = NULL;
04541 int debug = 0;
04542 struct ast_config *cfg = NULL;
04543 struct ast_variable *var = NULL;
04544 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
04545
04546 if ((cfg = ast_config_load(JABBER_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
04547 return -1;
04548 }
04549
04550
04551 ast_set_flag(&globalflags, AJI_AUTOREGISTER | AJI_AUTOACCEPT);
04552
04553 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
04554 ast_log(LOG_WARNING, "No such configuration file %s\n", JABBER_CONFIG);
04555 return 0;
04556 }
04557
04558 cat = ast_category_browse(cfg, NULL);
04559 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
04560 if (!strcasecmp(var->name, "debug")) {
04561 debug = (ast_false(ast_variable_retrieve(cfg, "general", "debug"))) ? 0 : 1;
04562 } else if (!strcasecmp(var->name, "autoprune")) {
04563 ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOPRUNE);
04564 } else if (!strcasecmp(var->name, "autoregister")) {
04565 ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOREGISTER);
04566 } else if (!strcasecmp(var->name, "collection_nodes")) {
04567 ast_set2_flag(&pubsubflags, ast_true(var->value), AJI_XEP0248);
04568 } else if (!strcasecmp(var->name, "pubsub_autocreate")) {
04569 ast_set2_flag(&pubsubflags, ast_true(var->value), AJI_PUBSUB_AUTOCREATE);
04570 } else if (!strcasecmp(var->name, "auth_policy")) {
04571 if (!strcasecmp(var->value, "accept")) {
04572 ast_set_flag(&globalflags, AJI_AUTOACCEPT);
04573 } else {
04574 ast_clear_flag(&globalflags, AJI_AUTOACCEPT);
04575 }
04576 }
04577 }
04578
04579 while (cat) {
04580 if (strcasecmp(cat, "general")) {
04581 var = ast_variable_browse(cfg, cat);
04582 aji_create_client(cat, var, debug);
04583 }
04584 cat = ast_category_browse(cfg, cat);
04585 }
04586 ast_config_destroy(cfg);
04587 return 1;
04588 }
04589
04590
04591
04592
04593
04594
04595
04596 struct aji_client *ast_aji_get_client(const char *name)
04597 {
04598 struct aji_client *client = NULL;
04599 char *aux = NULL;
04600
04601 client = ASTOBJ_CONTAINER_FIND(&clients, name);
04602 if (!client && strchr(name, '@')) {
04603 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04604 aux = ast_strdupa(iterator->user);
04605 if (strchr(aux, '/')) {
04606
04607 aux = strsep(&aux, "/");
04608 }
04609 if (!strncasecmp(aux, name, strlen(aux))) {
04610 client = ASTOBJ_REF(iterator);
04611 }
04612 });
04613 }
04614
04615 return client;
04616 }
04617
04618 struct aji_client_container *ast_aji_get_clients(void)
04619 {
04620 return &clients;
04621 }
04622
04623
04624
04625
04626
04627
04628
04629
04630 static int manager_jabber_send(struct mansession *s, const struct message *m)
04631 {
04632 struct aji_client *client = NULL;
04633 const char *id = astman_get_header(m, "ActionID");
04634 const char *jabber = astman_get_header(m, "Jabber");
04635 const char *screenname = astman_get_header(m, "ScreenName");
04636 const char *message = astman_get_header(m, "Message");
04637
04638 if (ast_strlen_zero(jabber)) {
04639 astman_send_error(s, m, "No transport specified");
04640 return 0;
04641 }
04642 if (ast_strlen_zero(screenname)) {
04643 astman_send_error(s, m, "No ScreenName specified");
04644 return 0;
04645 }
04646 if (ast_strlen_zero(message)) {
04647 astman_send_error(s, m, "No Message specified");
04648 return 0;
04649 }
04650
04651 astman_send_ack(s, m, "Attempting to send Jabber Message");
04652 client = ast_aji_get_client(jabber);
04653 if (!client) {
04654 astman_send_error(s, m, "Could not find Sender");
04655 return 0;
04656 }
04657 if (strchr(screenname, '@') && message) {
04658 ast_aji_send_chat(client, screenname, message);
04659 astman_append(s, "Response: Success\r\n");
04660 } else {
04661 astman_append(s, "Response: Error\r\n");
04662 }
04663 ASTOBJ_UNREF(client, ast_aji_client_destroy);
04664 if (!ast_strlen_zero(id)) {
04665 astman_append(s, "ActionID: %s\r\n", id);
04666 }
04667 astman_append(s, "\r\n");
04668 return 0;
04669 }
04670
04671
04672
04673
04674
04675 static int aji_reload(int reload)
04676 {
04677 int res;
04678
04679 ASTOBJ_CONTAINER_MARKALL(&clients);
04680 if (!(res = aji_load_config(reload))) {
04681 ast_log(LOG_ERROR, "JABBER: Failed to load config.\n");
04682 return 0;
04683 } else if (res == -1)
04684 return 1;
04685
04686 ASTOBJ_CONTAINER_PRUNE_MARKED(&clients, ast_aji_client_destroy);
04687 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04688 ASTOBJ_RDLOCK(iterator);
04689 if (iterator->state == AJI_DISCONNECTED) {
04690 if (!iterator->thread)
04691 ast_pthread_create_background(&iterator->thread, NULL, aji_recv_loop, iterator);
04692 } else if (iterator->state == AJI_CONNECTING) {
04693 aji_get_roster(iterator);
04694 if (iterator->distribute_events) {
04695 aji_init_event_distribution(iterator);
04696 }
04697 }
04698
04699 ASTOBJ_UNLOCK(iterator);
04700 });
04701
04702 return 1;
04703 }
04704
04705
04706
04707
04708
04709 static int unload_module(void)
04710 {
04711
04712 ast_cli_unregister_multiple(aji_cli, ARRAY_LEN(aji_cli));
04713 ast_unregister_application(app_ajisend);
04714 ast_unregister_application(app_ajisendgroup);
04715 ast_unregister_application(app_ajistatus);
04716 ast_unregister_application(app_ajijoin);
04717 ast_unregister_application(app_ajileave);
04718 ast_manager_unregister("JabberSend");
04719 ast_custom_function_unregister(&jabberstatus_function);
04720 if (mwi_sub) {
04721 ast_event_unsubscribe(mwi_sub);
04722 }
04723 if (device_state_sub) {
04724 ast_event_unsubscribe(device_state_sub);
04725 }
04726 ast_custom_function_unregister(&jabberreceive_function);
04727
04728 ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
04729 ASTOBJ_WRLOCK(iterator);
04730 ast_debug(3, "JABBER: Releasing and disconnecting client: %s\n", iterator->name);
04731 iterator->state = AJI_DISCONNECTING;
04732 ASTOBJ_UNLOCK(iterator);
04733 pthread_join(iterator->thread, NULL);
04734 ast_aji_disconnect(iterator);
04735 });
04736
04737 ASTOBJ_CONTAINER_DESTROYALL(&clients, ast_aji_client_destroy);
04738 ASTOBJ_CONTAINER_DESTROY(&clients);
04739
04740 ast_cond_destroy(&message_received_condition);
04741 ast_mutex_destroy(&messagelock);
04742
04743 return 0;
04744 }
04745
04746
04747
04748
04749
04750 static int load_module(void)
04751 {
04752 ASTOBJ_CONTAINER_INIT(&clients);
04753 if (!aji_reload(0))
04754 return AST_MODULE_LOAD_DECLINE;
04755 ast_manager_register_xml("JabberSend", EVENT_FLAG_SYSTEM, manager_jabber_send);
04756 ast_register_application_xml(app_ajisend, aji_send_exec);
04757 ast_register_application_xml(app_ajisendgroup, aji_sendgroup_exec);
04758 ast_register_application_xml(app_ajistatus, aji_status_exec);
04759 ast_register_application_xml(app_ajijoin, aji_join_exec);
04760 ast_register_application_xml(app_ajileave, aji_leave_exec);
04761 ast_cli_register_multiple(aji_cli, ARRAY_LEN(aji_cli));
04762 ast_custom_function_register(&jabberstatus_function);
04763 ast_custom_function_register(&jabberreceive_function);
04764
04765 ast_mutex_init(&messagelock);
04766 ast_cond_init(&message_received_condition, NULL);
04767 return 0;
04768 }
04769
04770
04771
04772
04773
04774 static int reload(void)
04775 {
04776 aji_reload(1);
04777 return 0;
04778 }
04779
04780 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "AJI - Asterisk Jabber Interface",
04781 .load = load_module,
04782 .unload = unload_module,
04783 .reload = reload,
04784 .load_pri = AST_MODPRI_CHANNEL_DEPEND,
04785 );