420 #define CLIENT_BUCKETS 53 423 #define BUDDY_BUCKETS 53 426 #define RESOURCE_BUCKETS 53 429 #define XMPP_TLS_NS "urn:ietf:params:xml:ns:xmpp-tls" 432 #define STATUS_DISAPPEAR 6 556 iks_filter_delete(client->
filter);
560 iks_stack_delete(client->
stack);
575 const char *
id = obj;
584 const char *
id = arg;
592 if (state == client->
state) {
624 ast_log(
LOG_ERROR,
"Could not initialize buddy container for '%s'\n", name);
635 if (!(client->
stack = iks_stack_new(8192, 8192))) {
662 if (!cfg || !cfg->clients || !(clientcfg =
xmpp_config_find(cfg->clients, category))) {
666 ao2_ref(clientcfg->client, +1);
667 return clientcfg->client;
713 const char *
match = (flags &
OBJ_KEY) ? arg : two->name;
759 ast_log(
LOG_ERROR,
"No oauth_clientid or oauth_secret specified, so client '%s' can't be used\n", clientcfg->
name);
764 if (!cfg || !cfg->clients || !(oldclientcfg =
xmpp_config_find(cfg->clients, clientcfg->
name))) {
770 if (strcmp(clientcfg->
user, oldclientcfg->user) ||
771 strcmp(clientcfg->
password, oldclientcfg->password) ||
772 strcmp(clientcfg->
refresh_token, oldclientcfg->refresh_token) ||
773 strcmp(clientcfg->
oauth_clientid, oldclientcfg->oauth_clientid) ||
774 strcmp(clientcfg->
oauth_secret, oldclientcfg->oauth_secret) ||
775 strcmp(clientcfg->
server, oldclientcfg->server) ||
776 (clientcfg->
port != oldclientcfg->port) ||
778 (clientcfg->
priority != oldclientcfg->priority)) {
799 .category =
"general",
808 .category =
"general",
812 .item_offset = offsetof(
struct xmpp_config, clients),
819 .alias =
"jabber.conf",
820 .types =
ACO_TYPES(&global_option, &client_option),
880 if (!cfg || !cfg->clients || !(clientcfg =
xmpp_config_find(cfg->clients, name))) {
884 ao2_ref(clientcfg->client, +1);
885 return clientcfg->client;
913 !(message_packet = iks_make_msg(group ? IKS_TYPE_GROUPCHAT : IKS_TYPE_CHAT, address, message))) {
918 snprintf(from,
sizeof(from),
"%s@%s/%s", nick, client->
jid->full, nick);
920 snprintf(from,
sizeof(from),
"%s", client->
jid->full);
923 iks_insert_attrib(message_packet,
"from", from);
927 iks_delete(message_packet);
940 iks *invite, *body =
NULL, *
namespace =
NULL;
942 if (!(invite = iks_new(
"message")) || !(body = iks_new(
"body")) || !(
namespace = iks_new(
"x"))) {
947 iks_insert_attrib(invite,
"to", user);
949 iks_insert_attrib(invite,
"id", client->
mid);
952 iks_insert_cdata(body, message, 0);
953 iks_insert_node(invite, body);
954 iks_insert_attrib(
namespace,
"xmlns",
"jabber:x:conference");
955 iks_insert_attrib(
namespace,
"jid", room);
956 iks_insert_node(invite,
namespace);
961 iks_delete(
namespace);
977 !(presence = iks_make_pres(level,
NULL)) || !(x = iks_new(
"x"))) {
983 snprintf(from,
sizeof(from),
"%s@%s/%s", nick, client->
jid->full, nick);
984 snprintf(roomid,
sizeof(roomid),
"%s/%s", room, nick);
986 snprintf(from,
sizeof(from),
"%s", client->
jid->full);
987 snprintf(roomid,
sizeof(roomid),
"%s/%s", room,
S_OR(nick, client->
jid->user));
990 iks_insert_attrib(presence,
"to", roomid);
991 iks_insert_attrib(presence,
"from", from);
992 iks_insert_attrib(x,
"xmlns",
"http://jabber.org/protocol/muc");
993 iks_insert_node(presence, x);
999 iks_delete(presence);
1023 for (i = strlen(mid) - 1; i >= 0; i--) {
1024 if (mid[i] !=
'z') {
1025 mid[i] = mid[i] + 1;
1046 !(request = iks_new(
"iq"))) {
1051 iks_insert_attrib(request,
"to", clientcfg->pubsubnode);
1054 iks_insert_attrib(request,
"from", client->
jid->full);
1055 iks_insert_attrib(request,
"type", type);
1058 iks_insert_attrib(request,
"id", client->
mid);
1072 const char *event_type,
unsigned int cachable)
1081 pubsub = iks_insert(request,
"pubsub");
1082 iks_insert_attrib(pubsub,
"xmlns",
"http://jabber.org/protocol/pubsub");
1083 publish = iks_insert(pubsub,
"publish");
1085 item = iks_insert(publish,
"item");
1086 iks_insert_attrib(item,
"id", node);
1089 iks *
options, *x, *field_form_type, *field_persist;
1091 options = iks_insert(pubsub,
"publish-options");
1092 x = iks_insert(options,
"x");
1093 iks_insert_attrib(x,
"xmlns",
"jabber:x:data");
1094 iks_insert_attrib(x,
"type",
"submit");
1095 field_form_type = iks_insert(x,
"field");
1096 iks_insert_attrib(field_form_type,
"var",
"FORM_TYPE");
1097 iks_insert_attrib(field_form_type,
"type",
"hidden");
1098 iks_insert_cdata(iks_insert(field_form_type,
"value"),
"http://jabber.org/protocol/pubsub#publish-options", 0);
1099 field_persist = iks_insert(x,
"field");
1100 iks_insert_attrib(field_persist,
"var",
"pubsub#persist_items");
1101 iks_insert_cdata(iks_insert(field_persist,
"value"),
"0", 1);
1110 iks *configure, *x, *field_owner, *field_node_type, *field_node_config,
1111 *field_deliver_payload, *field_persist_items, *field_access_model,
1112 *field_pubsub_collection;
1113 configure = iks_insert(pubsub,
"configure");
1114 x = iks_insert(configure,
"x");
1115 iks_insert_attrib(x,
"xmlns",
"jabber:x:data");
1116 iks_insert_attrib(x,
"type",
"submit");
1117 field_owner = iks_insert(x,
"field");
1118 iks_insert_attrib(field_owner,
"var",
"FORM_TYPE");
1119 iks_insert_attrib(field_owner,
"type",
"hidden");
1120 iks_insert_cdata(iks_insert(field_owner,
"value"),
1121 "http://jabber.org/protocol/pubsub#owner", 39);
1123 field_node_type = iks_insert(x,
"field");
1124 iks_insert_attrib(field_node_type,
"var",
"pubsub#node_type");
1125 iks_insert_cdata(iks_insert(field_node_type,
"value"), node_type, strlen(node_type));
1127 field_node_config = iks_insert(x,
"field");
1128 iks_insert_attrib(field_node_config,
"var",
"FORM_TYPE");
1129 iks_insert_attrib(field_node_config,
"type",
"hidden");
1130 iks_insert_cdata(iks_insert(field_node_config,
"value"),
1131 "http://jabber.org/protocol/pubsub#node_config", 45);
1132 field_deliver_payload = iks_insert(x,
"field");
1133 iks_insert_attrib(field_deliver_payload,
"var",
"pubsub#deliver_payloads");
1134 iks_insert_cdata(iks_insert(field_deliver_payload,
"value"),
"1", 1);
1135 field_persist_items = iks_insert(x,
"field");
1136 iks_insert_attrib(field_persist_items,
"var",
"pubsub#persist_items");
1137 iks_insert_cdata(iks_insert(field_persist_items,
"value"),
"1", 1);
1138 field_access_model = iks_insert(x,
"field");
1139 iks_insert_attrib(field_access_model,
"var",
"pubsub#access_model");
1140 iks_insert_cdata(iks_insert(field_access_model,
"value"),
"whitelist", 9);
1141 if (node_type && !strcasecmp(node_type,
"leaf")) {
1142 field_pubsub_collection = iks_insert(x,
"field");
1143 iks_insert_attrib(field_pubsub_collection,
"var",
"pubsub#collection");
1144 iks_insert_cdata(iks_insert(field_pubsub_collection,
"value"), collection_name,
1145 strlen(collection_name));
1159 iks *
pubsub, *affiliations, *affiliate;
1163 if (!modify_affiliates) {
1164 ast_log(
LOG_ERROR,
"Could not create IQ for creating affiliations on client '%s'\n", client->
name);
1168 pubsub = iks_insert(modify_affiliates,
"pubsub");
1169 iks_insert_attrib(pubsub,
"xmlns",
"http://jabber.org/protocol/pubsub#owner");
1170 affiliations = iks_insert(pubsub,
"affiliations");
1171 iks_insert_attrib(affiliations,
"node", node);
1175 affiliate = iks_insert(affiliations,
"affiliation");
1176 iks_insert_attrib(affiliate,
"jid", buddy->
id);
1177 iks_insert_attrib(affiliate,
"affiliation",
"owner");
1183 iks_delete(modify_affiliates);
1195 char *
name,
const char *collection_name)
1197 iks *node, *
pubsub, *create;
1203 pubsub = iks_insert(node,
"pubsub");
1204 iks_insert_attrib(pubsub,
"xmlns",
"http://jabber.org/protocol/pubsub");
1205 create = iks_insert(pubsub,
"create");
1206 iks_insert_attrib(create,
"node", name);
1227 pubsub = iks_insert(request,
"pubsub");
1228 iks_insert_attrib(pubsub,
"xmlns",
"http://jabber.org/protocol/pubsub#owner");
1229 delete = iks_insert(pubsub,
"delete");
1230 iks_insert_attrib(
delete,
"node", node_name);
1233 iks_delete(request);
1256 const char *leaf_name)
1270 const char *oldmsgs,
const char *newmsgs)
1282 mailbox_node = iks_insert(request,
"mailbox");
1283 iks_insert_attrib(mailbox_node,
"xmlns",
"http://asterisk.org");
1284 iks_insert_attrib(mailbox_node,
"eid", eid_str);
1285 iks_insert_cdata(iks_insert(mailbox_node,
"NEWMSGS"), newmsgs, strlen(newmsgs));
1286 iks_insert_cdata(iks_insert(mailbox_node,
"OLDMSGS"), oldmsgs, strlen(oldmsgs));
1290 iks_delete(request);
1301 const char *device_state,
unsigned int cachable)
1305 char eid_str[20], cachable_str[2];
1320 state = iks_insert(request,
"state");
1321 iks_insert_attrib(state,
"xmlns",
"http://asterisk.org");
1322 iks_insert_attrib(state,
"eid", eid_str);
1323 snprintf(cachable_str,
sizeof(cachable_str),
"%u", cachable);
1324 iks_insert_attrib(state,
"cachable", cachable_str);
1325 iks_insert_cdata(state, device_state, strlen(device_state));
1327 iks_delete(request);
1339 char oldmsgs[10], newmsgs[10];
1353 snprintf(oldmsgs,
sizeof(oldmsgs),
"%d", mwi_state->
old_msgs);
1354 snprintf(newmsgs,
sizeof(newmsgs),
"%d", mwi_state->
new_msgs);
1394 ast_log(
LOG_ERROR,
"Could not create IQ when creating pubsub unsubscription on client '%s'\n", client->
name);
1398 pubsub = iks_insert(request,
"pubsub");
1399 iks_insert_attrib(pubsub,
"xmlns",
"http://jabber.org/protocol/pubsub");
1400 unsubscribe = iks_insert(pubsub,
"unsubscribe");
1401 iks_insert_attrib(unsubscribe,
"jid", client->
jid->partial);
1402 iks_insert_attrib(unsubscribe,
"node", node);
1405 iks_delete(request);
1420 if (!cfg || !cfg->global || !request) {
1421 ast_log(
LOG_ERROR,
"Could not create IQ when creating pubsub subscription on client '%s'\n", client->
name);
1425 pubsub = iks_insert(request,
"pubsub");
1426 iks_insert_attrib(pubsub,
"xmlns",
"http://jabber.org/protocol/pubsub");
1427 subscribe = iks_insert(pubsub,
"subscribe");
1428 iks_insert_attrib(subscribe,
"jid", client->
jid->partial);
1429 iks_insert_attrib(subscribe,
"node", node);
1431 iks *
options, *x, *sub_options, *sub_type, *sub_depth, *sub_expire;
1432 options = iks_insert(pubsub,
"options");
1433 x = iks_insert(options,
"x");
1434 iks_insert_attrib(x,
"xmlns",
"jabber:x:data");
1435 iks_insert_attrib(x,
"type",
"submit");
1436 sub_options = iks_insert(x,
"field");
1437 iks_insert_attrib(sub_options,
"var",
"FORM_TYPE");
1438 iks_insert_attrib(sub_options,
"type",
"hidden");
1439 iks_insert_cdata(iks_insert(sub_options,
"value"),
1440 "http://jabber.org/protocol/pubsub#subscribe_options", 51);
1441 sub_type = iks_insert(x,
"field");
1442 iks_insert_attrib(sub_type,
"var",
"pubsub#subscription_type");
1443 iks_insert_cdata(iks_insert(sub_type,
"value"),
"items", 5);
1444 sub_depth = iks_insert(x,
"field");
1445 iks_insert_attrib(sub_depth,
"var",
"pubsub#subscription_depth");
1446 iks_insert_cdata(iks_insert(sub_depth,
"value"),
"all", 3);
1447 sub_expire = iks_insert(x,
"field");
1448 iks_insert_attrib(sub_expire,
"var",
"pubsub#expire");
1449 iks_insert_cdata(iks_insert(sub_expire,
"value"),
"presence", 8);
1452 iks_delete(request);
1463 char *item_id, *device_state, *
mailbox, *cachable_str;
1464 int oldmsgs, newmsgs;
1465 iks *
item, *item_content;
1468 item = iks_find(iks_find(iks_find(pak->x,
"event"),
"items"),
"item");
1471 return IKS_FILTER_EAT;
1473 item_id = iks_find_attrib(item,
"id");
1474 item_content = iks_child(item);
1475 ast_str_to_eid(&pubsub_eid, iks_find_attrib(item_content,
"eid"));
1477 ast_debug(1,
"Returning here, eid of incoming event matches ours!\n");
1478 return IKS_FILTER_EAT;
1480 if (!strcasecmp(iks_name(item_content),
"state")) {
1481 if ((cachable_str = iks_find_attrib(item_content,
"cachable"))) {
1482 sscanf(cachable_str,
"%30u", &cachable);
1484 device_state = iks_find_cdata(item,
"state");
1489 return IKS_FILTER_EAT;
1490 }
else if (!strcasecmp(iks_name(item_content),
"mailbox")) {
1491 mailbox =
strsep(&item_id,
"@");
1492 sscanf(iks_find_cdata(item_content,
"OLDMSGS"),
"%10d", &oldmsgs);
1493 sscanf(iks_find_cdata(item_content,
"NEWMSGS"),
"%10d", &newmsgs);
1497 return IKS_FILTER_EAT;
1499 ast_debug(1,
"Don't know how to handle PubSub event of type %s\n",
1500 iks_name(item_content));
1501 return IKS_FILTER_EAT;
1504 return IKS_FILTER_EAT;
1510 char *node_name, *
error;
1512 iks *orig_request, *orig_pubsub = iks_find(pak->x,
"pubsub");
1515 if (!cfg || !cfg->global) {
1517 return IKS_FILTER_EAT;
1521 ast_debug(1,
"Error isn't a PubSub error, why are we here?\n");
1522 return IKS_FILTER_EAT;
1525 orig_request = iks_child(orig_pubsub);
1526 error = iks_find_attrib(iks_find(pak->x,
"error"),
"code");
1527 node_name = iks_find_attrib(orig_request,
"node");
1529 if (!sscanf(error,
"%30d", &error_num)) {
1530 return IKS_FILTER_EAT;
1533 if (error_num > 399 && error_num < 500 && error_num != 404) {
1535 "Error performing operation on PubSub node %s, %s.\n", node_name, error);
1536 return IKS_FILTER_EAT;
1537 }
else if (error_num > 499 && error_num < 600) {
1539 return IKS_FILTER_EAT;
1542 if (!strcasecmp(iks_name(orig_request),
"publish")) {
1546 if (iks_find(iks_find(orig_request,
"item"),
"state")) {
1548 }
else if (iks_find(iks_find(orig_request,
"item"),
"mailbox")) {
1556 iks_insert_node(request, orig_pubsub);
1558 iks_delete(request);
1563 return IKS_FILTER_EAT;
1564 }
else if (!strcasecmp(iks_name(orig_request),
"subscribe")) {
1572 return IKS_FILTER_EAT;
1620 IKS_PAK_MESSAGE, IKS_RULE_FROM, clientcfg->pubsubnode, IKS_RULE_DONE);
1622 IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_ERROR, IKS_RULE_DONE);
1632 #define BUDDY_OFFLINE 6 1633 #define BUDDY_NOT_IN_ROSTER 7 1689 if (
args.argc != 2) {
1690 ast_log(
LOG_ERROR,
"JABBER_STATUS requires 2 arguments: sender and jid.\n");
1695 if (jid.argc < 1 || jid.argc > 2) {
1705 snprintf(buf, buflen,
"%d",
get_buddy_status(clientcfg, jid.screenname, jid.resource));
1711 .
name =
"JABBER_STATUS",
1734 ast_log(
LOG_ERROR,
"%s requires arguments (sender,jid[,nickname])\n", app_ajijoin);
1740 if (
args.argc < 2 ||
args.argc > 3) {
1741 ast_log(
LOG_ERROR,
"%s requires arguments (sender,jid[,nickname])\n", app_ajijoin);
1745 if (strchr(
args.jid,
'/')) {
1757 snprintf(nick,
sizeof(nick),
"asterisk");
1759 snprintf(nick,
sizeof(nick),
"%s", clientcfg->client->jid->user);
1762 snprintf(nick,
sizeof(nick),
"%s",
args.nick);
1793 ast_log(
LOG_ERROR,
"%s requires arguments (sender,jid[,nickname])\n", app_ajileave);
1799 if (
args.argc < 2 ||
args.argc > 3) {
1800 ast_log(
LOG_ERROR,
"%s requires arguments (sender,jid[,nickname])\n", app_ajileave);
1804 if (strchr(
args.jid,
'/')) {
1821 snprintf(nick,
sizeof(nick),
"asterisk");
1823 snprintf(nick,
sizeof(nick),
"%s", clientcfg->client->jid->user);
1826 snprintf(nick,
sizeof(nick),
"%s",
args.nick);
1896 ast_log(
LOG_ERROR,
"%s requires arguments (sender,groupchatid,message[,nickname])\n", app_ajisendgroup);
1903 ast_log(
LOG_ERROR,
"%s requires arguments (sender,groupchatid,message[,nickname])\n", app_ajisendgroup);
1914 snprintf(nick,
sizeof(nick),
"asterisk");
1916 snprintf(nick,
sizeof(nick),
"%s", clientcfg->client->jid->user);
1919 snprintf(nick,
sizeof(nick),
"%s",
args.nick);
1941 int timeout, jidlen, resourcelen, found = 0;
1942 struct timeval start;
1963 if (
args.argc < 2 ||
args.argc > 3) {
1978 sscanf(
args.timeout,
"%d", &timeout);
1985 jidlen = strlen(jid.screenname);
1986 resourcelen =
ast_strlen_zero(jid.resource) ? 0 : strlen(jid.resource);
1993 ast_debug(3,
"Waiting for an XMPP message from %s\n",
args.jid);
2004 while (diff < timeout) {
2005 struct timespec ts = { 0, };
2006 struct timeval wait;
2010 ts.tv_sec = wait.tv_sec;
2011 ts.tv_nsec = wait.tv_usec * 1000;
2019 if (res == ETIMEDOUT) {
2020 ast_debug(3,
"No message received from %s in %d seconds\n",
args.jid, timeout);
2026 if (jid.argc == 1) {
2028 if (strncasecmp(jid.screenname, message->
from, jidlen)) {
2033 char *resource = strchr(message->
from,
'/');
2034 if (!resource || strlen(resource) == 0) {
2036 if (strncasecmp(jid.screenname, message->
from, jidlen)) {
2041 if (strncasecmp(jid.screenname, message->
from, jidlen) || strncmp(jid.resource, resource, resourcelen)) {
2048 ast_debug(3,
"Found old message from %s, deleting it\n", message->
from);
2083 .
name =
"JABBER_RECEIVE",
2099 int deleted = 0, isold = 0;
2109 if (!from || !strncasecmp(from, message->
from, strlen(from))) {
2116 if (!from || !strncasecmp(from, message->
from, strlen(from))) {
2133 char *sender, *dest;
2146 if (!cfg || !cfg->clients || !(clientcfg =
xmpp_config_find(cfg->clients, sender))) {
2151 ast_debug(1,
"Sending message to '%s' from '%s'\n", dest, clientcfg->name);
2157 return res == IKS_OK ? 0 : -1;
2197 "Goodbye. Your status is no longer required.\n"))) {
2201 if (!(iq = iks_new(
"iq")) || !(query = iks_new(
"query")) || !(item = iks_new(
"item"))) {
2202 ast_log(
LOG_WARNING,
"Could not allocate memory for roster removal of '%s' from client '%s'\n",
2203 user, client->
name);
2207 iks_insert_attrib(iq,
"from", client->
jid->full);
2208 iks_insert_attrib(iq,
"type",
"set");
2209 iks_insert_attrib(query,
"xmlns",
"jabber:iq:roster");
2210 iks_insert_node(iq, query);
2211 iks_insert_attrib(item,
"jid", user);
2212 iks_insert_attrib(item,
"subscription",
"remove");
2213 iks_insert_node(query, item);
2216 ast_log(
LOG_WARNING,
"Could not send roster removal request of '%s' from client '%s'\n",
2217 user, client->
name);
2239 "Greetings! I am the Asterisk Open Source PBX and I want to subscribe to your presence\n"))) {
2241 buddy->
id, client->
name);
2258 return IKS_FILTER_EAT;
2261 for (item = iks_child(pak->query); item; item = iks_next(item)) {
2264 if (iks_strcmp(iks_name(item),
"item")) {
2274 iks_find_attrib(item,
"jid"), client->
name);
2280 ast_log(
LOG_ERROR,
"Could not allocate buddy '%s' on client '%s'\n", iks_find_attrib(item,
"jid"),
2287 if (!iks_strcmp(iks_find_attrib(item,
"subscription"),
"none") ||
2288 !iks_strcmp(iks_find_attrib(item,
"subscription"),
"from")) {
2304 return IKS_FILTER_EAT;
2316 !(presence = iks_make_pres(level, desc)) || !(cnode = iks_new(
"c")) || !(priority = iks_new(
"priority"))) {
2317 ast_log(
LOG_ERROR,
"Unable to allocate stanzas for setting presence status for client '%s'\n", client->
name);
2322 iks_insert_attrib(presence,
"to", to);
2326 iks_insert_attrib(presence,
"from", from);
2329 snprintf(priorityS,
sizeof(priorityS),
"%d", clientcfg->priority);
2330 iks_insert_cdata(priority, priorityS, strlen(priorityS));
2331 iks_insert_node(presence, priority);
2332 iks_insert_attrib(cnode,
"node",
"http://www.asterisk.org/xmpp/client/caps");
2333 iks_insert_attrib(cnode,
"ver",
"asterisk-xmpp");
2334 iks_insert_attrib(cnode,
"ext",
"voice-v1 video-v1 camera-v1");
2335 iks_insert_attrib(cnode,
"xmlns",
"http://jabber.org/protocol/caps");
2336 iks_insert_node(presence, cnode);
2341 iks_delete(presence);
2342 iks_delete(priority);
2351 if (!(iq = iks_new(
"iq")) || !(query = iks_new(
"query")) || !(ident = iks_new(
"identity")) || !(disco = iks_new(
"feature")) ||
2352 !(google = iks_new(
"feature")) || !(jingle = iks_new(
"feature")) || !(ice = iks_new(
"feature")) || !(rtp = iks_new(
"feature")) ||
2353 !(audio = iks_new(
"feature")) || !(video = iks_new(
"feature"))) {
2354 ast_log(
LOG_ERROR,
"Could not allocate memory for responding to service discovery request from '%s' on client '%s'\n",
2355 pak->from->full, client->
name);
2359 iks_insert_attrib(iq,
"from", client->
jid->full);
2362 iks_insert_attrib(iq,
"to", pak->from->full);
2365 iks_insert_attrib(iq,
"type",
"result");
2366 iks_insert_attrib(iq,
"id", pak->id);
2367 iks_insert_attrib(query,
"xmlns",
"http://jabber.org/protocol/disco#info");
2368 iks_insert_attrib(ident,
"category",
"client");
2369 iks_insert_attrib(ident,
"type",
"pc");
2370 iks_insert_attrib(ident,
"name",
"asterisk");
2371 iks_insert_attrib(disco,
"var",
"http://jabber.org/protocol/disco#info");
2373 iks_insert_attrib(google,
"var",
"http://www.google.com/xmpp/protocol/voice/v1");
2374 iks_insert_attrib(jingle,
"var",
"urn:xmpp:jingle:1");
2375 iks_insert_attrib(ice,
"var",
"urn:xmpp:jingle:transports:ice-udp:1");
2376 iks_insert_attrib(rtp,
"var",
"urn:xmpp:jingle:apps:rtp:1");
2377 iks_insert_attrib(audio,
"var",
"urn:xmpp:jingle:apps:rtp:audio");
2378 iks_insert_attrib(video,
"var",
"urn:xmpp:jingle:apps:rtp:video");
2379 iks_insert_node(iq, query);
2380 iks_insert_node(query, ident);
2381 iks_insert_node(query, google);
2382 iks_insert_node(query, disco);
2383 iks_insert_node(query, jingle);
2384 iks_insert_node(query, ice);
2385 iks_insert_node(query, rtp);
2386 iks_insert_node(query, audio);
2387 iks_insert_node(query, video);
2402 return IKS_FILTER_EAT;
2413 return IKS_FILTER_EAT;
2418 return IKS_FILTER_EAT;
2423 if (iks_find_with_attrib(pak->query,
"feature",
"var",
"urn:xmpp:jingle:1")) {
2432 return IKS_FILTER_EAT;
2447 client->
jid = (iks_find_cdata(pak->query,
"jid")) ? iks_id_new(client->
stack, iks_find_cdata(pak->query,
"jid")) : client->
jid;
2453 if (!(roster = iks_make_iq(IKS_TYPE_GET, IKS_NS_ROSTER))) {
2454 ast_log(
LOG_ERROR,
"Unable to allocate memory for roster request for client '%s'\n", client->
name);
2461 iks_insert_attrib(roster,
"id",
"roster");
2465 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);
2470 return IKS_FILTER_EAT;
2474 static void xmpp_log_hook(
void *data,
const char *xmpp,
size_t size,
int incoming)
2485 ast_verbose(
"\n<--- XMPP sent to '%s' --->\n%s\n<------------->\n", client->
name, xmpp);
2487 ast_verbose(
"\n<--- XMPP received from '%s' --->\n%s\n<------------->\n", client->
name, xmpp);
2498 return IKS_NET_NOCONN;
2503 int len = strlen(message);
2505 ret = SSL_write(client->
ssl_session, message, len);
2516 ret = iks_send_raw(client->
parser, message);
2517 if (ret != IKS_OK) {
2528 char msg[91 + strlen(
namespace) + 6 + strlen(to) + 16 + 1];
2530 snprintf(msg,
sizeof(msg),
"<?xml version='1.0'?>" 2531 "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='" 2532 "%s' to='%s' version='1.0'>",
namespace, to);
2551 #ifndef HAVE_OPENSSL 2552 ast_log(
LOG_ERROR,
"TLS connection for client '%s' cannot be established. OpenSSL is not available.\n", client->
name);
2555 if (iks_send_raw(client->
parser,
"<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>") == IKS_NET_TLSFAIL) {
2573 BIO *bio = BIO_new(BIO_s_mem());
2575 ERR_print_errors(bio);
2576 len = BIO_get_mem_data(bio, &buf);
2579 memcpy(ret, buf, len);
2595 if (!strcmp(iks_name(node),
"success")) {
2599 }
else if (!strcmp(iks_name(node),
"failure")) {
2602 }
else if (strcmp(iks_name(node),
"proceed")) {
2607 #ifndef HAVE_OPENSSL 2608 ast_log(
LOG_ERROR,
"Somehow we managed to try to start TLS negotiation on client '%s' without OpenSSL support, disconnecting\n", client->
name);
2616 ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
2617 SSL_CTX_set_options(client->
ssl_context, ssl_opts);
2623 sock = iks_fd(client->
parser);
2636 ast_log(
LOG_ERROR,
"TLS connection for client '%s' could not be established, failed to send stream header after negotiation\n",
2641 ast_debug(1,
"TLS connection for client '%s' started with server\n", client->
name);
2649 ast_log(
LOG_ERROR,
"TLS connection for client '%s' cannot be established. " 2650 "OpenSSL initialization failed: %s\n", client->
name, err);
2660 char buf[41], sidpass[100];
2662 if (!(iq = iks_new(
"iq")) || !(query = iks_insert(iq,
"query"))) {
2663 ast_log(
LOG_ERROR,
"Stanzas could not be allocated for authentication on client '%s'\n", client->
name);
2668 iks_insert_attrib(iq,
"type",
"set");
2669 iks_insert_cdata(iks_insert(query,
"username"), client->
jid->user, 0);
2670 iks_insert_cdata(iks_insert(query,
"resource"), client->
jid->resource, 0);
2672 iks_insert_attrib(query,
"xmlns",
"jabber:iq:auth");
2673 snprintf(sidpass,
sizeof(sidpass),
"%s%s", iks_find_attrib(node,
"id"), cfg->
password);
2675 iks_insert_cdata(iks_insert(query,
"digest"), buf, 0);
2678 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);
2679 iks_insert_attrib(iq,
"id", client->
mid);
2683 iks_insert_attrib(iq,
"to", client->
jid->server);
2697 int features,
len = strlen(client->
jid->user) + strlen(cfg->
password) + 3;
2700 char base64[(len + 2) * 4 / 3];
2702 if (strcmp(iks_name(node),
"stream:features")) {
2707 features = iks_stream_features(node);
2709 if ((features & IKS_STREAM_SASL_MD5) && !
xmpp_is_secure(client)) {
2710 if (iks_start_sasl(client->
parser, IKS_SASL_DIGEST_MD5, (
char*)client->
jid->user, (
char*)cfg->
password) != IKS_OK) {
2711 ast_log(
LOG_ERROR,
"Tried to authenticate client '%s' using SASL DIGEST-MD5 but could not\n", client->
name);
2720 if (!(features & IKS_STREAM_SASL_PLAIN)) {
2721 ast_log(
LOG_ERROR,
"Tried to authenticate client '%s' using SASL PLAIN but server does not support it\n", client->
name);
2725 if (!(auth = iks_new(
"auth"))) {
2726 ast_log(
LOG_ERROR,
"Could not allocate memory for SASL PLAIN authentication for client '%s'\n", client->
name);
2730 iks_insert_attrib(auth,
"xmlns", IKS_NS_XMPP_SASL);
2732 iks_insert_attrib(auth,
"mechanism",
"X-OAUTH2");
2733 iks_insert_attrib(auth,
"auth:service",
"oauth2");
2734 iks_insert_attrib(auth,
"xmlns:auth",
"http://www.google.com/talk/protocol/auth");
2736 iks_insert_attrib(auth,
"mechanism",
"PLAIN");
2739 if (strchr(client->
jid->user,
'/')) {
2742 snprintf(combined,
sizeof(combined),
"%c%s%c%s", 0,
strsep(&user,
"/"), 0, cfg->
password);
2744 snprintf(combined,
sizeof(combined),
"%c%s%c%s", 0, client->
jid->user, 0, cfg->
password);
2748 iks_insert_cdata(auth,
base64, 0);
2770 if (!strcmp(iks_name(node),
"success")) {
2775 }
else if (!strcmp(iks_name(node),
"failure")) {
2778 }
else if (strcmp(iks_name(node),
"stream:features")) {
2783 features = iks_stream_features(node);
2785 if (features & IKS_STREAM_BIND) {
2788 if (!(auth = iks_make_resource_bind(client->
jid))) {
2789 ast_log(
LOG_ERROR,
"Failed to allocate memory for stream bind on client '%s'\n", client->
name);
2794 iks_insert_attrib(auth,
"id", client->
mid);
2801 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);
2804 if (features & IKS_STREAM_SESSION) {
2807 if (!(auth = iks_make_session())) {
2808 ast_log(
LOG_ERROR,
"Failed to allocate memory for stream session on client '%s'\n", client->
name);
2812 iks_insert_attrib(auth,
"id",
"auth");
2820 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);
2829 char secret[160], shasum[320],
message[344];
2830 ikspak *pak = iks_packet(node);
2832 snprintf(secret,
sizeof(secret),
"%s%s", pak->id, cfg->
password);
2834 snprintf(message,
sizeof(message),
"<handshake>%s</handshake>", shasum);
2857 !(iq = iks_new(
"iq")) || !(query = iks_new(
"query")) || !(identity = iks_new(
"identity")) || !(disco = iks_new(
"feature")) ||
2858 !(reg = iks_new(
"feature")) || !(commands = iks_new(
"feature")) || !(gateway = iks_new(
"feature")) || !(version = iks_new(
"feature")) ||
2859 !(vcard = iks_new(
"feature")) || !(search = iks_new(
"search")) || !(item = iks_new(
"item"))) {
2860 ast_log(
LOG_ERROR,
"Failed to allocate stanzas for service discovery get response to '%s' on component '%s'\n",
2861 pak->from->partial, client->
name);
2865 iks_insert_attrib(iq,
"from", clientcfg->user);
2866 iks_insert_attrib(iq,
"to", pak->from->full);
2867 iks_insert_attrib(iq,
"id", pak->id);
2868 iks_insert_attrib(iq,
"type",
"result");
2870 if (!(node = iks_find_attrib(pak->query,
"node"))) {
2871 iks_insert_attrib(query,
"xmlns",
"http://jabber.org/protocol/disco#info");
2872 iks_insert_attrib(identity,
"category",
"gateway");
2873 iks_insert_attrib(identity,
"type",
"pstn");
2874 iks_insert_attrib(identity,
"name",
"Asterisk The Open Source PBX");
2875 iks_insert_attrib(disco,
"var",
"http://jabber.org/protocol/disco");
2876 iks_insert_attrib(reg,
"var",
"jabber:iq:register");
2877 iks_insert_attrib(commands,
"var",
"http://jabber.org/protocol/commands");
2878 iks_insert_attrib(gateway,
"var",
"jabber:iq:gateway");
2879 iks_insert_attrib(version,
"var",
"jabber:iq:version");
2880 iks_insert_attrib(vcard,
"var",
"vcard-temp");
2881 iks_insert_attrib(search,
"var",
"jabber:iq:search");
2883 iks_insert_node(iq, query);
2884 iks_insert_node(query, identity);
2885 iks_insert_node(query, disco);
2886 iks_insert_node(query, reg);
2887 iks_insert_node(query, commands);
2888 iks_insert_node(query, gateway);
2889 iks_insert_node(query, version);
2890 iks_insert_node(query, vcard);
2891 iks_insert_node(query, search);
2892 }
else if (!strcasecmp(node,
"http://jabber.org/protocol/commands")) {
2893 iks_insert_attrib(query,
"xmlns",
"http://jabber.org/protocol/disco#items");
2894 iks_insert_attrib(query,
"node",
"http://jabber.org/protocol/commands");
2895 iks_insert_attrib(item,
"node",
"confirmaccount");
2896 iks_insert_attrib(item,
"name",
"Confirm account");
2897 iks_insert_attrib(item,
"jid", clientcfg->user);
2899 iks_insert_node(iq, query);
2900 iks_insert_node(query, item);
2901 }
else if (!strcasecmp(node,
"confirmaccount")) {
2902 iks_insert_attrib(query,
"xmlns",
"http://jabber.org/protocol/disco#info");
2903 iks_insert_attrib(commands,
"var",
"http://jabber.org/protocol/commands");
2905 iks_insert_node(iq, query);
2906 iks_insert_node(query, commands);
2908 ast_debug(3,
"Unsupported service discovery info request received with node '%s' on component '%s'\n",
2909 node, client->
name);
2914 ast_log(
LOG_WARNING,
"Could not send response to service discovery request on component '%s'\n",
2921 iks_delete(version);
2922 iks_delete(gateway);
2923 iks_delete(commands);
2926 iks_delete(identity);
2930 return IKS_FILTER_EAT;
2944 !(iq = iks_new(
"iq")) || !(query = iks_new(
"query")) || !(error = iks_new(
"error")) || !(notacceptable = iks_new(
"not-acceptable")) ||
2945 !(instructions = iks_new(
"instructions"))) {
2946 ast_log(
LOG_ERROR,
"Failed to allocate stanzas for register get response to '%s' on component '%s'\n",
2947 pak->from->partial, client->
name);
2951 iks_insert_attrib(iq,
"from", clientcfg->user);
2952 iks_insert_attrib(iq,
"to", pak->from->full);
2953 iks_insert_attrib(iq,
"id", pak->id);
2954 iks_insert_attrib(iq,
"type",
"result");
2955 iks_insert_attrib(query,
"xmlns",
"jabber:iq:register");
2956 iks_insert_node(iq, query);
2959 iks_insert_attrib(error,
"code",
"406");
2960 iks_insert_attrib(error,
"type",
"modify");
2961 iks_insert_attrib(notacceptable,
"xmlns",
"urn:ietf:params:xml:ns:xmpp-stanzas");
2963 iks_insert_node(iq, error);
2964 iks_insert_node(error, notacceptable);
2966 ast_log(
LOG_ERROR,
"Received register attempt from '%s' but buddy is not configured on component '%s'\n",
2967 pak->from->partial, client->
name);
2968 }
else if (!(node = iks_find_attrib(pak->query,
"node"))) {
2969 iks_insert_cdata(instructions,
"Welcome to Asterisk - the Open Source PBX.\n", 0);
2970 iks_insert_node(query, instructions);
2973 ast_log(
LOG_WARNING,
"Received register get to component '%s' using unsupported node '%s' from '%s'\n",
2974 client->
name, node, pak->from->partial);
2980 ast_log(
LOG_WARNING,
"Could not send response to '%s' for received register get on component '%s'\n",
2981 pak->from->partial, client->
name);
2985 iks_delete(instructions);
2986 iks_delete(notacceptable);
2991 return IKS_FILTER_EAT;
2998 iks *iq, *presence =
NULL, *x =
NULL;
3000 if (!(iq = iks_new(
"iq")) || !(presence = iks_new(
"presence")) || !(x = iks_new(
"x"))) {
3001 ast_log(
LOG_ERROR,
"Failed to allocate stanzas for register set response to '%s' on component '%s'\n",
3002 pak->from->partial, client->
name);
3006 iks_insert_attrib(iq,
"from", client->
jid->full);
3007 iks_insert_attrib(iq,
"to", pak->from->full);
3008 iks_insert_attrib(iq,
"id", pak->id);
3009 iks_insert_attrib(iq,
"type",
"result");
3012 ast_log(
LOG_WARNING,
"Could not send response to '%s' for received register set on component '%s'\n",
3013 pak->from->partial, client->
name);
3017 iks_insert_attrib(presence,
"from", client->
jid->full);
3018 iks_insert_attrib(presence,
"to", pak->from->partial);
3020 iks_insert_attrib(presence,
"id", client->
mid);
3023 iks_insert_attrib(presence,
"type",
"subscribe");
3024 iks_insert_attrib(x,
"xmlns",
"vcard-temp:x:update");
3026 iks_insert_node(presence, x);
3030 pak->from->partial, client->
name);
3035 iks_delete(presence);
3038 return IKS_FILTER_EAT;
3051 !(iq = iks_new(
"iq")) || !(query = iks_new(
"query")) || !(item = iks_new(
"item")) || !(feature = iks_new(
"feature"))) {
3052 ast_log(
LOG_ERROR,
"Failed to allocate stanzas for service discovery items response to '%s' on component '%s'\n",
3053 pak->from->partial, client->
name);
3057 iks_insert_attrib(iq,
"from", clientcfg->user);
3058 iks_insert_attrib(iq,
"to", pak->from->full);
3059 iks_insert_attrib(iq,
"id", pak->id);
3060 iks_insert_attrib(iq,
"type",
"result");
3061 iks_insert_attrib(query,
"xmlns",
"http://jabber.org/protocol/disco#items");
3062 iks_insert_node(iq, query);
3064 if (!(node = iks_find_attrib(pak->query,
"node"))) {
3065 iks_insert_attrib(item,
"node",
"http://jabber.org/protocol/commands");
3066 iks_insert_attrib(item,
"name",
"Asterisk Commands");
3067 iks_insert_attrib(item,
"jid", clientcfg->user);
3069 iks_insert_node(query, item);
3070 }
else if (!strcasecmp(node,
"http://jabber.org/protocol/commands")) {
3071 iks_insert_attrib(query,
"node",
"http://jabber.org/protocol/commands");
3073 ast_log(
LOG_WARNING,
"Received service discovery items request to component '%s' using unsupported node '%s' from '%s'\n",
3074 client->
name, node, pak->from->partial);
3079 ast_log(
LOG_WARNING,
"Could not send response to service discovery items request from '%s' on component '%s'\n",
3080 pak->from->partial, client->
name);
3084 iks_delete(feature);
3089 return IKS_FILTER_EAT;
3095 if (!strcmp(iks_name(node),
"stream:features")) {
3099 if (strcmp(iks_name(node),
"handshake")) {
3126 ast_debug(3,
"XMPP client '%s' received a message\n", client->
name);
3128 if (!(body = iks_find_cdata(pak->x,
"body"))) {
3133 if (!(message =
ast_calloc(1,
sizeof(*message)))) {
3181 ast_debug(3,
"Deleted %d messages for client %s from JID %s\n", deleted, client->
name, pak->from->partial);
3200 if (!(iq = iks_new(
"iq")) || !(query = iks_new(
"query"))) {
3205 iks_insert_attrib(iq,
"type",
"get");
3206 iks_insert_attrib(iq,
"to", to);
3207 iks_insert_attrib(iq,
"from", from);
3209 iks_insert_attrib(iq,
"id", client->
mid);
3212 iks_insert_attrib(query,
"xmlns",
"http://jabber.org/protocol/disco#info");
3213 iks_insert_node(iq, query);
3237 ast_debug(2,
"JABBER: Sending Keep-Alive Ping for client '%s'\n", client->
name);
3239 if (!(iq = iks_new(
"iq")) || !(ping = iks_new(
"ping"))) {
3244 iks_insert_attrib(iq,
"type",
"get");
3245 iks_insert_attrib(iq,
"to", to);
3246 iks_insert_attrib(iq,
"from", from);
3249 iks_insert_attrib(iq,
"id", client->
mid);
3253 iks_insert_attrib(ping,
"xmlns",
"urn:xmpp:ping");
3254 iks_insert_node(iq, ping);
3270 char *
type = iks_find_attrib(pak->x,
"type");
3280 if (!pak->from->resource) {
3286 if (strcmp(client->
jid->partial, pak->from->partial)) {
3287 ast_log(
LOG_WARNING,
"Received presence information about '%s' despite not having them in roster on client '%s'\n",
3288 pak->from->partial, client->
name);
3299 ast_log(
LOG_ERROR,
"Could not allocate resource object for resource '%s' of buddy '%s' on client '%s'\n",
3300 pak->from->resource, buddy->
id, client->
name);
3318 if (!(node = iks_find_attrib(iks_find(pak->x,
"c"),
"node"))) {
3319 node = iks_find_attrib(iks_find(pak->x,
"caps:c"),
"node");
3322 if (!(ver = iks_find_attrib(iks_find(pak->x,
"c"),
"ver"))) {
3323 ver = iks_find_attrib(iks_find(pak->x,
"caps:c"),
"ver");
3330 if ((node && strcmp(resource->
caps.
node, node)) || (ver && strcmp(resource->
caps.
version, ver))) {
3340 if (iks_find_with_attrib(pak->x,
"c",
"node",
"http://www.google.com/xmpp/client/caps") ||
3341 iks_find_with_attrib(pak->x,
"caps:c",
"node",
"http://www.google.com/xmpp/client/caps") ||
3342 iks_find_with_attrib(pak->x,
"c",
"node",
"http://www.android.com/gtalk/client/caps") ||
3343 iks_find_with_attrib(pak->x,
"caps:c",
"node",
"http://www.android.com/gtalk/client/caps") ||
3344 iks_find_with_attrib(pak->x,
"c",
"node",
"http://mail.google.com/xmpp/client/caps") ||
3345 iks_find_with_attrib(pak->x,
"caps:c",
"node",
"http://mail.google.com/xmpp/client/caps")) {
3351 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);
3357 resource->
priority = atoi((iks_find_cdata(pak->x,
"priority")) ? iks_find_cdata(pak->x,
"priority") :
"0");
3362 "Account: %s\r\nJID: %s\r\nResource: %s\r\nStatus: %d\r\nPriority: %d" 3363 "\r\nDescription: %s\r\n",
3375 "Account: %s\r\nJID: %s\r\nStatus: %u\r\n",
3376 client->
name, pak->from->partial, pak->show ? pak->show : IKS_SHOW_UNAVAILABLE);
3399 switch (pak->subtype) {
3400 case IKS_TYPE_SUBSCRIBE:
3404 if ((presence = iks_new(
"presence")) && (status = iks_new(
"status"))) {
3405 iks_insert_attrib(presence,
"type",
"subscribed");
3406 iks_insert_attrib(presence,
"to", pak->from->full);
3407 iks_insert_attrib(presence,
"from", client->
jid->full);
3410 iks_insert_attrib(presence,
"id", pak->id);
3413 iks_insert_cdata(status,
"Asterisk has approved your subscription", 0);
3414 iks_insert_node(presence, status);
3417 ast_log(
LOG_ERROR,
"Could not send subscription acceptance to '%s' from client '%s'\n",
3418 pak->from->partial, client->
name);
3421 ast_log(
LOG_ERROR,
"Could not allocate presence stanzas for accepting subscription from '%s' to client '%s'\n",
3422 pak->from->partial, client->
name);
3426 iks_delete(presence);
3433 case IKS_TYPE_SUBSCRIBED:
3442 pak->from->partial, client->
name);
3480 pak = iks_packet(node);
3485 if (iks_has_children(node) && strchr(iks_name(iks_child(node)),
':')) {
3486 char *node_ns =
NULL;
3488 char *node_name = iks_name(iks_child(node));
3489 char *aux = strchr(node_name,
':') + 1;
3490 snprintf(attr, strlen(
"xmlns:") + (strlen(node_name) - strlen(aux)),
"xmlns:%s", node_name);
3491 node_ns = iks_find_attrib(iks_child(node), attr);
3494 pak->query = iks_child(node);
3521 iks_filter_packet(client->
filter, pak);
3532 pthread_cancel(client->
thread);
3558 iks_disconnect(client->
parser);
3569 struct timeval tv = { .tv_sec = 5, .tv_usec = 0 };
3572 int res = IKS_NET_NOCONN;
3581 iks_parser_reset(client->
parser);
3583 if (!client->
filter && !(client->
filter = iks_filter_new())) {
3589 ast_debug(2,
"Obtaining OAuth access token for client '%s'\n", client->
name);
3596 res = iks_connect_via(client->
parser,
S_OR(clientcfg->server, client->
jid->server), clientcfg->port,
3600 setsockopt(iks_fd(client->
parser), SOL_SOCKET, SO_RCVTIMEO, (
char *)&tv,
sizeof(
struct timeval));
3602 if (res == IKS_NET_NOCONN) {
3603 ast_log(
LOG_ERROR,
"No XMPP connection available when trying to connect client '%s'\n", client->
name);
3605 }
else if (res == IKS_NET_NODNS) {
3606 ast_log(
LOG_ERROR,
"No DNS available for XMPP connection when trying to connect client '%s'\n", client->
name);
3619 struct pollfd pfd = { .events = POLLIN };
3630 pfd.fd = iks_fd(client->
parser);
3632 res =
ast_poll(&pfd, 1, timeout > 0 ? timeout * 1000 : -1);
3636 len = SSL_read(client->
ssl_session, buffer, buf_len);
3639 len = recv(pfd.fd, buffer, buf_len, 0);
3643 }
else if (len <= 0) {
3653 int len, ret, pos = 0, newbufpos = 0;
3660 if (len < 0)
return IKS_NET_RWERR;
3672 while (isspace(buf[pos+1])) {
3676 newbuf[newbufpos] =
c;
3688 ast_debug(1,
"JABBER: Detected Google Keep Alive. " 3689 "Sending out Ping request for client '%s'\n", client->
name);
3697 ret = iks_parse(client->
parser, newbuf, 0, 0);
3698 memset(newbuf, 0,
sizeof(newbuf));
3711 if (ret != IKS_OK) {
3714 ast_debug(3,
"XML parsing successful\n");
3722 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,
NULL);
3725 *sleep_time =
MIN(60, *sleep_time * 2);
3727 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
NULL);
3734 int res = IKS_NET_RWERR;
3735 unsigned int sleep_time = 1;
3738 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
NULL);
3746 if (res == IKS_NET_RWERR || client->
timeout == 0) {
3750 res = IKS_NET_RWERR;
3763 if (res == IKS_HOOK) {
3765 }
else if (res == IKS_NET_TLSFAIL) {
3771 if (cfg && cfg->clients) {
3781 if (res == IKS_OK) {
3786 }
else if (res == IKS_NET_RWERR) {
3790 }
else if (res == IKS_NET_NOSOCK) {
3792 }
else if (res == IKS_NET_NOCONN) {
3794 }
else if (res == IKS_NET_NODNS) {
3796 }
else if (res == IKS_NET_NOTSUPP) {
3798 }
else if (res == IKS_NET_DROPPED) {
3800 }
else if (res == IKS_NET_UNKNOWN) {
3802 }
else if (res == IKS_OK) {
3830 char cBuf[1024] =
"";
3831 const char *
url =
"https://www.googleapis.com/oauth2/v3/token";
3836 "CURL(%s,client_id=%s&client_secret=%s&refresh_token=%s&grant_type=refresh_token)",
3841 ast_debug(2,
"Performing OAuth 2.0 authentication for client '%s' using command: %s\n",
3845 ast_log(
LOG_ERROR,
"CURL is unavailable. This is required for OAuth 2.0 authentication of XMPP client '%s'. Please ensure it is loaded.\n",
3850 ast_debug(2,
"OAuth 2.0 authentication for client '%s' returned: %s\n", cfg->
name, cBuf);
3861 ast_log(
LOG_ERROR,
"An error occurred while performing OAuth 2.0 authentication for client '%s': %s\n", cfg->
name, cBuf);
3883 ast_log(
LOG_ERROR,
"Iksemel stream could not be created for client '%s' - client not active\n", cfg->
name);
3891 char resource[strlen(cfg->
user) + strlen(
"/asterisk-xmpp") + 1];
3893 snprintf(resource,
sizeof(resource),
"%s/asterisk-xmpp", cfg->
user);
3900 ast_log(
LOG_ERROR,
"Jabber identity '%s' could not be created for client '%s' - client not active\n", cfg->
user, cfg->
name);
3951 if (!cfg || !cfg->clients || !(clientcfg =
xmpp_config_find(cfg->clients, jabber))) {
3985 query = iks_insert(request,
"query");
3986 iks_insert_attrib(query,
"xmlns",
"http://jabber.org/protocol/disco#items");
3989 iks_insert_attrib(query,
"node", collection);
4006 if (iks_has_children(pak->query)) {
4007 item = iks_first_tag(pak->query);
4008 ast_verbose(
"Connection %s: %s\nNode name: %s\n", client->
name, client->
jid->partial,
4009 iks_find_attrib(item,
"node"));
4010 while ((item = iks_next_tag(item))) {
4011 ast_verbose(
"Node name: %s\n", iks_find_attrib(item,
"node"));
4020 return IKS_FILTER_EAT;
4034 ast_log(
LOG_ERROR,
"Could not request pubsub nodes on client '%s' - IQ could not be created\n", client->
name);
4039 IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->
mid,
4042 iks_delete(request);
4062 e->
command =
"xmpp list nodes";
4064 "Usage: xmpp list nodes <connection> [collection]\n" 4065 " Lists the user's nodes on the respective connection\n" 4066 " ([connection] as configured in xmpp.conf.)\n";
4074 }
else if (a->
argc == 4 || a->
argc == 5) {
4079 collection = a->
argv[4];
4082 if (!cfg || !cfg->clients || !(clientcfg =
xmpp_config_find(cfg->clients, name))) {
4083 ast_cli(a->
fd,
"Unable to find client '%s'!\n", name);
4087 ast_cli(a->
fd,
"Listing pubsub nodes.\n");
4105 if (iks_has_children(pak->query)) {
4106 item = iks_first_tag(pak->query);
4108 iks_find_attrib(item,
"node"));
4109 while ((item = iks_next_tag(item))) {
4118 return IKS_FILTER_EAT;
4126 IKS_PAK_IQ, IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, client->
mid,
4129 iks_delete(request);
4148 e->
command =
"xmpp purge nodes";
4150 "Usage: xmpp purge nodes <connection> <node>\n" 4151 " Purges nodes on PubSub server\n" 4152 " as configured in xmpp.conf.\n";
4163 if (!cfg || !cfg->clients || !(clientcfg =
xmpp_config_find(cfg->clients, name))) {
4164 ast_cli(a->
fd,
"Unable to find client '%s'!\n", name);
4193 e->
command =
"xmpp delete node";
4195 "Usage: xmpp delete node <connection> <node>\n" 4196 " Deletes a node on PubSub server\n" 4197 " as configured in xmpp.conf.\n";
4208 if (!cfg || !cfg->clients || !(clientcfg =
xmpp_config_find(cfg->clients, name))) {
4209 ast_cli(a->
fd,
"Unable to find client '%s'!\n", name);
4226 const char *
name, *collection_name;
4230 e->
command =
"xmpp create collection";
4232 "Usage: xmpp create collection <connection> <collection>\n" 4233 " Creates a PubSub collection node using the account\n" 4234 " as configured in xmpp.conf.\n";
4244 collection_name = a->
argv[4];
4246 if (!cfg || !cfg->clients || !(clientcfg =
xmpp_config_find(cfg->clients, name))) {
4247 ast_cli(a->
fd,
"Unable to find client '%s'!\n", name);
4251 ast_cli(a->
fd,
"Creating test PubSub node collection.\n");
4266 const char *
name, *collection_name, *leaf_name;
4270 e->
command =
"xmpp create leaf";
4272 "Usage: xmpp create leaf <connection> <collection> <leaf>\n" 4273 " Creates a PubSub leaf node using the account\n" 4274 " as configured in xmpp.conf.\n";
4284 collection_name = a->
argv[4];
4285 leaf_name = a->
argv[5];
4287 if (!cfg || !cfg->clients || !(clientcfg =
xmpp_config_find(cfg->clients, name))) {
4288 ast_cli(a->
fd,
"Unable to find client '%s'!\n", name);
4292 ast_cli(a->
fd,
"Creating test PubSub node collection.\n");
4308 e->
command =
"xmpp set debug {on|off}";
4310 "Usage: xmpp set debug {on|off}\n" 4311 " Enables/disables dumping of XMPP/Jabber packets for debugging purposes.\n";
4321 if (!strncasecmp(a->
argv[e->
args - 1],
"on", 2)) {
4323 ast_cli(a->
fd,
"XMPP Debugging Enabled.\n");
4325 }
else if (!strncasecmp(a->
argv[e->
args - 1],
"off", 3)) {
4327 ast_cli(a->
fd,
"XMPP Debugging Disabled.\n");
4346 e->
command =
"xmpp show connections";
4348 "Usage: xmpp show connections\n" 4349 " Shows state of client and component connections\n";
4355 if (!cfg || !cfg->clients) {
4359 ast_cli(a->
fd,
"Jabber Users and their status:\n");
4367 state =
"Disconnecting";
4370 state =
"Disconnected";
4373 state =
"Connecting";
4376 state =
"Waiting to request TLS";
4379 state =
"Requested TLS";
4382 state =
"Waiting to authenticate";
4385 state =
"Authenticating";
4388 state =
"Retrieving roster";
4391 state =
"Connected";
4422 e->
command =
"xmpp show buddies";
4424 "Usage: xmpp show buddies\n" 4425 " Shows buddy lists of our clients\n";
4431 if (!cfg || !cfg->clients) {
4510 if (!strcasecmp(var->
name,
"debug")) {
4512 }
else if (!strcasecmp(var->
name,
"autoprune")) {
4514 }
else if (!strcasecmp(var->
name,
"autoregister")) {
4516 }
else if (!strcasecmp(var->
name,
"auth_policy")) {
4518 }
else if (!strcasecmp(var->
name,
"collection_nodes")) {
4520 }
else if (!strcasecmp(var->
name,
"pubsub_autocreate")) {
4533 if (!strcasecmp(var->
name,
"debug")) {
4535 }
else if (!strcasecmp(var->
name,
"type")) {
4537 }
else if (!strcasecmp(var->
name,
"distribute_events")) {
4539 }
else if (!strcasecmp(var->
name,
"usetls")) {
4541 }
else if (!strcasecmp(var->
name,
"usesasl")) {
4543 }
else if (!strcasecmp(var->
name,
"forceoldssl")) {
4545 }
else if (!strcasecmp(var->
name,
"keepalive")) {
4547 }
else if (!strcasecmp(var->
name,
"autoprune")) {
4550 }
else if (!strcasecmp(var->
name,
"autoregister")) {
4553 }
else if (!strcasecmp(var->
name,
"auth_policy")) {
4556 }
else if (!strcasecmp(var->
name,
"sendtodialplan")) {
4569 if (!strcasecmp(var->
value,
"unavailable")) {
4570 cfg->
status = IKS_SHOW_UNAVAILABLE;
4571 }
else if (!strcasecmp(var->
value,
"available") || !strcasecmp(var->
value,
"online")) {
4572 cfg->
status = IKS_SHOW_AVAILABLE;
4573 }
else if (!strcasecmp(var->
value,
"chat") || !strcasecmp(var->
value,
"chatty")) {
4574 cfg->
status = IKS_SHOW_CHAT;
4575 }
else if (!strcasecmp(var->
value,
"away")) {
4576 cfg->
status = IKS_SHOW_AWAY;
4577 }
else if (!strcasecmp(var->
value,
"xa") || !strcasecmp(var->
value,
"xaway")) {
4578 cfg->
status = IKS_SHOW_XA;
4579 }
else if (!strcasecmp(var->
value,
"dnd")) {
4580 cfg->
status = IKS_SHOW_DND;
4581 }
else if (!strcasecmp(var->
value,
"invisible")) {
4582 #ifdef IKS_SHOW_INVISIBLE 4583 cfg->
status = IKS_SHOW_INVISIBLE;
4585 cfg->
status = IKS_SHOW_DND;
4686 ast_log(
LOG_WARNING,
"Entity ID is not set. The distributing device state or MWI will not work.\n");
static struct ast_xmpp_buddy * xmpp_client_create_buddy(struct ao2_container *container, const char *id)
Internal function which creates a buddy on a client.
#define BUDDY_NOT_IN_ROSTER
static int global_bitfield_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
static int acf_jabberstatus_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
enum sip_cc_notify_state state
int ast_xmpp_chatroom_leave(struct ast_xmpp_client *client, const char *room, const char *nickname)
Leave an XMPP multi-user chatroom.
int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
executes a read operation on a function
Main Channel structure associated with a channel.
static int xmpp_client_service_discovery_get_hook(void *data, ikspak *pak)
Hook function called when client receives a service discovery get message.
int ast_xmpp_chatroom_send(struct ast_xmpp_client *client, const char *nickname, const char *address, const char *message)
Send a message to an XMPP multi-user chatroom.
#define AST_CLI_DEFINE(fn, txt,...)
ast_device_state
Device States.
static int xmpp_resource_hash(const void *obj, const int flags)
Hashing function for XMPP resource.
int ast_msg_set_tech(struct ast_msg *msg, const char *fmt,...)
Set the technology associated with this message.
#define AST_LIST_LOCK(head)
Locks a list.
static int xmpp_client_authenticate_sasl(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
Internal function called when we need to authenticate using SASL.
void astman_append(struct mansession *s, const char *fmt,...)
Asterisk main include file. File version handling, generic pbx functions.
static void xmpp_pubsub_create_collection(struct ast_xmpp_client *client, const char *collection_name)
Create a PubSub collection node.
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
static int client_buddy_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
static char * xmpp_cli_create_collection(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Method to expose PubSub collection node creation via CLI.
static void sleep_with_backoff(unsigned int *sleep_time)
static struct aco_type global
static void * ast_xmpp_client_config_alloc(const char *cat)
Allocator function for configuration.
XMPP Client Configuration.
CONFIG_INFO_STANDARD(cfg_info, globals, xmpp_config_alloc,.files=ACO_FILES(&res_xmpp_conf),.post_apply_config=xmpp_config_post_apply,)
static int manager_jabber_send(struct mansession *s, const struct message *m)
int ast_msg_set_context(struct ast_msg *msg, const char *fmt,...)
Set the dialplan context for this message.
#define aco_option_register_custom(info, name, matchtype, types, default_val, handler, flags)
Register a config option.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
char * ast_eid_to_str(char *s, int maxlen, struct ast_eid *eid)
Convert an EID to a string.
static int xmpp_client_receive(struct ast_xmpp_client *client, unsigned int timeout)
Internal function which receives data from the XMPP client connection.
static int xmpp_client_unsubscribe_user(struct ast_xmpp_client *client, const char *user)
Helper function which unsubscribes a user and removes them from the roster.
int ast_msg_set_body(struct ast_msg *msg, const char *fmt,...)
Set the 'body' text of a message (in UTF-8)
struct ast_endpoint * ast_endpoint_create(const char *tech, const char *resource)
Create an endpoint struct.
#define ast_set2_flag(p, value, flag)
#define ast_test_flag(p, flag)
static char * xmpp_cli_delete_pubsub_node(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Method to expose PubSub node deletion via CLI.
static iks * xmpp_pubsub_build_node_config(iks *pubsub, const char *node_type, const char *collection_name)
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
static int xmpp_config_prelink(void *newitem)
static int xmpp_client_service_discovery_result_hook(void *data, ikspak *pak)
Hook function called when client receives a service discovery result message.
static int xmpp_pubsub_delete_node_list(void *data, ikspak *pak)
Delete pubsub item lists.
static int xmpp_leave_exec(struct ast_channel *chan, const char *data)
Application to leave a chat room.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
static int xmpp_component_service_discovery_items_hook(void *data, ikspak *pak)
Hook function called when we receive a service discovery items request.
descriptor for a cli entry.
int ast_xmpp_chatroom_invite(struct ast_xmpp_client *client, const char *user, const char *room, const char *message)
Invite a user to an XMPP multi-user chatroom.
static void * xmpp_config_find(struct ao2_container *tmp_container, const char *category)
Find function for configuration.
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
static void xmpp_pubsub_mwi_cb(void *data, struct stasis_subscription *sub, struct stasis_message *msg)
Callback function for MWI events.
int64_t ast_tvdiff_sec(struct timeval end, struct timeval start)
Computes the difference (in seconds) between two struct timeval instances.
static int debug
Global debug status.
static void xmpp_config_post_apply(void)
static int xmpp_send_cb(const struct ast_msg *msg, const char *to, const char *from)
#define ao2_callback(c, flags, cb_fn, arg)
static AO2_GLOBAL_OBJ_STATIC(globals)
struct ast_msg * ast_msg_alloc(void)
Allocate a message.
#define aco_option_register(info, name, matchtype, types, default_val, opt_type, flags,...)
Register a config option.
#define RESOURCE_BUCKETS
Number of buckets for resources (per buddy)
enum ast_device_state state
static int xmpp_client_authenticating(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
Internal function called when we are authenticating.
int stasis_subscription_is_subscribed(const struct stasis_subscription *sub)
Returns whether a subscription is currently subscribed.
void ast_xmpp_increment_mid(char *mid)
Helper function which increments the message identifier.
static void * xmpp_client_thread(void *data)
XMPP client connection thread.
static char * xmpp_cli_purge_pubsub_nodes(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Method to purge PubSub nodes via CLI.
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
int ast_xmpp_chatroom_join(struct ast_xmpp_client *client, const char *room, const char *nickname)
Join an XMPP multi-user chatroom.
Structure for variables, used for configurations and for channel variables.
const ast_string_field password
struct ast_xmpp_message::@329 list
static void xmpp_pubsub_request_nodes(struct ast_xmpp_client *client, const char *collection)
Request item list from pubsub.
static struct ast_xmpp_client * xmpp_client_alloc(const char *name)
Allocator function for ast_xmpp_client.
const char *const name
Name of this message technology.
static int xmpp_client_request_tls(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
Internal function called when we need to request TLS support.