summaryrefslogtreecommitdiff
path: root/res/res_sip_pidf.c
diff options
context:
space:
mode:
authorJoshua Colp <jcolp@digium.com>2013-06-22 14:03:22 +0000
committerJoshua Colp <jcolp@digium.com>2013-06-22 14:03:22 +0000
commit77002bc377f19ea11e60732c486b6ef371688773 (patch)
treec19fd245c519c6d7905403849a7af9c7e4a4be3e /res/res_sip_pidf.c
parentea03516cb5426915d183526335d3a7d662ea29dc (diff)
Merge in current pimp_my_sip work, including:
1. Security events 2. Websocket support 3. Diversion header + redirecting support 4. An anonymous endpoint identifier 5. Inbound extension state subscription support 6. PIDF notify generation 7. One touch recording support (special thanks Sean Bright!) 8. Blind and attended transfer support 9. Automatic inbound registration expiration 10. SRTP support 11. Media offer control dialplan function 12. Connected line support 13. SendText() support 14. Qualify support 15. Inband DTMF detection 16. Call and pickup groups 17. Messaging support Thanks everyone! Side note: I'm reminded of the song "How Far We've Come" by Matchbox Twenty. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@392565 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'res/res_sip_pidf.c')
-rw-r--r--res/res_sip_pidf.c341
1 files changed, 341 insertions, 0 deletions
diff --git a/res/res_sip_pidf.c b/res/res_sip_pidf.c
new file mode 100644
index 000000000..78633da9a
--- /dev/null
+++ b/res/res_sip_pidf.c
@@ -0,0 +1,341 @@
+/*
+ * asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Kevin Harwell <kharwell@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*** MODULEINFO
+ <depend>pjproject</depend>
+ <depend>res_sip</depend>
+ <depend>res_sip_pubsub</depend>
+ <depend>res_sip_exten_state</depend>
+ <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+#include <pjsip.h>
+#include <pjsip_simple.h>
+#include <pjlib.h>
+
+#include "asterisk/module.h"
+#include "asterisk/res_sip.h"
+#include "asterisk/res_sip_exten_state.h"
+
+enum state {
+ NOTIFY_OPEN,
+ NOTIFY_INUSE,
+ NOTIFY_CLOSED
+};
+
+static void exten_state_to_str(int state, char **statestring, char **pidfstate,
+ char **pidfnote, int *local_state)
+{
+ switch (state) {
+ case AST_EXTENSION_RINGING:
+ *statestring = "early";
+ *local_state = NOTIFY_INUSE;
+ *pidfstate = "busy";
+ *pidfnote = "Ringing";
+ break;
+ case AST_EXTENSION_INUSE:
+ *statestring = "confirmed";
+ *local_state = NOTIFY_INUSE;
+ *pidfstate = "busy";
+ *pidfnote = "On the phone";
+ break;
+ case AST_EXTENSION_BUSY:
+ *statestring = "confirmed";
+ *local_state = NOTIFY_CLOSED;
+ *pidfstate = "busy";
+ *pidfnote = "On the phone";
+ break;
+ case AST_EXTENSION_UNAVAILABLE:
+ *statestring = "terminated";
+ *local_state = NOTIFY_CLOSED;
+ *pidfstate = "away";
+ *pidfnote = "Unavailable";
+ break;
+ case AST_EXTENSION_ONHOLD:
+ *statestring = "confirmed";
+ *local_state = NOTIFY_CLOSED;
+ *pidfstate = "busy";
+ *pidfnote = "On hold";
+ break;
+ case AST_EXTENSION_NOT_INUSE:
+ default:
+ /* Default setting */
+ *statestring = "terminated";
+ *local_state = NOTIFY_OPEN;
+ *pidfstate = "--";
+ *pidfnote ="Ready";
+
+ break;
+ }
+}
+
+static pj_xml_attr *create_attr(pj_pool_t *pool, pj_xml_node *node,
+ const char *name, const char *value)
+{
+ pj_xml_attr *attr = PJ_POOL_ALLOC_T(pool, pj_xml_attr);
+
+ pj_strdup2(pool, &attr->name, name);
+ pj_strdup2(pool, &attr->value, value);
+
+ pj_xml_add_attr(node, attr);
+ return attr;
+}
+
+static pj_xml_node *create_node(pj_pool_t *pool, pj_xml_node *parent,
+ const char* name)
+{
+ pj_xml_node *node = PJ_POOL_ALLOC_T(pool, pj_xml_node);
+
+ pj_list_init(&node->attr_head);
+ pj_list_init(&node->node_head);
+
+ pj_strdup2(pool, &node->name, name);
+
+ node->content.ptr = NULL;
+ node->content.slen = 0;
+
+ pj_xml_add_node(parent, node);
+ return node;
+}
+
+static pj_xml_attr *find_node_attr(pj_pool_t* pool, pj_xml_node *parent,
+ const char *node_name, const char *attr_name)
+{
+ pj_str_t name;
+ pj_xml_node *node;
+ pj_xml_attr *attr;
+
+ if (!(node = pj_xml_find_node(parent, pj_cstr(&name, node_name)))) {
+ node = create_node(pool, parent, node_name);
+ }
+
+ if (!(attr = pj_xml_find_attr(node, pj_cstr(&name, attr_name), NULL))) {
+ attr = create_attr(pool, node, attr_name, "");
+ }
+
+ return attr;
+}
+
+/*!
+ * \internal
+ * \brief Adds non standard elements to the xml body
+ *
+ * This is some code that was part of the original chan_sip implementation
+ * that is not part of the RFC 3863 definition, but we are keeping available
+ * for backward compatability. The original comment stated that Eyebeam
+ * supports this format.
+
+ */
+static void add_non_standard(pj_pool_t *pool, pj_xml_node *node, const char *pidfstate)
+{
+ static const char *XMLNS_PP = "xmlns:pp";
+ static const char *XMLNS_PERSON = "urn:ietf:params:xml:ns:pidf:person";
+
+ static const char *XMLNS_ES = "xmlns:es";
+ static const char *XMLNS_RPID_STATUS = "urn:ietf:params:xml:ns:pidf:rpid:status:rpid-status";
+
+ static const char *XMLNS_EP = "xmlns:ep";
+ static const char *XMLNS_RPID_PERSON = "urn:ietf:params:xml:ns:pidf:rpid:rpid-person";
+
+ pj_xml_node *person = create_node(pool, node, "pp:person");
+ pj_xml_node *status = create_node(pool, person, "status");
+
+ if (pidfstate[0] != '-') {
+ pj_xml_node *activities = create_node(pool, status, "ep:activities");
+ pj_strdup2(pool, &activities->content, "ep:");
+ pj_strcat2(&activities->content, pidfstate);
+ }
+
+ create_attr(pool, node, XMLNS_PP, XMLNS_PERSON);
+ create_attr(pool, node, XMLNS_ES, XMLNS_RPID_STATUS);
+ create_attr(pool, node, XMLNS_EP, XMLNS_RPID_PERSON);
+}
+
+static void release_pool(void *obj)
+{
+ pj_pool_t *pool = obj;
+
+ pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
+}
+
+static int pidf_xml_create_body(struct ast_sip_exten_state_data *data, const char *local,
+ const char *remote, struct ast_str **body_text)
+{
+ pjpidf_pres *pres;
+ pjpidf_tuple *tuple;
+ pj_str_t entity, note, id, contact, priority;
+ char *statestring = NULL, *pidfstate = NULL, *pidfnote = NULL;
+ int local_state, size;
+
+ RAII_VAR(pj_pool_t *, pool,
+ pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(),
+ "pidf", 1024, 1024), release_pool);
+
+ exten_state_to_str(data->exten_state, &statestring, &pidfstate,
+ &pidfnote, &local_state);
+
+ if (!(pres = pjpidf_create(pool, pj_cstr(&entity, local)))) {
+ ast_log(LOG_WARNING, "Unable to create PIDF presence\n");
+ return -1;
+ }
+
+ add_non_standard(pool, pres, pidfstate);
+
+ if (!pjpidf_pres_add_note(pool, pres, pj_cstr(&note, pidfnote))) {
+ ast_log(LOG_WARNING, "Unable to add note to PIDF presence\n");
+ return -1;
+ }
+
+ if (!(tuple = pjpidf_pres_add_tuple(pool, pres, pj_cstr(&id, data->exten)))) {
+ ast_log(LOG_WARNING, "Unable to create PIDF tuple\n");
+ return -1;
+ }
+
+ pjpidf_tuple_set_contact(pool, tuple, pj_cstr(&contact, remote));
+ pjpidf_tuple_set_contact_prio(pool, tuple, pj_cstr(&priority, "1"));
+ pjpidf_status_set_basic_open(pjpidf_tuple_get_status(tuple),
+ (pidfstate[0] == 'b') || (local_state != NOTIFY_CLOSED));
+
+ if (!(size = pjpidf_print(pres, ast_str_buffer(*body_text),
+ ast_str_size(*body_text)))) {
+ ast_log(LOG_WARNING, "PIDF body text too large\n");
+ return -1;
+ }
+ *(ast_str_buffer(*body_text) + size) = '\0';
+ ast_str_update(*body_text);
+
+ return 0;
+}
+
+static struct ast_sip_exten_state_provider pidf_xml_provider = {
+ .event_name = "presence",
+ .type = "application",
+ .subtype = "pidf+xml",
+ .body_type = "application/pidf+xml",
+ .create_body = pidf_xml_create_body
+};
+
+static int xpidf_xml_create_body(struct ast_sip_exten_state_data *data, const char *local,
+ const char *remote, struct ast_str **body_text)
+{
+ static pj_str_t STR_ADDR_PARAM = { ";user=ip", 8 };
+ pjxpidf_pres *pres;
+ pj_xml_attr *attr;
+ pj_str_t name, uri;
+ char *statestring = NULL, *pidfstate = NULL, *pidfnote = NULL;
+ int local_state, size;
+
+ RAII_VAR(pj_pool_t *, pool,
+ pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(),
+ "pidf", 1024, 1024), release_pool);
+
+ exten_state_to_str(data->exten_state, &statestring, &pidfstate,
+ &pidfnote, &local_state);
+
+ if (!(pres = pjxpidf_create(pool, pj_cstr(&name, local)))) {
+ ast_log(LOG_WARNING, "Unable to create PIDF presence\n");
+ return -1;
+ }
+
+ attr = find_node_attr(pool, pres, "atom", "id");
+ pj_strdup2(pool, &attr->value, data->exten);
+
+ attr = find_node_attr(pool, pres, "address", "uri");
+
+ uri.ptr = (char*) pj_pool_alloc(pool, strlen(remote) + STR_ADDR_PARAM.slen);
+ pj_strcpy2( &uri, remote);
+ pj_strcat( &uri, &STR_ADDR_PARAM);
+ pj_strdup(pool, &attr->value, &uri);
+
+ create_attr(pool, pj_xml_find_node(pres, pj_cstr(&name, "address")),
+ "priority", "0.80000");
+
+ attr = find_node_attr(pool, pres, "status", "status");
+ pj_strdup2(pool, &attr->value,
+ (local_state == NOTIFY_OPEN) ? "open" :
+ (local_state == NOTIFY_INUSE) ? "inuse" : "closed");
+
+ attr = find_node_attr(pool, pres, "msnsubstatus", "substatus");
+ pj_strdup2(pool, &attr->value,
+ (local_state == NOTIFY_OPEN) ? "online" :
+ (local_state == NOTIFY_INUSE) ? "onthephone" : "offline");
+
+ if (!(size = pjxpidf_print(pres, ast_str_buffer(*body_text),
+ ast_str_size(*body_text)))) {
+ ast_log(LOG_WARNING, "XPIDF body text too large\n");
+ return -1;
+ }
+
+ *(ast_str_buffer(*body_text) + size) = '\0';
+ ast_str_update(*body_text);
+
+ return 0;
+}
+
+static struct ast_sip_exten_state_provider xpidf_xml_provider = {
+ .event_name = "presence",
+ .type = "application",
+ .subtype = "xpidf+xml",
+ .body_type = "application/xpidf+xml",
+ .create_body = xpidf_xml_create_body
+};
+
+static struct ast_sip_exten_state_provider cpim_pidf_xml_provider = {
+ .event_name = "presence",
+ .type = "application",
+ .subtype = "cpim-pidf+xml",
+ .body_type = "application/cpim-pidf+xml",
+ .create_body = xpidf_xml_create_body,
+};
+
+static int load_module(void)
+{
+ if (ast_sip_register_exten_state_provider(&pidf_xml_provider)) {
+ ast_log(LOG_WARNING, "Unable to load provider event_name=%s, body_type=%s",
+ pidf_xml_provider.event_name, pidf_xml_provider.body_type);
+ }
+
+ if (ast_sip_register_exten_state_provider(&xpidf_xml_provider)) {
+ ast_log(LOG_WARNING, "Unable to load provider event_name=%s, body_type=%s",
+ xpidf_xml_provider.event_name, xpidf_xml_provider.body_type);
+ }
+
+ if (ast_sip_register_exten_state_provider(&cpim_pidf_xml_provider)) {
+ ast_log(LOG_WARNING, "Unable to load provider event_name=%s, body_type=%s",
+ cpim_pidf_xml_provider.event_name, cpim_pidf_xml_provider.body_type);
+ }
+
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int unload_module(void)
+{
+ ast_sip_unregister_exten_state_provider(&cpim_pidf_xml_provider);
+ ast_sip_unregister_exten_state_provider(&xpidf_xml_provider);
+ ast_sip_unregister_exten_state_provider(&pidf_xml_provider);
+
+ return 0;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "SIP Extension State PIDF Provider",
+ .load = load_module,
+ .unload = unload_module,
+ .load_pri = AST_MODPRI_CHANNEL_DEPEND,
+);