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