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