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