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