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.
Assume that the ao2_container is already locked.
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
int stasis_subscription_set_filter(struct stasis_subscription *subscription, enum stasis_subscription_message_filter filter)
Set the message type filtering level on a subscription.
void ast_xmpp_client_lock(struct ast_xmpp_client *client)
Lock an XMPP client connection.
#define XMPP_MAX_ATTRLEN
Maximum size of an attribute.
static int xmpp_client_send_disco_info_request(struct ast_xmpp_client *client, const char *to, const char *from)
Helper function which sends a discovery information request to a user.
int ast_msg_tech_register(const struct ast_msg_tech *tech)
Register a message technology.
static void xmpp_resource_destructor(void *obj)
Destructor callback function for XMPP resource.
#define ast_cond_init(cond, attr)
char resource[XMPP_MAX_RESJIDLEN]
#define ast_cli_register_multiple(e, len)
Register multiple commands.
enum aco_process_status aco_process_config(struct aco_info *info, int reload)
Process a config info via the options registered with an aco_info.
static char * xmpp_show_buddies(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static struct aco_type item
#define ao2_global_obj_ref(holder)
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
enum ast_devstate_cache cachable
static char * xmpp_cli_create_leafnode(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Method to expose PubSub leaf node creation via CLI.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
void ast_endpoint_set_state(struct ast_endpoint *endpoint, enum ast_endpoint_state state)
Updates the state of the given endpoint.
static int xmpp_roster_hook(void *data, ikspak *pak)
Hook function called when roster is received from server.
struct ast_json * ast_json_load_string(const char *input, struct ast_json_error *error)
Parse null terminated string into a JSON object or array.
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
#define ao2_link_flags(container, obj, flags)
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
#define ast_mutex_lock(a)
static int match(struct ast_sockaddr *addr, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
#define ast_copy_flags(dest, src, flagz)
static int xmpp_client_config_merge_buddies(void *obj, void *arg, int flags)
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
void ast_verbose(const char *fmt,...)
static int xmpp_buddy_cmp(void *obj, void *arg, int flags)
Comparator function for XMPP buddy.
#define ast_strdup(str)
A wrapper for strdup()
Defined handlers for XMPP client states.
struct stasis_topic * ast_mwi_topic_all(void)
Get the Stasis Message Bus API topic for MWI messages.
struct ao2_container * stasis_cache_dump(struct stasis_cache *cache, struct stasis_message_type *type)
Dump cached items to a subscription for the ast_eid_default entity.
Out-of-call text message support.
struct stasis_subscription * device_state_sub
The representation of a single configuration file to be processed.
void ast_cli(int fd, const char *fmt,...)
static int xmpp_component_register_get_hook(void *data, ikspak *pak)
Hook function called when the component is queried about registration.
static void xmpp_pubsub_devstate_cb(void *data, struct stasis_subscription *sub, struct stasis_message *msg)
Callback function for device state events.
int ast_unregister_application(const char *app)
Unregister an application.
static void xmpp_init_event_distribution(struct ast_xmpp_client *client)
Initialize collections for event distribution.
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
#define ACO_TYPES(...)
A helper macro to ensure that aco_info types always have a sentinel.
const char * ast_msg_get_body(const struct ast_msg *msg)
Get the body of a message.
static struct ast_custom_function jabberstatus_function
struct ast_xmpp_client * ast_xmpp_client_find(const char *name)
Find an XMPP client connection using a given name.
static struct ast_str * password
An Entity ID is essentially a MAC address, brief and unique.
JSON parsing error information.
static void xmpp_pubsub_subscribe(struct ast_xmpp_client *client, const char *node)
Subscribe to a PubSub node.
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
int ast_msg_set_to(struct ast_msg *msg, const char *fmt,...)
Set the 'to' URI of a message.
struct ast_xmpp_client::@330 messages
int ast_eid_cmp(const struct ast_eid *eid1, const struct ast_eid *eid2)
Compare two EIDs.
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
int args
This gets set in ast_cli_register()
static int cached_devstate_cb(void *obj, void *arg, int flags)
static int unload_module(void)
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
pthread_cond_t ast_cond_t
static void xmpp_client_set_presence(struct ast_xmpp_client *client, const char *to, const char *from, int level, const char *desc)
Internal function which changes the presence status of an XMPP client.
#define ast_strlen_zero(foo)
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
#define ast_pthread_create_background(a, b, c, d)
static char * xmpp_do_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static const struct xmpp_state_handler xmpp_state_handlers[]
static char mailbox[AST_MAX_MAILBOX_UNIQUEID]
struct stasis_message_type * ast_device_state_message_type(void)
Get the Stasis message type for device state messages.
unsigned int stream_flags
static int xmpp_pubsub_handle_event(void *data, ikspak *pak)
Callback for handling PubSub events.
#define BUDDY_BUCKETS
Number of buckets for buddies (per client)
#define EVENT_FLAG_SYSTEM
#define ast_debug(level,...)
Log a DEBUG message.
struct stasis_subscription * mwi_sub
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
static const char * app_ajisendgroup
int ast_devstate_changed(enum ast_device_state state, enum ast_devstate_cache cachable, const char *fmt,...)
Tells Asterisk the State for Device is changed.
int aco_info_init(struct aco_info *info)
Initialize an aco_info structure.
static const char * app_ajistatus
enum ast_device_state ast_devstate_val(const char *val)
Convert device state from text to integer value.
#define XMPP_MAX_RESJIDLEN
Maximum size of a resource JID.
Asterisk JSON abstraction layer.
static int xmpp_component_register_set_hook(void *data, ikspak *pak)
Hook function called when someone registers to the component.
static int xmpp_client_authenticate_digest(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
Internal function called when we need to authenticate using non-SASL.
static const struct ast_msg_tech msg_tech
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Type for default option handler for unsigned integers.
static void xmpp_pubsub_purge_nodes(struct ast_xmpp_client *client, const char *collection_name)
const struct ast_eid * eid
The EID of the server where this message originated.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define AST_PTHREADT_NULL
#define STATUS_DISAPPEAR
Status for a disappearing buddy.
#define ast_poll(a, b, c)
Data structure associated with a custom dialplan function.
#define AST_STRING_FIELD(name)
Declare a string field.
static int xmpp_client_reconnect(struct ast_xmpp_client *client)
Internal function used to reconnect an XMPP client to its server.
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
#define ao2_ref(o, delta)
In case you didn't read that giant block of text above the mansession_session struct, the struct mansession is named this solely to keep the API the same in Asterisk. This structure really represents data that is different from Manager action to Manager action. The mansession_session pointer contained within points to session-specific data.
static struct agi_command commands[]
AGI commands list.
static void ast_xmpp_client_config_destructor(void *obj)
Destructor function for configuration.
int ast_str_to_eid(struct ast_eid *eid, const char *s)
Convert a string into an EID.
static void * xmpp_config_alloc(void)
Allocator for XMPP configuration.
#define ast_strdupa(s)
duplicate a string in memory from the stack
const ast_string_field user
const ast_string_field statusmsg
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
struct ao2_container * container
static struct console_pvt globals
static int delete_old_messages(struct ast_xmpp_client *client, char *from)
#define ast_cond_broadcast(cond)
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
int ast_msg_set_var(struct ast_msg *msg, const char *name, const char *value)
Set a variable on the message going to the dialplan.
struct aco_type * client_options[]
struct ao2_container * buddies
int ast_xmpp_client_disconnect(struct ast_xmpp_client *client)
Disconnect an XMPP client connection.
static int xmpp_pak_presence(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, iks *node, ikspak *pak)
Internal function called when a presence message is received.
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
static int xmpp_is_secure(struct ast_xmpp_client *client)
Helper function which returns whether an XMPP client connection is secure or not. ...
#define stasis_subscribe(topic, callback, data)
static struct ast_custom_function jabberreceive_function
int ast_publish_mwi_state_full(const char *mailbox, const char *context, int new_msgs, int old_msgs, const char *channel_id, struct ast_eid *eid)
Publish a MWI state update via stasis with all parameters.
Their was an error and no changes were applied.
static struct ast_cli_entry xmpp_cli[]
void ast_sha1_hash(char *output, const char *input)
Produces SHA1 hash based on input string.
static int xmpp_resource_immediate(void *obj, void *arg, int flags)
Internal astobj2 callback function which returns the first resource, which is the highest priority on...
static int acf_jabberreceive_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
static int xmpp_client_send_raw_message(struct ast_xmpp_client *client, const char *message)
Internal function which sends a raw message.
const char * ast_devstate_str(enum ast_device_state devstate) attribute_pure
Convert device state to text string that is easier to parse.
int ast_msg_queue(struct ast_msg *msg)
Queue a message for routing through the dialplan.
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
static iks * xmpp_pubsub_build_node_request(struct ast_xmpp_client *client, const char *collection)
Build the a node request.
const ast_string_field name
Configuration option-handling.
static int client_bitfield_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
int ast_publish_device_state_full(const char *device, enum ast_device_state state, enum ast_devstate_cache cachable, struct ast_eid *eid)
Publish a device state update with EID.
const SSL_METHOD * ssl_method
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
struct stasis_cache * ast_device_state_cache(void)
Backend cache for ast_device_state_topic_cached()
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
static void xmpp_pubsub_create_affiliations(struct ast_xmpp_client *client, const char *node)
Add Owner affiliations for pubsub node.
int ast_base64encode(char *dst, const unsigned char *src, int srclen, int max)
Encode data in base64.
static int load_module(void)
Load the module.
Defined handlers for different PAK types.
static const char * app_ajisend
static iks * xmpp_pubsub_build_publish_skeleton(struct ast_xmpp_client *client, const char *node, const char *event_type, unsigned int cachable)
Build the skeleton of a publish.
static int xmpp_pubsub_receive_node_list(void *data, ikspak *pak)
Receive pubsub item lists.
int ast_msg_tech_unregister(const struct ast_msg_tech *tech)
Unregister a message technology.
static int xmpp_buddy_hash(const void *obj, const int flags)
Hashing function for XMPP buddy.
static void xmpp_message_destroy(struct ast_xmpp_message *message)
Destroy function for XMPP messages.
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
void aco_info_destroy(struct aco_info *info)
Destroy an initialized aco_info struct.
static void xmpp_config_destructor(void *obj)
Destructor for XMPP configuration.
#define ao2_global_obj_release(holder)
static int xmpp_ping_request(struct ast_xmpp_client *client, const char *to, const char *from)
Helper function which sends a ping request to a server.
struct ast_xmpp_client * client
#define AST_NONSTANDARD_APP_ARGS(args, parse, sep)
Performs the 'nonstandard' argument separation process for an application.
static int xmpp_config_cmp(void *obj, void *arg, int flags)
Comparator function for configuration.
static int xmpp_send_stream_header(struct ast_xmpp_client *client, const struct ast_xmpp_client_config *cfg, const char *to)
Helper function which sends an XMPP stream header to the server.
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
static void xmpp_pubsub_publish_mwi(struct ast_xmpp_client *client, const char *mailbox, const char *oldmsgs, const char *newmsgs)
Publish MWI to a PubSub node.
#define stasis_subscribe_pool(topic, callback, data)
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
static struct aco_type client_option
struct stasis_subscription * stasis_unsubscribe(struct stasis_subscription *subscription)
Cancel a subscription.
#define ao2_iterator_next(iter)
#define ast_cond_destroy(cond)
const ast_string_field context
#define ao2_alloc(data_size, destructor_fn)
struct stasis_topic * ast_device_state_topic_all(void)
Get the Stasis topic for device state messages.
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
static void xmpp_pubsub_create_node(struct ast_xmpp_client *client, const char *node_type, const char *name, const char *collection_name)
Create a pubsub node.
static char version[AST_MAX_EXTENSION]
static void parse(struct mgcp_request *req)
static void xmpp_log_hook(void *data, const char *xmpp, size_t size, int incoming)
Logging hook function.
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
static int xmpp_send_exec(struct ast_channel *chan, const char *data)
static int xmpp_sendgroup_exec(struct ast_channel *chan, const char *data)
Application to send a message to a groupchat.
#define ast_calloc(num, len)
A wrapper for calloc()
static int client_status_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
struct ast_endpoint * endpoint
static int xmpp_client_requested_tls(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
Internal function called when we receive a response to our TLS initiation request.
static int xmpp_io_recv(struct ast_xmpp_client *client, char *buffer, size_t buf_len, int timeout)
Internal function which polls on an XMPP client and receives data.
#define STRFLDSET(type,...)
Convert a struct and a list of stringfield fields to an argument list of field offsets.
struct stasis_subscription * stasis_unsubscribe_and_join(struct stasis_subscription *subscription)
Cancel a subscription, blocking until the last message is processed.
struct stasis_message_type * ast_mwi_state_type(void)
Get the Stasis Message Bus API message type for MWI messages.
static char * xmpp_cli_list_pubsub_nodes(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Module has failed to load, may be in an inconsistent state.
static ast_mutex_t messagelock
#define ao2_find(container, arg, flags)
struct ao2_container * resources
static int unsubscribe(void *obj, void *arg, int flags)
static int request(void *obj)
static int xmpp_action_hook(void *data, int type, iks *node)
Action hook for when things occur.
static int xmpp_client_config_post_apply(void *obj, void *arg, int flags)
static struct aco_type global_option
static int xmpp_client_subscribe_user(void *obj, void *arg, int flags)
Callback function which subscribes to a user if needed.
structure to hold users read from users.conf
static void xmpp_pubsub_publish_device_state(struct ast_xmpp_client *client, const char *device, const char *device_state, unsigned int cachable)
Publish device state to a PubSub node.
Structure used to handle boolean flags.
const ast_string_field oauth_secret
const ast_string_field name
static int xmpp_resource_cmp(void *obj, void *arg, int flags)
Comparator function for XMPP resource.
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
struct aco_file res_xmpp_conf
int ast_msg_set_from(struct ast_msg *msg, const char *fmt,...)
Set the 'from' URI of a message.
static void xmpp_client_destructor(void *obj)
Destructor callback function for XMPP client.
struct ast_eid ast_eid_default
Global EID.
struct ao2_container * buddies
static void xmpp_pubsub_unsubscribe(struct ast_xmpp_client *client, const char *node)
Unsubscribe from a PubSub node.
static ast_cond_t message_received_condition
static void xmpp_buddy_destructor(void *obj)
Destructor callback function for XMPP buddy.
char * strsep(char **str, const char *delims)
static int xmpp_pak_s10n(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, iks *node, ikspak *pak)
Internal function called when a subscription message is received.
struct aco_type * global_options[]
int ast_msg_set_endpoint(struct ast_msg *msg, const char *fmt,...)
Set the technology's endpoint associated with this message.
static const char * app_ajijoin
const ast_string_field oauth_clientid
static void xmpp_pubsub_create_leaf(struct ast_xmpp_client *client, const char *collection_name, const char *leaf_name)
Create a PubSub leaf node.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
static int get_buddy_status(struct ast_xmpp_client_config *clientcfg, char *screenname, char *resource)
Standard Command Line Interface.
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Type information about a category-level configurable object.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
struct timeval ast_tv(ast_time_t sec, ast_suseconds_t usec)
Returns a timeval from sec, usec.
const char * ast_channel_name(const struct ast_channel *chan)
static int xmpp_join_exec(struct ast_channel *chan, const char *data)
Application to join a chat room.
const ast_string_field uniqueid
static void handler(const char *name, int response_code, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
static void xmpp_pubsub_delete_node(struct ast_xmpp_client *client, const char *node_name)
Delete a PubSub node.
static BUFHEAD * newbuf(HTAB *hashp, u_int32_t addr, BUFHEAD *prev_bp)
int stasis_subscription_accept_message_type(struct stasis_subscription *subscription, const struct stasis_message_type *type)
Indicate to a subscription that we are interested in a message type.
struct stasis_forward * sub
#define ao2_unlink_flags(container, obj, flags)
Abstract JSON element (object, array, string, int, ...).
Type for default option handler for stringfields.
static int xmpp_pak_message(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, iks *node, ikspak *pak)
Internal function called when a message is received.
void ast_xmpp_client_unlock(struct ast_xmpp_client *client)
Unlock an XMPP client connection.
static const char * app_ajileave
The structure that contains device state.
int error(const char *format,...)
static const struct xmpp_pak_handler xmpp_pak_handlers[]
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
int ast_eid_is_empty(const struct ast_eid *eid)
Check if EID is empty.
#define ast_mutex_init(pmutex)
struct ast_xmpp_global_config * global
static char * openssl_error_string(void)
const ast_string_field refresh_token
static int xmpp_client_send_message(struct ast_xmpp_client *client, int group, const char *nick, const char *address, const char *message)
Internal function used to send a message to a user or chatroom.
static int xmpp_client_authenticate(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
Internal function called when we need to authenticate.
static char context[AST_MAX_CONTEXT]
#define ast_mutex_destroy(a)
struct ast_xmpp_capabilities caps
struct ast_msg * ast_msg_destroy(struct ast_msg *msg)
Destroy an ast_msg.
static int xmpp_component_service_discovery_get_hook(void *data, ikspak *pak)
Hook function called when component receives a service discovery get message.
const ast_string_field server
static int xmpp_pubsub_handle_error(void *data, ikspak *pak)
The structure that contains MWI state.
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
void ast_endpoint_shutdown(struct ast_endpoint *endpoint)
Shutsdown an ast_endpoint.
#define ASTERISK_GPL_KEY
The text the key() function should return.
static char * xmpp_show_clients(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
#define manager_event(category, event, contents,...)
External routines may send asterisk manager events this way.
static void * xmpp_client_find_or_create(const char *category)
Look up existing client or create a new one.
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Asterisk module definitions.
void ast_xmpp_client_unref(struct ast_xmpp_client *client)
Release XMPP client connection reference.
XMPP Global Configuration.
static void xmpp_client_change_state(struct ast_xmpp_client *client, int state)
Internal function which changes the XMPP client state.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
static int fetch_access_token(struct ast_xmpp_client_config *cfg)
static int xmpp_component_authenticating(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
Internal function called when we authenticated as a component.
static int xmpp_component_authenticate(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
Internal function called when we should authenticate as a component.
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ast_cond_timedwait(cond, mutex, time)
#define ast_custom_function_register(acf)
Register a custom function.
struct ast_flags mod_flags
static iks * xmpp_pubsub_iq_create(struct ast_xmpp_client *client, const char *type)
Create an IQ packet.
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
int ast_xmpp_client_send(struct ast_xmpp_client *client, iks *stanza)
Send an XML stanza out using an established XMPP client connection.
struct ao2_container * clients
Structure for mutex and tracking information.
static int xmpp_resource_is_available(void *obj, void *arg, int flags)
Callback function which returns when the resource is available.
static int xmpp_client_set_group_presence(struct ast_xmpp_client *client, const char *room, int level, const char *nick)
int ast_xmpp_client_send_message(struct ast_xmpp_client *client, const char *user, const char *message)
Send a message to a given user using an established XMPP client connection.
#define ast_mutex_unlock(a)
#define AST_APP_ARG(name)
Define an application argument.
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
#define ao2_link(container, obj)
static int xmpp_connect_hook(void *data, ikspak *pak)
Hook function called when client finishes authenticating with the server.