diff options
Diffstat (limited to 'tinyXCAP/src')
-rw-r--r-- | tinyXCAP/src/txcap.c | 1079 | ||||
-rw-r--r-- | tinyXCAP/src/txcap_action.c | 208 | ||||
-rw-r--r-- | tinyXCAP/src/txcap_auid.c | 325 | ||||
-rw-r--r-- | tinyXCAP/src/txcap_document.c | 137 | ||||
-rw-r--r-- | tinyXCAP/src/txcap_node.c | 155 | ||||
-rw-r--r-- | tinyXCAP/src/txcap_selector.c | 167 |
6 files changed, 2071 insertions, 0 deletions
diff --git a/tinyXCAP/src/txcap.c b/tinyXCAP/src/txcap.c new file mode 100644 index 0000000..5341a30 --- /dev/null +++ b/tinyXCAP/src/txcap.c @@ -0,0 +1,1079 @@ +/*
+* Copyright (C) 2009-2010 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+/**@file txcap.c
+ * @brief RFC 4825 (XCAP) implementation.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "txcap.h"
+
+#include "tinyhttp/thttp_url.h"
+
+/**@defgroup txcap_stack_group XCAP stack
+*/
+
+
+/**@mainpage tinyXCAP API Overview
+*
+*
+* <h1>16 XCAP</h1>
+*
+* The XCAP Framework is mainly based on RFC 4825 and uses tinyHTTP project. The framework can be used to implements advanced OMA functionalities such Enhanced Address Book, Presence Authorization Rules, Service Configuration …
+* At startup the stack will load all supported AUIDs with their default values.
+*
+*
+*
+* <h2>16.1 Initialization</h2>
+*
+* As the XCAP stack depends on the HTTP/HTTPS stack (<a href="http://www.doubango.org/API/tinyHTTP/">tinyHTTP</a>) which uses the network library (<a href="http://www.doubango.org/API/tinyNET/"tinyNET</a>), you MUST call <a href="http://doubango.org/API/tinyNET/tnet_8c.html#affba6c2710347476f615b0135777c640"> tnet_startup()</a> before using any XCAP function (txcap_*). <br>
+* <a href="http://doubango.org/API/tinyNET/tnet_8c.html#ac42b22a7ac5831f04326aee9de033c84"> tnet_cleanup()</a> is used to terminate use of network functions. <br>
+* The example below demonstrates how to create and start a XCAP stack. In this example, the xcap-root URI is http://doubango.org:8080/services and the SIP AOR (used as XUI) is sip:bob@doubango.org.
+*
+* @code
+txcap_stack_handle_t* stack = tsk_null;
+int ret;
+
+tnet_startup();
+
+stack = txcap_stack_create(test_stack_callback, "sip:bob@doubango.org", "mysecret", "http://doubango.org:8080/services",
+
+ // options
+ TXCAP_STACK_SET_OPTION(TXCAP_STACK_OPTION_TIMEOUT, "6000"),
+
+ // stack-level headers (not mandatory)
+ TXCAP_STACK_SET_HEADER("Pragma", "No-Cache"),
+ TXCAP_STACK_SET_HEADER("Connection", "Keep-Alive"),
+ TXCAP_STACK_SET_HEADER("X-3GPP-Intended-Identity", "sip:bob@doubango.org"),
+ TXCAP_STACK_SET_HEADER("User-Agent", "XDM-client/OMA1.1"),
+ TXCAP_STACK_SET_NULL());
+
+if((ret = txcap_stack_start(stack))){
+ goto bail;
+}
+
+// …………
+
+bail:
+ TSK_OBJECT_SAFE_FREE(stack);
+tnet_cleanup();
+
+* @endcode
+*
+* The stack-level headers will be added in all outgoing requests.
+* A stack is a well-defined object and must be destroyed by using @a TSK_OBJECT_SAFE_FREE() macro. The stack will be automatically stopped when destroyed.
+*
+*
+*
+* <h2>16.2 Application Unique ID (AUID) object</h2>
+*
+* An AUID object is defined by:
+* - An id (e.g. “xcap-caps”),
+* - A MIME-Type (e.g. “application/xcap-caps+xml”),
+* - A namespace (e.g. “urn:ietf:params:xml:ns:xcap-caps”),
+* - A document name (e.g. “index”), which defines the name of the default document associated with this AUID
+* - A scope (“global” or “users”)
+*
+* At startup, the stack will load all supported AUIDs with their default values. You can at any time change these values or register your own AUID object. The list of default AUIDs with their default values are shown in the next sections.
+* When you are about to send a request, it’s not mandatory to use a registered AUID but it’s easier to generate the selector as all parameters are pre-configured.
+*
+*
+*
+* <h3>16.2.1 Default AUIDs</h3>
+*
+* The table below shows the default AUIDs as they are defined by the stack at startup.
+* <TABLE BORDER=0 CELLPADDING=0 CELLSPACING=0>
+* <TR VALIGN=TOP>
+* <TD WIDTH=139 BGCOLOR="#d9d9d9">
+*
+* <P STYLE="border: none; padding: 0in"><B>Id</B></P>
+* </TD>
+* <TD WIDTH=132 BGCOLOR="#d9d9d9">
+* <P STYLE="border: none; padding: 0in"><B>MIME-Type</B></P>
+* </TD>
+* <TD WIDTH=120 BGCOLOR="#d9d9d9">
+* <P STYLE="border: none; padding: 0in"><B>Namespace</B></P>
+*
+* </TD>
+* <TD WIDTH=84 BGCOLOR="#d9d9d9">
+* <P STYLE="border: none; padding: 0in"><B>Document </B>
+* </P>
+* </TD>
+* <TD WIDTH=53 BGCOLOR="#d9d9d9">
+* <P STYLE="border: none; padding: 0in"><B>Scope</B></P>
+* </TD>
+*
+* <TD WIDTH=129 BGCOLOR="#d9d9d9">
+* <P STYLE="border: none; padding: 0in"><B>Reference</B></P>
+* </TD>
+* </TR>
+* <TR VALIGN=TOP>
+* <TD WIDTH=139>
+* <P LANG="fr-FR" STYLE="border: none; padding: 0in">xcap-caps</P>
+* </TD>
+*
+* <TD WIDTH=132>
+* <P LANG="fr-FR" STYLE="border: none; padding: 0in">application/xcap-caps+xml</P>
+* </TD>
+* <TD WIDTH=120>
+* <P STYLE="border: none; padding: 0in">urn:ietf:params:xml:ns:xcap-caps</P>
+* </TD>
+* <TD WIDTH=84>
+* <P STYLE="border: none; padding: 0in">index</P>
+*
+* </TD>
+* <TD WIDTH=53>
+* <P STYLE="border: none; padding: 0in">global</P>
+* </TD>
+* <TD WIDTH=129>
+* <P LANG="fr-FR" STYLE="border: none; padding: 0in">RFC
+* 4825 section 12.1</P>
+* </TD>
+* </TR>
+*
+* <TR VALIGN=TOP>
+* <TD WIDTH=139>
+* <P LANG="fr-FR" STYLE="border: none; padding: 0in">resource-lists</P>
+* </TD>
+* <TD WIDTH=132>
+* <P LANG="fr-FR" STYLE="border: none; padding: 0in">application/resource-lists+xml</P>
+* </TD>
+* <TD WIDTH=120>
+*
+* <P STYLE="border: none; padding: 0in">urn:ietf:params:xml:ns:resource-lists</P>
+* </TD>
+* <TD WIDTH=84>
+* <P STYLE="border: none; padding: 0in">index</P>
+* </TD>
+* <TD WIDTH=53>
+* <P STYLE="border: none; padding: 0in">users</P>
+*
+* </TD>
+* <TD WIDTH=129>
+* <P LANG="fr-FR" STYLE="border: none; padding: 0in">RFC
+* 4826 section 3.4.1</P>
+* </TD>
+* </TR>
+* <TR VALIGN=TOP>
+* <TD WIDTH=139>
+* <P LANG="fr-FR" STYLE="border: none; padding: 0in">rls-services</P>
+*
+* </TD>
+* <TD WIDTH=132>
+* <P LANG="fr-FR" STYLE="border: none; padding: 0in">application/rls-services+xml</P>
+* </TD>
+* <TD WIDTH=120>
+* <P STYLE="border: none; padding: 0in">urn:ietf:params:xml:ns:rls-services"</P>
+* </TD>
+* <TD WIDTH=84>
+*
+* <P STYLE="border: none; padding: 0in">index</P>
+* </TD>
+* <TD WIDTH=53>
+* <P STYLE="border: none; padding: 0in">users</P>
+* </TD>
+* <TD WIDTH=129>
+* <P LANG="fr-FR" STYLE="border: none; padding: 0in">RFC
+* 4826 section 4.4.1</P>
+*
+* </TD>
+* </TR>
+* <TR VALIGN=TOP>
+* <TD WIDTH=139>
+* <P LANG="fr-FR" STYLE="border: none; padding: 0in">pres-rules</P>
+* </TD>
+* <TD WIDTH=132>
+* <P LANG="fr-FR" STYLE="border: none; padding: 0in">application/auth-policy+xml</P>
+*
+* </TD>
+* <TD WIDTH=120>
+* <P STYLE="border: none; padding: 0in">urn:ietf:params:xml:ns:pres-rules</P>
+* </TD>
+* <TD WIDTH=84>
+* <P STYLE="border: none; padding: 0in">index</P>
+* </TD>
+* <TD WIDTH=53>
+*
+* <P STYLE="border: none; padding: 0in">users</P>
+* </TD>
+* <TD WIDTH=129>
+* <P LANG="fr-FR" STYLE="border: none; padding: 0in">RFC
+* 5025 section 9.1</P>
+* </TD>
+* </TR>
+* <TR VALIGN=TOP>
+* <TD WIDTH=139>
+*
+* <P LANG="fr-FR" STYLE="border: none; padding: 0in">org.openmobilealliance.pres-rules</P>
+* </TD>
+* <TD WIDTH=132>
+* <P LANG="fr-FR" STYLE="border: none; padding: 0in">application/auth-policy+xml</P>
+* </TD>
+* <TD WIDTH=120>
+* <P STYLE="border: none; padding: 0in">urn:ietf:params:xml:ns:common-policy</P>
+*
+* </TD>
+* <TD WIDTH=84>
+* <P STYLE="border: none; padding: 0in">pres-rules</P>
+* </TD>
+* <TD WIDTH=53>
+* <P STYLE="border: none; padding: 0in">users</P>
+* </TD>
+* <TD WIDTH=129>
+*
+* <P LANG="fr-FR" STYLE="border: none; padding: 0in">[OMA-TS-Presence_SIMPLE_XDM-V1_1-20080627-A]
+* section 5.1.1.2</P>
+* </TD>
+* </TR>
+* <TR VALIGN=TOP>
+* <TD WIDTH=139>
+* <P LANG="fr-FR" STYLE="border: none; padding: 0in">directory</P>
+* </TD>
+* <TD WIDTH=132>
+*
+* <P LANG="fr-FR" STYLE="border: none; padding: 0in">application/directory+xml</P>
+* </TD>
+* <TD WIDTH=120>
+* <P STYLE="border: none; padding: 0in">urn:ietf:params:xml:ns:xcap-directory</P>
+* </TD>
+* <TD WIDTH=84>
+* <P STYLE="border: none; padding: 0in">directory.xml</P>
+*
+* </TD>
+* <TD WIDTH=53>
+* <P STYLE="border: none; padding: 0in">users</P>
+* </TD>
+* <TD WIDTH=129>
+* <P LANG="fr-FR" STYLE="border: none; padding: 0in">draft-garcia-simple-xcap-directory-00
+* section 9.1</P>
+* </TD>
+* </TR>
+*
+* <TR VALIGN=TOP>
+* <TD WIDTH=139>
+* <P LANG="fr-FR" STYLE="border: none; padding: 0in">org.openmobilealliance.xcap-directory</P>
+* </TD>
+* <TD WIDTH=132>
+* <P LANG="fr-FR" STYLE="border: none; padding: 0in">application/vnd.oma.xcap-directory+xml</P>
+* </TD>
+* <TD WIDTH=120>
+*
+* <P STYLE="border: none; padding: 0in">urn:oma:xml:xdm:xcap-directory</P>
+* </TD>
+* <TD WIDTH=84>
+* <P STYLE="border: none; padding: 0in">directory.xml</P>
+* </TD>
+* <TD WIDTH=53>
+* <P STYLE="border: none; padding: 0in">users</P>
+*
+* </TD>
+* <TD WIDTH=129>
+* <P LANG="fr-FR" STYLE="border: none; padding: 0in">[OMA-TS-XDM_Core-V1_1-20080627-A]
+* section 6.7.2.1</P>
+* </TD>
+* </TR>
+* <TR VALIGN=TOP>
+* <TD WIDTH=139>
+* <P LANG="fr-FR" STYLE="border: none; padding: 0in">org.openmobilealliance.pres-content</P>
+*
+* </TD>
+* <TD WIDTH=132>
+* <P LANG="fr-FR" STYLE="border: none; padding: 0in">application/vnd.oma.pres-content+xml</P>
+* </TD>
+* <TD WIDTH=120>
+* <P LANG="fr-FR" STYLE="border: none; padding: 0in">urn:oma:xml:prs:pres-content</P>
+* </TD>
+* <TD WIDTH=84>
+*
+* <P STYLE="border: none; padding: 0in">oma_status-icon/rcs_status_icon</P>
+* </TD>
+* <TD WIDTH=53>
+* <P STYLE="border: none; padding: 0in">users</P>
+* </TD>
+* <TD WIDTH=129>
+* <P LANG="fr-FR" STYLE="border: none; padding: 0in">[OMA-TS-Presence-SIMPLE_Content_XDM-V1_0-20081223-C]
+* section 5.1.2</P>
+*
+* </TD>
+* </TR>
+* <TR VALIGN=TOP>
+* <TD WIDTH=139>
+* <P LANG="fr-FR" STYLE="border: none; padding: 0in">org.openmobilealliance.conv-history</P>
+* </TD>
+* <TD WIDTH=132>
+* <P LANG="en-GB" STYLE="border: none; padding: 0in">application/vnd.oma.im.history-list+xml</P>
+*
+* </TD>
+* <TD WIDTH=120>
+* <P STYLE="border: none; padding: 0in">urn:oma:xml:im:history-list</P>
+* </TD>
+* <TD WIDTH=84>
+* <P LANG="fr-FR" STYLE="border: none; padding: 0in">conv-history</P>
+* </TD>
+* <TD WIDTH=53>
+*
+* <P STYLE="border: none; padding: 0in">users</P>
+* </TD>
+* <TD WIDTH=129>
+* <P STYLE="border: none; padding: 0in">[OMA-TS-IM_XDM-V1_0-20070816-C]
+* <SPAN LANG="fr-FR">section</SPAN>
+* 5.1.2</P>
+* </TD>
+* </TR>
+*
+* <TR VALIGN=TOP>
+* <TD WIDTH=139>
+* <P LANG="fr-FR" STYLE="border: none; padding: 0in">org.openmobilealliance.deferred-list</P>
+* </TD>
+* <TD WIDTH=132>
+* <P LANG="en-GB" STYLE="border: none; padding: 0in">application/vnd.oma.im.deferred-list+xml</P>
+* </TD>
+* <TD WIDTH=120>
+*
+* <P STYLE="border: none; padding: 0in">urn:oma:xml:im:history-list</P>
+* </TD>
+* <TD WIDTH=84>
+* <P LANG="fr-FR" STYLE="border: none; padding: 0in">deferred-list</P>
+* </TD>
+* <TD WIDTH=53>
+* <P STYLE="border: none; padding: 0in">users</P>
+*
+* </TD>
+* <TD WIDTH=129>
+* <P STYLE="border: none; padding: 0in">[OMA-TS-IM_XDM-V1_0-20070816-C]
+* <SPAN LANG="fr-FR">section</SPAN>
+* 5.2.2</P>
+* </TD>
+* </TR>
+* <TR VALIGN=TOP>
+*
+* <TD WIDTH=139>
+* <P LANG="fr-FR" STYLE="border: none; padding: 0in">org.openmobilealliance.group-usage-list</P>
+* </TD>
+* <TD WIDTH=132>
+* <P LANG="fr-FR" STYLE="border: none; padding: 0in">application/vnd.oma.group-usage-list+xml</P>
+* </TD>
+* <TD WIDTH=120>
+* <PRE CLASS="western" STYLE="margin-bottom: 0.2in; border: none; padding: 0in">rn:ietf:params:xml:ns:resource-lists</PRE><P STYLE="border: none; padding: 0in">
+*
+* </P>
+* </TD>
+* <TD WIDTH=84>
+* <P LANG="fr-FR" STYLE="border: none; padding: 0in">index</P>
+* </TD>
+* <TD WIDTH=53>
+* <P LANG="fr-FR" STYLE="border: none; padding: 0in">users</P>
+* </TD>
+*
+* <TD WIDTH=129>
+* <P STYLE="border: none; padding: 0in">[OMA-TS-XDM_Shared-V1_1-20080627-A]
+* subclause 5.2.2</P>
+* </TD>
+* </TR>
+* </TABLE>
+*
+*
+* <h3>16.2.2 AUID registration</h3>
+*
+* === The code below shows how to register two AUIDs. If the AUID object already exist (case-insensitive comparison on the id), then it will be updated. All fields are mandatory (id, mime-type, namespace, document and scope).
+*
+* @code
+txcap_stack_set(stack,
+ TXCAP_STACK_SET_AUID("my-xcap-caps", "application/my-xcap-caps+xml", "urn:ietf:params:xml:ns:my-xcap-caps", "my-document", tsk_true),
+ TXCAP_STACK_SET_AUID("my-resource-lists", "application/my-resource-lists+xml", "urn:ietf:params:xml:ns:my-resource-lists", "my-document", tsk_false),
+
+ TXCAP_STACK_SET_NULL()); // mandatory
+*
+* @endcode
+*
+* The stack should be created as shown at section 16.1.
+* Only AUIDs which don’t appear in the table above should be registered using this method
+*
+*
+
+* <h2>16.3 Selector</h2>
+*
+* The selector is a helper function which could be used to construct XCAP URIs. XCAP URI is constructed as per RFC 4825 section 6. @a TXCAP_SELECTOR_NODE_SET*() macros are used to build a complete and well-formed URI (already percent encoded).
+* All examples below assume that our AOR (used as XUI) is sip:bob@doubango.com, we are using the ‘rcs’list and the xcap-root URI is http://doubango.org:8080/services. All these parameters should be set when the stack is created. You will also notice that TXCAP_SELECTOR_NODE_SET_NULL() macro is used to ends the node selection parameters passed to txcap_selector_get_url(), it’s mandatory and should always be the last one.
+*
+* - Select XDMS capabilities:
+* @code
+char* urlstring = txcap_selector_get_url(stack, "xcap-caps",
+ TXCAP_SELECTOR_NODE_SET_NULL());
+ TSK_DEBUG_INFO("%s\n", urlstring);
+ TSK_FREE(urlstring);
+* @endcode
+*
+* Console Output:
+* <i>http://doubango.org:8080/services/xcap-caps/global/index</i>
+* - Select 'resource-lists' document
+* @code
+char* urlstring = txcap_selector_get_url(stack, "resource-lists",
+ TXCAP_SELECTOR_NODE_SET_NULL());
+TSK_DEBUG_INFO("%s\n", urlstring);
+TSK_FREE(urlstring);
+* @endcode
+*
+* Console Output:
+* <i>http://doubango.org:8080/services/resource-lists/users/sip:bob@doubango.org/index</i>
+*
+* - Select 'rcs' list
+* @code
+char* urlstring = txcap_selector_get_url(stack, "resource-lists",
+ TXCAP_SELECTOR_NODE_SET_ATTRIBUTE("list", "name", "rcs"),
+ TXCAP_SELECTOR_NODE_SET_NULL());
+TSK_DEBUG_INFO("%s\n", urlstring);
+* @endcode
+*
+* Console Output:
+* <i>http://doubango.org:8080/services/resource-lists/users/sip:bob@doubango.org/index/~~/resource-lists/list\%5B\@name=\%22rcs\%22\%5D</i>
+*
+* - Select the 2nd list
+* @code
+char* urlstring = txcap_selector_get_url(stack, "resource-lists",
+ TXCAP_SELECTOR_NODE_SET_POS("list", 2),
+ TXCAP_SELECTOR_NODE_SET_NULL());
+TSK_DEBUG_INFO("%s\n", urlstring);
+TSK_FREE(urlstring);
+* @endcode
+*
+* Console Output:
+* <i>http://doubango.org:8080/services/resource-lists/users/sip:bob@doubango.org/index/~~/resource-lists/list\%5B2\%5D</i>
+*
+* - Select the 4th list using wildcard
+* @code
+urlstring = txcap_selector_get_url(stack, "resource-lists",
+ TXCAP_SELECTOR_NODE_SET_POS("*", 4),
+ TXCAP_SELECTOR_NODE_SET_NULL());
+TSK_DEBUG_INFO("%s\n", urlstring);
+TSK_FREE(urlstring);
+* @endcode
+*
+* Console Output:
+* <i>http://doubango.org:8080/services/resource-lists/users/sip:bob@doubango.org/index/~~/resource-lists/*\%5B4\%5D</i>
+*
+* - Select bob's entry
+* @code
+char* urlstring = txcap_selector_get_url(stack, "resource-lists",
+ TXCAP_SELECTOR_NODE_SET_ATTRIBUTE("list", "name", "rcs"),
+ TXCAP_SELECTOR_NODE_SET_ATTRIBUTE("entry", "uri", "sip:bob@doubango.com"),
+ TXCAP_SELECTOR_NODE_SET_NULL());
+TSK_DEBUG_INFO("%s\n", urlstring);
+TSK_FREE(urlstring);
+* @endcode
+*
+* Console Output:
+* <i>http://doubango.org:8080/services/resource-lists/users/sip:bob@doubango.org/index/~~/resource-lists/list\%5B\@name=\%22rcs\%22\%5D/entry\%5B\@uri=\%22sip:bob@doubango.org\%22\%5D</i>
+*
+* - Select bob’s display-name
+* @code
+char* urlstring = txcap_selector_get_url(stack, "resource-lists",
+ TXCAP_SELECTOR_NODE_SET_ATTRIBUTE("list", "name", "rcs"),
+ TXCAP_SELECTOR_NODE_SET_ATTRIBUTE("entry", "uri", "sip:bob@doubango.org"),
+ TXCAP_SELECTOR_NODE_SET_NAME("display-name"),
+ TXCAP_SELECTOR_NODE_SET_NULL());
+TSK_DEBUG_INFO("%s\n", urlstring);
+TSK_FREE(urlstring);
+* @endcode
+*
+* Console Output:
+* <i>http://doubango.org:8080/services/resource-lists/users/sip:bob@doubango.org/index/~~/resource-lists/list\%5B\@name=\%22rcs\%22\%5D/entry\%5B\@uri=\%22sip:bob@doubango.org\%22\%5D/display-name</i>
+*
+* - Select the display-name of the 1st entry
+* @code
+char* urlstring = txcap_selector_get_url(stack, "resource-lists",
+ TXCAP_SELECTOR_NODE_SET_ATTRIBUTE("list", "name", "rcs"),
+ TXCAP_SELECTOR_NODE_SET_POS("entry", 1),
+ TXCAP_SELECTOR_NODE_SET_NAME("display-name"),
+ TXCAP_SELECTOR_NODE_SET_NULL());
+TSK_DEBUG_INFO("%s\n", urlstring);
+TSK_FREE(urlstring);
+* @endcode
+*
+* Console Output:
+* <i>http://doubango.org:8080/services/resource-lists/users/sip:bob@doubango.org/index/~~/resource-lists/list\%5B\@name=\%22rcs\%22\%5D/entry\%5B1\%5D/display-name</i>
+*
+* - Select bob from position 23
+* @code
+char* urlstring = txcap_selector_get_url(stack, "resource-lists",
+ TXCAP_SELECTOR_NODE_SET_ATTRIBUTE("list", "name", "rcs"),
+ TXCAP_SELECTOR_NODE_SET_POS_ATTRIBUTE("entry", 23, "uri", "sip:bob@doubango.org"),
+ TXCAP_SELECTOR_NODE_SET_NULL());
+TSK_DEBUG_INFO("%s\n", urlstring);
+TSK_FREE(urlstring);
+* @endcode
+*
+* Console Output:
+* <i>http://doubango.org:8080/services/resource-lists/users/sip:bob@doubango.org/index/~~/resource-lists/list\%5B\@name=\%22rcs\%22\%5D/entry\%5B23\%5D\%5B\@uri=\%22sip:bob@doubango.org\%22\%5D</i>
+*
+* - Namespaces test
+* @code
+char* urlstring = txcap_selector_get_url(stack, "resource-lists",
+ TXCAP_SELECTOR_NODE_SET_NAME("foo"),
+ TXCAP_SELECTOR_NODE_SET_NAME("a:bar"),
+ TXCAP_SELECTOR_NODE_SET_NAME("b:baz"),
+ TXCAP_SELECTOR_NODE_SET_NAMESPACE("a", "urn:namespace1-uri"),
+ TXCAP_SELECTOR_NODE_SET_NAMESPACE("b", "urn:namespace2-uri"),
+ TXCAP_SELECTOR_NODE_SET_NULL());
+TSK_DEBUG_INFO("%s\n", urlstring);
+TSK_FREE(urlstring);
+* @endcode
+*
+* Console Output:
+* <i>http://doubango.org:8080/services/resource-lists/users/sip:bob@doubango.org/index/~~/resource-lists/foo/a:bar/b:baz%3Fxmlns(a=\%22urn:namespace1-uri\%22)xmlns(b=\%22urn:namespace2-uri\%22)</i>
+*
+* <h2>16.4 XDMC Usage</h2>
+*
+* It is assumed that the address of the XDMS (or aggregation Proxy) is “doubango.org:8080/services” and thus the XCAP Root URI is “doubango.org:8080/services”. “sip:bob@doubango.org” will be used as the XUI.
+* An XDMC can perform twelve actions:
+* - @ref txcap_action_create_element(): Creates new element by sending a HTTP/HTTPS PUT request. The default Content-Type will be “application/xcap-el+xml”, unless you provide your own Content-Type by using TXCAP_ACTION_SET_HEADER().
+* - @ref txcap_action_create_document(): Creates new document by sending a HTTP/HTTPS PUT request. The default Content-Type will be the one associated with the AUID of the document, unless you provide your own Content-Type by using TXCAP_ACTION_SET_HEADER().
+* - @ref txcap_action_create_attribute(): Creates new attribute by sending a HTTP/HTTPS PUT request. The default Content-Type will be “application/xcap-att+xml”, unless you provide your own Content-Type by using TXCAP_ACTION_SET_HEADER().
+* - @ref txcap_action_replace_element(): Replaces an element by sending a HTTP/HTTPS PUT request. The default Content-Type will be “application/xcap-el+xml”, unless you provide your own Content-Type by using TXCAP_ACTION_SET_HEADER().
+* - @ref txcap_action_replace_document(): Replaces a document by sending a HTTP/HTTPS PUT request. The default Content-Type will be the one associated with the AUID of the document, unless you provide your own Content-Type by using TXCAP_ACTION_SET_HEADER().
+* - @ref txcap_action_replace_attribute(): Replaces an attribute by sending a HTTP/HTTPS PUT request. The default Content-Type will be “application/xcap-att+xml”, unless you provide your own Content-Type by using TXCAP_ACTION_SET_HEADER().
+* - @ref txcap_action_fetch_element(): Retrieves an element from the XDMS by sending a HTTP/HTTPS GET request. The default Content-Type will be “application/xcap-el+xml”, unless you provide your own Content-Type by using TXCAP_ACTION_SET_HEADER().
+* - @ref txcap_action_fetch_document(): Retrieves a document from the XDMS by sending a HTTP/HTTPS GET request. The default Content-Type will be the one associated with the AUID of the document, unless you provide your own Content-Type by using TXCAP_ACTION_SET_HEADER().
+* - @ref txcap_action_fetch_attribute(): Retrieves an attribute from the XDMS by sending a HTTP/HTTPS GET request. The default Content-Type will be “application/xcap-att+xml”, unless you provide your own Content-Type by using TXCAP_ACTION_SET_HEADER().
+* - @ref txcap_action_delete_element(): Deletes an element from the XDMS by sending a HTTP/HTTPS DELETE request.
+* - @ref txcap_action_delete_document(): Deletes a document from the XDMS by sending a HTTP/HTTPS DELETE request.
+* - @ref txcap_action_delete_attribute(): Deletes an attribute from the XDMS by sending a HTTP/HTTPS DELETE request.
+*
+* To understand how the stack is created, please refer to section 16.1.
+*
+*
+* <h3>16.4.1 Retrieving XDMS capabilities</h3>
+* === The code below shows how an XDMC obtains the XDMS capabilities document.
+* @code
+int ret = txcap_action_fetch_document(stack,
+ // selector
+ TXCAP_ACTION_SET_SELECTOR("xcap-caps",
+ TXCAP_SELECTOR_NODE_SET_NULL()),
+ // ends parameters
+ TXCAP_ACTION_SET_NULL()
+ );
+* @endcode
+*
+* The XDMC will send:
+* @code
+GET /services/xcap-caps/global/index HTTP/1.1
+Host: doubango.org:8080
+Connection: Keep-Alive
+User-Agent: XDM-client/OMA1.1
+X-3GPP-Intended-Identity: sip:bob@doubango.org
+Content-Type: application/xcap-caps+xml
+* @endcode
+*
+* <h3>16.4.2 Address Book</h3>
+*
+* === The code below shows how an XDMC obtains URI Lists (Address Book).
+*
+* @code
+int ret = txcap_action_fetch_document(stack,
+ // action-level options
+ TXCAP_ACTION_SET_OPTION(TXCAP_ACTION_OPTION_TIMEOUT, "6000"),
+ //action-level headers
+ TXCAP_ACTION_SET_HEADER("Pragma", "No-Cache"),
+ // selector
+ TXCAP_ACTION_SET_SELECTOR("resource-lists",
+ TXCAP_SELECTOR_NODE_SET_NULL()),
+ // ends parameters
+ TXCAP_ACTION_SET_NULL()
+ );
+* @endcode
+*
+* The XDMC will send:
+* @code
+GET /services/resource-lists/users/sip:bob@doubango.org/index HTTP/1.1
+Host: doubango.org:8080
+Connection: Keep-Alive
+User-Agent: XDM-client/OMA1.1
+X-3GPP-Intended-Identity: sip:bob@doubango.org
+Pragma: No-Cache
+Content-Type: application/resource-lists+xml
+* @endcode
+*
+* === The code below shows how to add a new list to the address book
+* @code
+int ret = txcap_action_create_element(stack,
+ // selector
+ TXCAP_ACTION_SET_SELECTOR("resource-lists",
+ TXCAP_SELECTOR_NODE_SET_ATTRIBUTE("list", "name", "newlist"),
+ TXCAP_SELECTOR_NODE_SET_NULL()),
+ // payload
+ TXCAP_ACTION_SET_PAYLOAD(PAYLOAD, strlen(PAYLOAD)),
+ // ends parameters
+ TXCAP_ACTION_SET_NULL()
+ );
+* @endcode
+*
+* The XDMC will send:
+* @code
+PUT /services/resource-lists/users/sip:bob@doubano.org/index/~~/resource-lists/list\%5B\@name=\%22newlist\%22\%5D HTTP/1.1
+Host: doubango.org:8080
+Content-Length: 110
+Connection: Keep-Alive
+User-Agent: XDM-client/OMA1.1
+X-3GPP-Intended-Identity: sip:bob@doubango.org
+Content-Type: application/xcap-el+xml
+
+<list name="newlist" xmlns="urn:ietf:params:xml:ns:resource-lists"><display-name>newlist</display-name></list>
+* @endcode
+*
+* === The code below shows how to retrieve the previously added list
+* @code
+int ret = txcap_action_fetch_element(stack,
+ // action-level selector
+ TXCAP_ACTION_SET_SELECTOR("resource-lists",
+ TXCAP_SELECTOR_NODE_SET_ATTRIBUTE("list", "name", "newlist"),
+ TXCAP_SELECTOR_NODE_SET_NULL()),
+ // ends parameters
+ TXCAP_ACTION_SET_NULL()
+ );
+* @endcode
+*
+* The XDMC will send:
+* @code
+GET /services/resource-lists/users/sip:bob@doubango.org/index/~~/resource-lists/list\%5B\@name=\%22newlist\%22\%5D HTTP/1.1
+Host: doubango.org:8080
+Connection: Keep-Alive
+User-Agent: XDM-client/OMA1.1
+X-3GPP-Intended-Identity: sip:bob@doubango.org
+Content-Type: application/xcap-el+xml
+** @endcode
+*
+* === The code below shows how to add a new entry (“sip:alice@doubango.org”) to the previously added list
+* @code
+int ret = txcap_action_create_element(stack,
+ // selector
+ TXCAP_ACTION_SET_SELECTOR("resource-lists",
+ TXCAP_SELECTOR_NODE_SET_ATTRIBUTE("list", "name", "newlist"),
+ TXCAP_SELECTOR_NODE_SET_ATTRIBUTE("entry", "uri", “sip:alice@doubango.org”),
+ TXCAP_SELECTOR_NODE_SET_NULL()),
+ // payload
+ TXCAP_ACTION_SET_PAYLOAD(PAYLOAD, strlen(PAYLOAD)),
+ // ends parameters
+ TXCAP_ACTION_SET_NULL()
+ );
+* @endcode
+*
+* The XDMC will send:
+* @code
+PUT /services/resource-lists/users/sip:bob@doubango.org/index/~~/resource-lists/list\%5B\@name=\%22newlist\%22\%5D/entry\%5B\@uri=\%22sip:alice@doubango.org\%22\%5D HTTP/1.1
+Host: doubango.org:8080
+Content-Length: 125
+Connection: Keep-Alive
+User-Agent: XDM-client/OMA1.1
+X-3GPP-Intended-Identity: sip:bob@doubango.org
+Content-Type: application/xcap-el+xml
+
+<entry uri="sip:alice@doubango.org" xmlns="urn:ietf:params:xml:ns:resource-lists"><display-name>alice</display-name></entry>
+* @endcode
+*
+* <h3>16.4.3 Obtaining Presence Content Document </h3>
+*
+* === The code below shows how an XDMC obtains the Presence Content document (avatar).
+*
+* @code
+int ret = txcap_action_fetch_document(stack,
+ // action-level options
+ TXCAP_ACTION_SET_OPTION(TXCAP_ACTION_OPTION_TIMEOUT, "6000"),
+ //action-level headers
+ TXCAP_ACTION_SET_HEADER("Pragma", "No-Cache"),
+ // selector
+ TXCAP_ACTION_SET_SELECTOR("org.openmobilealliance.pres-content",
+ TXCAP_SELECTOR_NODE_SET_NULL()),
+ // ends parameters
+ TXCAP_ACTION_SET_NULL()
+ );
+* @endcode
+*
+* The XDMC will send:
+*
+* @code
+GET /services/org.openmobilealliance.pres-content/users/sip:mamadou@micromethod.com/oma_status-icon/rcs_status_icon HTTP/1.1
+Host: doubango.org:8080
+Connection: Keep-Alive
+User-Agent: XDM-client/OMA1.1
+X-3GPP-Intended-Identity: sip:bob@doubango.org
+Pragma: No-Cache
+Content-Type: application/vnd.oma.pres-content+xml
+* @endcode
+*/
+
+/** Internal function used to set options.
+*/
+int __txcap_stack_set(txcap_stack_t* self, va_list *app)
+{
+ txcap_stack_param_type_t curr;
+ tsk_bool_t cred_updated = tsk_false;
+
+ if(!self || !self->http_session){
+ return -1;
+ }
+
+ while((curr = va_arg(*app, txcap_stack_param_type_t)) != xcapp_null){
+ switch(curr){
+ case xcapp_option:
+ { /* (txcap_stack_option_t)ID_ENUM, (const char*)VALUE_STR */
+ txcap_stack_option_t ID_ENUM = va_arg(*app, txcap_stack_option_t);
+ const char* VALUE_STR = va_arg(*app, const char*);
+ switch(ID_ENUM){
+ case TXCAP_STACK_OPTION_ROOT:
+ {
+ tsk_strupdate(&self->xcap_root, VALUE_STR);
+ break;
+ }
+ /* PASSWORD and XUI are not used as options in the HTTP/HTTPS stack */
+ case TXCAP_STACK_OPTION_PASSWORD:
+ {
+ tsk_strupdate(&self->password, VALUE_STR);
+ cred_updated = tsk_true;
+ break;
+ }
+ case TXCAP_STACK_OPTION_XUI:
+ {
+ tsk_strupdate(&self->xui, VALUE_STR);
+ cred_updated = tsk_true;
+ break;
+ }
+ case TXCAP_STACK_OPTION_LOCAL_IP:
+ {
+ thttp_stack_set(self->http_stack, THTTP_STACK_SET_LOCAL_IP(VALUE_STR),
+ THTTP_STACK_SET_NULL());
+ break;
+ }
+ case TXCAP_STACK_OPTION_LOCAL_PORT:
+ {
+ int port = atoi(VALUE_STR);
+ thttp_stack_set(self->http_stack, THTTP_STACK_SET_LOCAL_PORT(port),
+ THTTP_STACK_SET_NULL());
+ break;
+ }
+ default:
+ { /* HTTP Options: MUST be changed to valid HTTP option enum */
+ switch(ID_ENUM){
+ case TXCAP_STACK_OPTION_TIMEOUT:
+ tsk_options_add_option(&((thttp_session_t*)self->http_session)->options, THTTP_SESSION_OPTION_TIMEOUT, VALUE_STR);
+ break;
+ case TXCAP_STACK_OPTION_TTL:
+ tsk_options_add_option(&((thttp_session_t*)self->http_session)->options, THTTP_SESSION_OPTION_TTL, VALUE_STR);
+ break;
+ default:
+ TSK_DEBUG_WARN("%d is an invalid XCAP option", ID_ENUM);
+ break;
+ }
+
+ break;
+ }
+ }
+ break;
+ }
+
+ case xcapp_header:
+ { /* (const char*)NAME_STR, (const char*)VALUE_STR */
+ const char* NAME_STR = va_arg(*app, const char*);
+ const char* VALUE_STR = va_arg(*app, const char*);
+ if(VALUE_STR == (const char*)-1){
+ tsk_params_remove_param(((thttp_session_t*)self->http_session)->headers, NAME_STR);
+ }
+ else{
+ tsk_params_add_param(&((thttp_session_t*)self->http_session)->headers, NAME_STR, VALUE_STR);
+ }
+ break;
+ }
+
+ case xcapp_userdata:
+ { /* (const void*)CTX_PTR */
+ const void* CTX_PTR = va_arg(*app, const void*);
+ ((thttp_session_t*)self->http_session)->userdata = CTX_PTR;
+ break;
+ }
+
+ case xcapp_auid:
+ { /* (const char*)ID_STR, (const char*)MIME_TYPE_STR, (const char*)NS_STR, (const char*)DOC_NAME_STR, (tsk_bool_t)IS_GLOBAL_BOOL */
+ const char* ID_STR = va_arg(*app, const char*);
+ const char* MIME_TYPE_STR = va_arg(*app, const char*);
+ const char* NS_STR = va_arg(*app, const char*);
+ const char* DOC_NAME_STR = va_arg(*app, const char*);
+ tsk_bool_t IS_GLOBAL_BOOL = va_arg(*app, tsk_bool_t);
+
+ if(txcap_auid_register(self->auids, ID_STR, MIME_TYPE_STR, NS_STR, DOC_NAME_STR, IS_GLOBAL_BOOL)){
+ // do nothing
+ }
+
+ break;
+ }
+
+ default:
+ {
+ TSK_DEBUG_ERROR("NOT SUPPORTED.");
+ goto bail;
+ }
+ } /* switch */
+ } /* while */
+
+ if(cred_updated && self->http_session){
+ /* credentials */
+ thttp_session_set(self->http_session,
+ THTTP_SESSION_SET_CRED(self->xui, self->password),
+ THTTP_SESSION_SET_NULL());
+ }
+ return 0;
+
+bail:
+ return -2;
+}
+
+/**@ingroup txcap_stack_group
+* Creates new XCAP stack.
+* @param callback Poiner to the callback function to call when new messages come to the transport layer.
+* Can be set to Null if you don't want to be alerted.
+* @param xui user's id as per RFC 4825 subclause 4. Also used to fill @b "X-3GPP-Intended-Identity" header.
+* This paramter is mandatory and must not be null. If for any reason you'd like to update the user's id, then use @ref TXCAP_STACK_SET_XUI().
+* @param password user's password used to authenticate to the XDMS.
+* This parameter is not mandatory. If for any reason you'd like to update the password, then use @ref TXCAP_STACK_SET_PASSWORD().
+* @param xcap_root xcap-root URI as per RFC 4825 subclause 6.1, used to build all request-uris.
+* This parameter is not mandatory and must be a valid HTPP/HTTPS URL.
+* @param ... User configuration. You must use @a TXCAP_STACK_SET_*() macros to set these options.
+* The list of options must always end with @ref TXCAP_STACK_SET_NULL() even if these is no option to pass to the stack.
+* @retval A Pointer to the newly created stack if succeed and @a Null otherwise.
+* A stack is a well-defined object.
+*
+* @code
+int test_stack_callback(const thttp_event_t *httpevent);
+
+txcap_stack_handle_t* stack = txcap_stack_create(test_stack_callback, "sip:bob@example.com", "mysecret", "http://doubango.org:8080/services",
+
+ // stack-level options
+ TXCAP_STACK_SET_OPTION(TXCAP_STACK_OPTION_TIMEOUT, "6000"),
+
+ // stack-level headers
+ TXCAP_STACK_SET_HEADER("Connection", "Keep-Alive"),
+ TXCAP_STACK_SET_HEADER("User-Agent", "XDM-client/OMA1.1"),
+ TXCAP_STACK_SET_HEADER("X-3GPP-Intended-Identity", XUI),
+
+ TXCAP_STACK_SET_NULL());
+* @endcode
+*
+* @sa @ref txcap_stack_set
+*/
+txcap_stack_handle_t* txcap_stack_create(thttp_stack_callback_f callback, const char* xui, const char* password, const char* xcap_root, ...)
+{
+ txcap_stack_t* ret = tsk_null;
+
+ if(!xui || !xcap_root){
+ TSK_DEBUG_ERROR("Both xui and xcap_root are mandatory and should be non-null");
+ goto bail;
+ }
+
+ /* check url validity */
+ if(!thttp_url_isvalid(xcap_root)){
+ TSK_DEBUG_ERROR("%s is not a valid HTTP/HTTPS url", xcap_root);
+ goto bail;
+ }
+
+ if(!(ret = tsk_object_new(txcap_stack_def_t, callback, xui, password, xcap_root))){
+ TSK_DEBUG_FATAL("Failed to create the XCAP stack");
+ goto bail;
+ }
+ else{
+ /* set parameters */
+ va_list ap;
+ va_start(ap, xcap_root);
+ __txcap_stack_set(ret, &ap);
+ va_end(ap);
+ /* credendials */
+ tsk_strupdate(&ret->xui, xui);
+ tsk_strupdate(&ret->password, password);
+ if(ret->http_session){
+ thttp_session_set(ret->http_session,
+ THTTP_SESSION_SET_CRED(ret->xui, ret->password),
+ THTTP_SESSION_SET_NULL());
+ }
+ }
+
+bail:
+ return ret;
+}
+
+/**@ingroup txcap_stack_group
+* Starts the stack.
+* @param self A pointer to the stack to stark. The stack shall be created using @ref txcap_stack_create().
+* @retval Zero if succeed and non-zero error code otherwise.
+* @sa @ref txcap_stack_stop
+*/
+int txcap_stack_start(txcap_stack_handle_t* self)
+{
+ int ret = -1;
+ txcap_stack_t* stack = self;
+
+ if(!stack){
+ goto bail;
+ }
+
+ if(!(ret = thttp_stack_start(stack->http_stack))){
+ //if(!stack->http_session){
+ // stack->http_session = thttp_session_create(stack->http_stack ,
+ // THTTP_SESSION_SET_NULL());
+ //}
+ }
+
+bail:
+ return ret;
+}
+
+/**@ingroup txcap_stack_group
+* Updates the stack configuration.
+* @param self The XCAP stack to update. The stack shall be created using @ref txcap_stack_create().
+* @param ... Any @a TXCAP_STACK_SET_*() macros. MUST ends with @ref TXCAP_STACK_SET_NULL().
+* @retval Zero if succeed and non-zero error code otherwise.
+*
+* @code
+txcap_stack_handle_t* stack;
+// ... create the stack
+
+txcap_stack_set(stack,
+ // add new AUIDs
+ TXCAP_STACK_SET_AUID("xcap-caps2", "application/xcap-caps2+xml", "urn:ietf:params:xml:ns:xcap-caps2", "index2", tsk_true),
+ TXCAP_STACK_SET_AUID("resource-lists2", "application/resource-lists+xml2", "urn:ietf:params:xml:ns:resource-lists2", "index2", tsk_false),
+ // stack-level headers
+ TXCAP_STACK_SET_HEADER("Connection", "Keep-Alive"),
+ TXCAP_STACK_SET_HEADER("User-Agent", "XDM-client/OMA1.1"),
+
+ TXCAP_STACK_SET_NULL());
+* @endcode
+*
+* @sa @ref txcap_stack_create
+*/
+int txcap_stack_set(txcap_stack_handle_t* self, ...)
+{
+ int ret = -1;
+ va_list ap;
+
+ if(!self){
+ goto bail;
+ }
+
+ va_start(ap, self);
+ ret = __txcap_stack_set(self, &ap);
+ va_end(ap);
+
+bail:
+ return ret;
+}
+
+/**@ingroup txcap_stack_group
+* Stops the stack. The stack must already be started.
+* @param self A pointer to the stack to stop. The stack shall be created using @ref txcap_stack_create().
+* @retval Zero if succeed and non-zero error code otherwise.
+* @sa @ref txcap_stack_start
+*/
+int txcap_stack_stop(txcap_stack_handle_t* self)
+{
+ int ret = -1;
+ txcap_stack_t* stack = self;
+
+ if(!stack){
+ goto bail;
+ }
+ else{
+ if(!(ret = thttp_stack_stop(stack->http_stack))){
+ //TSK_OBJECT_SAFE_FREE(stack->http_session);
+ }
+ }
+
+bail:
+ return ret;
+}
+
+
+
+
+
+
+
+
+
+//========================================================
+// XCAP stack object definition
+//
+static tsk_object_t* _txcap_stack_create(tsk_object_t * self, va_list * app)
+{
+ txcap_stack_t *stack = self;
+ if(stack){
+ thttp_stack_callback_f callback;
+ tsk_safeobj_init(stack);
+
+ callback = va_arg(*app, thttp_stack_callback_f);
+ stack->xui = tsk_strdup( va_arg(*app, const char*) );
+ stack->password = tsk_strdup( va_arg(*app, const char*) );
+ stack->xcap_root = tsk_strdup( va_arg(*app, const char*) );
+
+ /* HTTP/HTTPS stack and session */
+ stack->http_stack = thttp_stack_create(callback,
+ THTTP_STACK_SET_NULL());
+ stack->http_session = thttp_session_create(stack->http_stack ,
+ THTTP_SESSION_SET_NULL());
+
+ /* Options */
+ stack->options = tsk_list_create();
+
+ /* AUIDs */
+ txcap_auids_init(&stack->auids);
+ }
+ return self;
+}
+
+static tsk_object_t* txcap_stack_destroy(tsk_object_t* self)
+{
+ txcap_stack_t *stack = self;
+ if(stack){
+ /* vars */
+ TSK_FREE(stack->xui);
+ TSK_FREE(stack->password);
+ TSK_FREE(stack->xcap_root);
+
+ /* HTTP/HTTPS resources */
+ TSK_OBJECT_SAFE_FREE(stack->http_session);
+ TSK_OBJECT_SAFE_FREE(stack->http_stack);
+
+ /* Options */
+ TSK_OBJECT_SAFE_FREE(stack->options);
+
+ /* AUIDs */
+ TSK_OBJECT_SAFE_FREE(stack->auids);
+
+ tsk_safeobj_deinit(stack);
+ }
+ return self;
+}
+
+static const tsk_object_def_t txcap_stack_def_s =
+{
+ sizeof(txcap_stack_t),
+ _txcap_stack_create,
+ txcap_stack_destroy,
+ tsk_null,
+};
+const tsk_object_def_t *txcap_stack_def_t = &txcap_stack_def_s;
diff --git a/tinyXCAP/src/txcap_action.c b/tinyXCAP/src/txcap_action.c new file mode 100644 index 0000000..9276273 --- /dev/null +++ b/tinyXCAP/src/txcap_action.c @@ -0,0 +1,208 @@ +/*
+* Copyright (C) 2009-2010 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+/**@file txcap_action.c
+ * @brief XCAP actions.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tinyxcap/txcap_action.h"
+
+#include "tsk_options.h"
+#include "tsk_params.h"
+#include "tinyxcap/txcap_selector.h"
+
+/**@defgroup txcap_action_group XDMC (Sending Requests)
+*/
+
+extern char* __txcap_selector_get_url(const txcap_stack_handle_t* stack, const char* auid_id, va_list* app);
+
+
+/** Sends HTTP/HTTPS request to the XDMS.
+*/
+int txcap_action_perform(txcap_stack_handle_t* stack, txcap_action_type_t type, txcap_action_target_t target, ...)
+{
+ tsk_options_L_t* options = tsk_null;
+ tsk_params_L_t* headers = tsk_null;
+ char* urlstring = tsk_null;
+ thttp_action_t* action;
+ thttp_dialog_t* dialog;
+ int ret = -1;
+ txcap_action_param_type_t curr;
+ const char* method = "GET";
+ const char* mime_type = tsk_null;
+ const char* AUID_STR = tsk_null;
+ const void* PAY_PTR = tsk_null;
+ size_t PAY_SIZE = 0;
+ va_list ap;
+ txcap_stack_t* xcap_stack = stack;
+
+ if(!xcap_stack){
+ goto bail;
+ }
+ else{
+ xcap_stack = tsk_object_ref(stack);
+ options = tsk_list_create();
+ headers = tsk_list_create();
+ }
+
+ va_start(ap, target);
+ while((curr = va_arg(ap, txcap_action_param_type_t)) != txcap_apt_null){
+ switch(curr){
+ case txcap_apt_option:
+ { /*(thttp_action_option_t)ID_INT, (const char*)VALUE_STR*/
+ thttp_action_option_t ID_INT = va_arg(ap, thttp_action_option_t);
+ const char* VALUE_STR = va_arg(ap, const char *);
+ tsk_options_add_option(&options, ID_INT, VALUE_STR);
+ break;
+ }
+ case txcap_apt_header:
+ { /* (const char*)NAME_STR, (const char*)VALUE_STR */
+ const char* NAME_STR = va_arg(ap, const char *);
+ const char* VALUE_STR = va_arg(ap, const char *);
+ if(VALUE_STR == (const char*)-1){
+ tsk_params_remove_param(headers, NAME_STR);
+ }
+ else{
+ tsk_params_add_param(&headers, NAME_STR, VALUE_STR);
+ }
+ break;
+ }
+ case txcap_apt_payload:
+ { /*(const void*)PAY_PTR, (size_t)PAY_SIZE*/
+ PAY_PTR = va_arg(ap, const void *);
+ PAY_SIZE = va_arg(ap, size_t);
+ break;
+ }
+ case txcap_apt_selector:
+ { /*(const char*)AUID_STR, __VA_ARGS__*/
+ AUID_STR = va_arg(ap, const char *);
+ if(!urlstring){
+ urlstring = __txcap_selector_get_url(stack, AUID_STR, &ap);
+ }
+ break;
+ }
+ case txcap_apt_urlstring:
+ { /* (const char*)URI_STR */
+ const char* URI_STR = va_arg(ap, const char *);
+ if(!urlstring){
+ urlstring = tsk_strdup(URI_STR);
+ }
+ break;
+ }
+ default:
+ {
+ TSK_DEBUG_ERROR("NOT SUPPORTED.");
+ goto done;
+ }
+ }/* switch */
+ } /* while */
+
+done:
+ va_end(ap);
+
+ /* checks urlstring */
+ if(!urlstring){
+ TSK_DEBUG_ERROR("Failed to compute XCAP URL");
+ goto bail;
+ }
+
+ /* HTTP method */
+ switch(type){
+ case txcap_atp_create:
+ case txcap_atp_replace:
+ method = "PUT"; break;
+ case txcap_atp_fetch:
+ method = "GET"; break;
+ case txcap_atp_delete:
+ method = "DELETE"; break;
+ }
+
+ /*content-type*/
+ switch(target){
+ case txcap_atg_element:
+ mime_type = TXCAP_MIME_TYPE_ELEMENT; break;
+ case txcap_atg_document:
+ {
+ if(AUID_STR){
+ txcap_auid_t* auid;
+ if((auid = txcap_auid_get_by_id(xcap_stack->auids, AUID_STR))){
+ mime_type = (const char*)auid->mime_type; // (cont char*) do not strdup()
+ TSK_OBJECT_SAFE_FREE(auid);
+ }
+ else{
+ TSK_DEBUG_WARN("Failed to find auid with id=%s", AUID_STR);
+ }
+ }
+ break;
+ }
+ case txcap_atg_attribute:
+ mime_type = TXCAP_MIME_TYPE_ATTRIBUTE; break;
+ }
+
+ /* HTTP action */
+ if((action = thttp_action_create(thttp_atype_o_request, urlstring, method, tsk_null))){
+ const tsk_list_item_t* item;
+ if((dialog = thttp_dialog_new(xcap_stack->http_session))){
+ /* copy options */
+ tsk_list_foreach(item, options){
+ tsk_options_add_option(&action->options, ((const tsk_option_t*)item->data)->id, ((const tsk_option_t*)item->data)->value);
+ }
+ /* copy action-level headers */
+ tsk_list_foreach(item, headers){
+ tsk_params_add_param(&action->headers, ((const tsk_param_t*)item->data)->name, ((const tsk_param_t*)item->data)->value);
+ }
+ /* copy session-level headers ==> will be added by thttp_dialog_send_request()*/
+ //--tsk_list_pushback_list(action->headers, ((thttp_session_t*)xcap_stack->http_session)->headers);
+
+ /* Content-Type */
+ if(mime_type){
+ if(!tsk_params_have_param(action->headers, "Content-Type")){
+ tsk_params_add_param(&action->headers, "Content-Type", mime_type);
+ }
+ }
+
+ /* payload */
+ if(PAY_PTR && PAY_SIZE){
+ action->payload = tsk_buffer_create(PAY_PTR, PAY_SIZE);
+ }
+
+ /* performs */
+ ret = thttp_dialog_fsm_act(dialog, action->type, tsk_null, action);
+ tsk_object_unref(dialog);
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to create new HTTP/HTTPS dialog.");
+ ret = -2;
+ }
+ TSK_OBJECT_SAFE_FREE(action);
+ }
+
+bail:
+ TSK_FREE(urlstring);
+ TSK_OBJECT_SAFE_FREE(options);
+ TSK_OBJECT_SAFE_FREE(headers);
+ tsk_object_unref(xcap_stack);
+ return ret;
+}
+
diff --git a/tinyXCAP/src/txcap_auid.c b/tinyXCAP/src/txcap_auid.c new file mode 100644 index 0000000..731065b --- /dev/null +++ b/tinyXCAP/src/txcap_auid.c @@ -0,0 +1,325 @@ +/*
+* Copyright (C) 2009-2010 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+/**@file txcap_auid.c
+ * @brief XCAP AUID manager.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tinyxcap/txcap_auid.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+
+
+typedef struct auid_s
+{
+ txcap_auid_type_t type;
+ const char* id;
+ const char* mime_type;
+ const char* ns;
+ const char* document_name;
+ tsk_bool_t global;
+}
+auid_t;
+
+/** List of all default auids */
+static const auid_t __txcap_auids[] =
+{
+ /*== xcap-caps ==*/{
+ tauid_ietf_xcap_caps,
+ TXCAP_AUID_IETF_XCAP_CAPS_ID,
+ TXCAP_AUID_IETF_XCAP_CAPS_MIME_TYPE,
+ TXCAP_AUID_IETF_XCAP_CAPS_NS,
+ TXCAP_AUID_IETF_XCAP_CAPS_DOC,
+ tsk_true
+ },
+
+ /*== resource-lists ==*/{
+ tauid_ietf_resource_lists,
+ TXCAP_AUID_IETF_RESOURCE_LISTS_ID,
+ TXCAP_AUID_IETF_RESOURCE_LISTS_MIME_TYPE,
+ TXCAP_AUID_IETF_RESOURCE_LISTS_NS,
+ TXCAP_AUID_IETF_RESOURCE_LISTS_DOC,
+ tsk_false
+ },
+
+ /*== rls-services ==*/{
+ tauid_ietf_rls_services,
+ TXCAP_AUID_IETF_RLS_SERVICES_ID,
+ TXCAP_AUID_IETF_RLS_SERVICES_MIME_TYPE,
+ TXCAP_AUID_IETF_RLS_SERVICES_NS,
+ TXCAP_AUID_IETF_RLS_SERVICES_DOC,
+ tsk_false
+ },
+
+ /*== pres-rules ==*/{
+ tauid_ietf_pres_rules,
+ TXCAP_AUID_IETF_PRES_RULES_ID,
+ TXCAP_AUID_IETF_PRES_RULES_MIME_TYPE,
+ TXCAP_AUID_IETF_PRES_RULES_NS,
+ TXCAP_AUID_IETF_PRES_RULES_DOC,
+ tsk_false
+ },
+
+ /*== pidf-manipulation ==*/{
+ tauid_ietf_pres_rules,
+ TXCAP_AUID_IETF_PIDF_MANIPULATION_ID,
+ TXCAP_AUID_IETF_PIDF_MANIPULATION_MIME_TYPE,
+ TXCAP_AUID_IETF_PIDF_MANIPULATION_NS,
+ TXCAP_AUID_IETF_PIDF_MANIPULATION_DOC,
+ tsk_false
+ },
+
+ /*== org.openmobilealliance.pres-rules ==*/{
+ tauid_oma_pres_rules,
+ TXCAP_AUID_OMA_PRES_RULES_ID,
+ TXCAP_AUID_OMA_PRES_RULES_MIME_TYPE,
+ TXCAP_AUID_OMA_PRES_RULES_NS,
+ TXCAP_AUID_OMA_PRES_RULES_DOC,
+ tsk_false
+ },
+
+ /*== directory ==*/{
+ tauid_ietf_directory,
+ TXCAP_AUID_IETF_DIRECTORY_ID,
+ TXCAP_AUID_IETF_DIRECTORY_MIME_TYPE,
+ TXCAP_AUID_IETF_DIRECTORY_NS,
+ TXCAP_AUID_IETF_DIRECTORY_DOC,
+ tsk_false
+ },
+
+ /*== org.openmobilealliance.xcap-directory ==*/{
+ tauid_oma_directory,
+ TXCAP_AUID_OMA_DIRECTORY_ID,
+ TXCAP_AUID_OMA_DIRECTORY_MIME_TYPE,
+ TXCAP_AUID_OMA_DIRECTORY_NS,
+ TXCAP_AUID_OMA_DIRECTORY_DOC,
+ tsk_false
+ },
+
+ /*== org.openmobilealliance.pres-content ==*/{
+ tauid_oma_pres_content,
+ TXCAP_AUID_OMA_PRES_CONTENT_ID,
+ TXCAP_AUID_OMA_PRES_CONTENT_MIME_TYPE,
+ TXCAP_AUID_OMA_PRES_CONTENT_NS,
+ TXCAP_AUID_OMA_PRES_CONTENT_DOC,
+ tsk_false
+ },
+
+ /*== org.openmobilealliance.conv-history ==*/{
+ tauid_oma_conv_history,
+ TXCAP_AUID_OMA_CONV_HISTORY_ID,
+ TXCAP_AUID_OMA_CONV_HISTORY_MIME_TYPE,
+ TXCAP_AUID_OMA_CONV_HISTORY_NS,
+ TXCAP_AUID_OMA_CONV_HISTORY_DOC,
+ tsk_false
+ },
+
+ /*== org.openmobilealliance.deferred-list ==*/{
+ tauid_oma_deferred_list,
+ TXCAP_AUID_OMA_DEFERRED_LIST_ID,
+ TXCAP_AUID_OMA_DEFERRED_LIST_MIME_TYPE,
+ TXCAP_AUID_OMA_DEFERRED_LIST_NS,
+ TXCAP_AUID_OMA_DEFERRED_LIST_DOC,
+ tsk_false
+ },
+
+ /*== org.openmobilealliance.group-usage-list ==*/{
+ tauid_oma_shared_groups,
+ TXCAP_AUID_OMA_SHARED_GROUPS_ID,
+ TXCAP_AUID_OMA_SHARED_GROUPS_MIME_TYPE,
+ TXCAP_AUID_OMA_SHARED_GROUPS_NS,
+ TXCAP_AUID_OMA_SHARED_GROUPS_DOC,
+ tsk_false
+ },
+};
+
+txcap_auid_t* txcap_auid_create(txcap_auid_type_t type, const char* id, const char* mime_type, const char* ns, const char* document_name, tsk_bool_t is_global)
+{
+ return tsk_object_new(txcap_auid_def_t, type, id, mime_type, ns, document_name, is_global);
+}
+
+/** Predicate function used to find an option by id.
+*/
+static int pred_find_auid_by_id(const tsk_list_item_t *item, const void *id)
+{
+ if(item && item->data){
+ txcap_auid_t *auid = item->data;
+ return tsk_stricmp(auid->id, (const char*)id);
+ }
+ return -1;
+}
+
+
+
+/** Initialze the list of auids with default values from __txcap_auids
+* auids must be null;
+*/
+int txcap_auids_init(txcap_auids_L_t** auids)
+{
+ size_t i;
+ size_t count;
+ if(!auids){
+ TSK_DEBUG_ERROR("invalid parameter.");
+ return -1;
+ }
+ else if(*auids){
+ TSK_DEBUG_WARN("auids already initialized.");
+ }
+ else{
+ *auids = tsk_list_create();
+ }
+
+ count = sizeof(__txcap_auids)/sizeof(auid_t);
+ for(i = 0; i<count; i++){
+ txcap_auid_t* auid = txcap_auid_create(__txcap_auids[i].type,
+ __txcap_auids[i].id,
+ __txcap_auids[i].mime_type,
+ __txcap_auids[i].ns,
+ __txcap_auids[i].document_name,
+ __txcap_auids[i].global);
+ tsk_list_push_back_data(*auids, (void**)&auid);
+ }
+
+ return 0;
+}
+
+/**
+* Registers a new AUID. If the AUID already exist (case-insensitive comparison on the id),
+* then it will be updated with the new supplied values.
+* @param auids The destination list.
+* @param id The id of the new AUID to add (e.g. xcap-caps).
+* @param mime_type The MIME-Type of the new AUID to add (e.g. application/xcap-caps+xml).
+* @param ns The Namespace of the new AUID to add (e.g. urn:ietf:params:xml:ns:xcap-caps).
+* @param document_name The name of the new AUID to add (e.g. index).
+* @param is_global Indicates whether the AUID scope is global or not (user).
+* @retval Zero if succeed and non-zero error code otherwise.
+*/
+int txcap_auid_register(txcap_auids_L_t* auids, const char* id, const char* mime_type, const char* ns, const char* document_name, tsk_bool_t is_global)
+{
+ const tsk_list_item_t* item;
+ int ret = -1;
+
+ if(!auids || !id){
+ return -1;
+ }
+
+ if((item = tsk_list_find_item_by_pred(auids, pred_find_auid_by_id, id))){
+ tsk_strupdate(&((txcap_auid_t*)item->data)->mime_type, mime_type);
+ tsk_strupdate(&((txcap_auid_t*)item->data)->ns, ns);
+ tsk_strupdate(&((txcap_auid_t*)item->data)->document_name, document_name);
+ ((txcap_auid_t*)item->data)->global = is_global;
+ ret = 0;
+ }
+ else{
+ txcap_auid_t* auid;
+ if((auid = txcap_auid_create(tauid_dummy, id, mime_type, ns, document_name, is_global))){
+ tsk_list_push_back_data(auids, (void**)&auid);
+ ret = 0;
+ }else{
+ ret = -2;
+ }
+ }
+
+ return ret;
+}
+
+/**
+* Finds an AUID by id (case-insensitive).
+* @param auids List of AUIDs from which to find the AUID.
+* @param id The @a id of the AUID to find.
+* @retval An AUID with the matching id or null if does not exist.
+* It's up to you to free the returned object.
+*/
+txcap_auid_t* txcap_auid_get_by_id(txcap_auids_L_t* auids, const char* id)
+{
+ //const txcap_auid_t* ret = tsk_null;
+ const tsk_list_item_t* item;
+
+ if(!auids){
+ return tsk_null;
+ }
+
+ if((item = tsk_list_find_item_by_pred(auids, pred_find_auid_by_id, id))){
+ return tsk_object_ref((void*)item->data);
+ }
+ else{
+ return tsk_null;
+ }
+
+}
+
+//=================================================================================================
+// AUID object definition
+//
+static tsk_object_t* txcap_auid_ctor(tsk_object_t * self, va_list * app)
+{
+ txcap_auid_t *auid = self;
+ if(auid){
+ auid->type = va_arg(*app, txcap_auid_type_t);
+ auid->id = tsk_strdup( va_arg(*app, const char*) );
+ auid->mime_type = tsk_strdup( va_arg(*app, const char*) );
+ auid->ns = tsk_strdup( va_arg(*app, const char*) );
+ auid->document_name = tsk_strdup( va_arg(*app, const char*) );
+ auid->global = va_arg(*app, tsk_bool_t);
+ }
+ return self;
+}
+
+static tsk_object_t* txcap_auid_dtor(tsk_object_t * self)
+{
+ txcap_auid_t *auid = self;
+ if(auid){
+ TSK_FREE(auid->id);
+ TSK_FREE(auid->mime_type);
+ TSK_FREE(auid->ns);
+ TSK_FREE(auid->document_name);
+ }
+
+ return self;
+}
+
+static int txcap_auid_cmp(const tsk_object_t *_a1, const tsk_object_t *_a2)
+{
+ const txcap_auid_t *a1 = _a1;
+ const txcap_auid_t *a2 = _a2;
+
+ if(a1 && a2){
+ return tsk_stricmp(a1->id, a2->id);
+ }
+ else{
+ return -1;
+ }
+}
+
+static const tsk_object_def_t txcap_auid_def_s =
+{
+ sizeof(txcap_auid_t),
+ txcap_auid_ctor,
+ txcap_auid_dtor,
+ txcap_auid_cmp,
+};
+const tsk_object_def_t *txcap_auid_def_t = &txcap_auid_def_s;
+
diff --git a/tinyXCAP/src/txcap_document.c b/tinyXCAP/src/txcap_document.c new file mode 100644 index 0000000..b212e08 --- /dev/null +++ b/tinyXCAP/src/txcap_document.c @@ -0,0 +1,137 @@ +/*
+* Copyright (C) 2009-2010 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+/**@file txcap_document.c
+ * @brief XCAP documents.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tinyxcap/txcap_document.h"
+
+#include "tinyxcap/txcap_auid.h"
+
+/**@ingroup txcap_selector_group
+* Create a custom XCAP document selector URI as per <a href="http://tools.ietf.org/html/rfc4825#section-6.2">RFC 4825 subclause 6.2</a>.
+* @param stack The XCAP stack from which to load the user's preference (xcap-root, AUIDs, XUI, name of the document, ...).
+* Should be created using @ref txcap_stack_create().
+* @param auid_id The Application Unique ID. Unique identifier within the namespace of application unique IDs created by this specification (RFC 4825)
+* that differentiates XCAP resources accessed by one application from XCAP resources accessed by another.
+* For more information see <a href="http://tools.ietf.org/html/rfc4825#section-4">RFC 4825 subclause 4</a>.
+* @retval The HTTP/HTTPS URI containing the XCAP root and document selector, resulting in the selection of a specific document. As a
+* result, performing a GET against the document URI would retrieve the document.
+* If supplied parameters are not valid this method will return NULL.
+* You must free the returned string.
+*
+* @code
+* // resource-lists document
+* char* urlstring;
+* if((urlstring = txcap_selector_get_document(stack, "resource-lists"))){
+* TSK_FREE(urlstring);
+* }
+* @endcode
+*
+* @code
+* // xcap-caps document
+* char* urlstring;
+* if((urlstring = txcap_selector_get_document(stack, "xcap-caps"))){
+* TSK_FREE(urlstring);
+* }
+* @endcode
+*
+* @sa @ref txcap_selector_get_document_2<br>@ref txcap_selector_get_url
+*/
+char* txcap_selector_get_document(const txcap_stack_handle_t* stack, const char* auid_id)
+{
+ char* ret = tsk_null;
+ txcap_auid_t* auid;
+
+ const txcap_stack_t* xcap_stack = stack;
+ if(xcap_stack && xcap_stack->auids && auid_id){
+ if((auid = txcap_auid_get_by_id(xcap_stack->auids, auid_id))){
+ ret = txcap_selector_get_document_2(xcap_stack->xcap_root, auid->id, auid->global? tsk_null: xcap_stack->xui, auid->document_name);
+ TSK_OBJECT_SAFE_FREE(auid);
+ }
+ else{
+ TSK_DEBUG_ERROR("Fail to find AUID with id %s.", auid_id);
+ }
+ }
+ else{
+ TSK_DEBUG_ERROR("Invalid parameter.");
+ }
+ return ret;
+}
+
+/**@ingroup txcap_selector_group
+* Create a custom XCAP document selector URI as per <a href="http://tools.ietf.org/html/rfc4825#section-6.2">RFC 4825 subclause 6.2</a>.
+* @param xcap_root The XCAP Root URI (valid HTTP/HTTPS URL). A context that contains all the documents across all
+* application usages and users that are managed by the server. For more information see <a href="http://tools.ietf.org/html/rfc4825#section-4">RFC 4825 subclause 4</a>.
+* @param auid_id The Application Unique ID. Unique identifier within the namespace of application unique IDs created by this specification (RFC 4825)
+* that differentiates XCAP resources accessed by one application from XCAP resources accessed by another.
+* For more information see <a href="http://tools.ietf.org/html/rfc4825#section-4">RFC 4825 subclause 4</a>.
+* @param xui The XCAP User Identifier. The XUI is a string, valid as a path element in an HTTP URI, that is associated with each user served
+* by the XCAP server. For more information see <a href="http://tools.ietf.org/html/rfc4825#section-4">RFC 4825 subclause 4</a>.
+* For global document, this parameter should be NULL or equal to "global".
+* @param doc_name The name of the document (e.g. index).
+* @retval The HTTP/HTTPS URI containing the XCAP root and document selector, resulting in the selection of a specific document. As a
+ result, performing a GET against the document URI would retrieve the document.
+* If supplied parameters are not valid this method will return NULL.
+* You must free the returned string.
+*
+* @code
+* // resource-lists document
+* char* urlstring;
+* if((urlstring = txcap_selector_get_document("http://doubango.org:8080/services", "resource-lists", "sip:bob@doubango.org", "index"))){
+* TSK_FREE(urlstring);
+* }
+* @endcode
+*
+* @code
+* // xcap-caps document
+* char* urlstring;
+* if((urlstring = txcap_selector_get_document("http://doubango.org:8080/services", "xcap-caps", "global", "index"))){
+* TSK_FREE(urlstring);
+* }
+* @endcode
+*
+* @sa @ref txcap_selector_get_document<br>@ref txcap_selector_get_url
+*/
+char* txcap_selector_get_document_2(const char* xcap_root, const char* auid_id, const char* xui, const char* doc_name)
+{
+ char* ret = tsk_null;
+
+ if(!xcap_root || !auid_id || !doc_name){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+
+ if(!xui || tsk_striequals("global", xui)){
+ /* xdm-root/auid-name/global/doc-name */
+ tsk_sprintf(&ret, "%s/%s/global/%s", xcap_root, auid_id, doc_name);
+ }
+ else{
+ /* xdm-root/auid-name/users/xui/doc-name */
+ tsk_sprintf(&ret, "%s/%s/users/%s/%s", xcap_root, auid_id, xui, doc_name);
+ }
+
+ return ret;
+}
\ No newline at end of file diff --git a/tinyXCAP/src/txcap_node.c b/tinyXCAP/src/txcap_node.c new file mode 100644 index 0000000..60e1aa2 --- /dev/null +++ b/tinyXCAP/src/txcap_node.c @@ -0,0 +1,155 @@ +/*
+* Copyright (C) 2009-2010 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+/**@file txcap_node.c
+ * @brief XCAP nodes.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tinyxcap/txcap_node.h"
+
+#include "tsk_string.h"
+#include "tsk_buffer.h"
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+
+#include <string.h> /* strlen() */
+
+/**@ingroup txcap_selector_group
+* Gets the Node Url.
+* @param auid_id The id of the AUID (e.g 'resource-lists').
+* @param ... Node selection steps. You must use @a TXCAP_SELECTOR_NODE_SET*() macros to set these steps.
+* The list of parameters must end with @ref TXCAP_SELECTOR_NODE_SET_NULL() even if there is no step.<br>
+* @retval The Url of the node (e.g. 'resource-lists/list[2]').
+*
+* @code
+char* node = txcap_selector_get_node("resource-lists",
+ TXCAP_SELECTOR_NODE_SET_ATTRIBUTE("list", "name", "rcs"),
+ TXCAP_SELECTOR_NODE_SET_ATTRIBUTE("entry", "uri", "sip:bob@example.com"),
+ TXCAP_SELECTOR_NODE_SET_NULL());
+
+ TSK_FREE(node);
+* @endcode
+*
+* @sa @ref txcap_selector_get_node_2<br>@ref txcap_selector_get_document<br> @ref txcap_selector_get_document_2<br>@ref txcap_selector_get_url
+*/
+char* txcap_selector_get_node(const char* auid_id, ...)
+{
+ char* ret = tsk_null;
+ va_list ap;
+
+ va_start(ap, auid_id);
+ ret = txcap_selector_get_node_2(auid_id, &ap);
+ va_end(ap);
+
+ return ret;
+}
+
+/**@ingroup txcap_selector_group
+* Gets the Node Url.
+* @param auid_id The id of the AUID (e.g 'resource-lists').
+* @param app Node selection steps. You must use @a TXCAP_SELECTOR_NODE_SET*() macros to set these steps.
+* The list of parameters must end with @ref TXCAP_SELECTOR_NODE_SET_NULL() even if there is no step.<br>
+* @retval The Url of the node (e.g. 'resource-lists/list[2]').
+*
+* @code
+* @endcode
+*
+* @sa @ref txcap_selector_get_node<br>@ref txcap_selector_get_document<br> @ref txcap_selector_get_document_2<br>@ref txcap_selector_get_url
+*/
+char* txcap_selector_get_node_2(const char* auid_id, va_list* app)
+{
+ char* ret = tsk_null;
+ char* namespace = tsk_null;
+ tsk_buffer_t* buffer = tsk_buffer_create_null();
+ txcap_selector_param_type_t step;
+
+ while((step = va_arg(*app, txcap_selector_param_type_t)) != xcapp_node_null){
+ switch(step){
+ case xcapp_node_name:
+ { /* (const char*)QNAME_STR */
+ const char* QNAME_STR = va_arg(*app, const char*);
+ if(tsk_buffer_append_2(buffer, "/%s", QNAME_STR)){
+ goto bail;
+ }
+ break;
+ }
+ case xcapp_node_pos:
+ { /* (const char*)QNAME_STR, (unsigned int)POS_UINT */
+ const char* QNAME_STR = va_arg(*app, const char*);
+ unsigned int POS_UINT = va_arg(*app, unsigned int);
+ tsk_buffer_append_2(buffer, "/%s%%5B%u%%5D",
+ QNAME_STR, POS_UINT);
+ break;
+ }
+ case xcapp_node_attribute:
+ { /* (const char*)QNAME_STR, (const char*)ATT_QNAME_STR, (const char*)ATT_VALUE_STR */
+ const char* QNAME_STR = va_arg(*app, const char*);
+ const char* ATT_QNAME_STR = va_arg(*app, const char*);
+ const char* ATT_VALUE_STR = va_arg(*app, const char*);
+ tsk_buffer_append_2(buffer, "/%s%%5B@%s=%%22%s%%22%%5D",
+ QNAME_STR, ATT_QNAME_STR, ATT_VALUE_STR);
+ break;
+ }
+ case xcapp_node_pos_n_attribute:
+ { /* (const char*)QNAME_STR, (unsigned int)POS_UINT, (const char*)ATT_QNAME_STR, (const char*)ATT_VALUE_STR */
+ const char* QNAME_STR = va_arg(*app, const char*);
+ unsigned int POS_UINT = va_arg(*app, unsigned int);
+ const char* ATT_QNAME_STR = va_arg(*app, const char*);
+ const char* ATT_VALUE_STR = va_arg(*app, const char*);
+ tsk_buffer_append_2(buffer, "/%s%%5B%u%%5D%%5B@%s=%%22%s%%22%%5D",
+ QNAME_STR, POS_UINT, ATT_QNAME_STR, ATT_VALUE_STR);
+ break;
+ }
+ case xcapp_node_namespace:
+ { /* (const char*)PREFIX_STR, (const char*)VALUE_STR */
+ const char* PREFIX_STR = va_arg(*app, const char*);
+ const char* VALUE_STR = va_arg(*app, const char*);
+ char* temp = tsk_null;
+ tsk_sprintf(&temp, "%sxmlns(%s=%%22%s%%22)",
+ namespace?"":"%3F",PREFIX_STR, VALUE_STR);
+ tsk_strcat(&namespace, temp);
+ TSK_FREE(temp);
+ break;
+ }
+ default:
+ {
+ TSK_DEBUG_ERROR("NOT SUPPORTED.");
+ goto bail;
+ }
+ } /* switch */
+ } /* while */
+
+ /* append the namespace */
+ if(namespace){
+ tsk_buffer_append(buffer, namespace, strlen(namespace));
+ TSK_FREE(namespace);
+ }
+
+bail:
+ if(TSK_BUFFER_DATA(buffer) && TSK_BUFFER_SIZE(buffer)){
+ ret = tsk_strndup(TSK_BUFFER_DATA(buffer), TSK_BUFFER_SIZE(buffer));
+ }
+ TSK_OBJECT_SAFE_FREE(buffer);
+ return ret;
+}
diff --git a/tinyXCAP/src/txcap_selector.c b/tinyXCAP/src/txcap_selector.c new file mode 100644 index 0000000..9d336d7 --- /dev/null +++ b/tinyXCAP/src/txcap_selector.c @@ -0,0 +1,167 @@ +/*
+* Copyright (C) 2009-2010 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+/**@file txcap_selector.c
+ * @brief XCAP selector.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tinyxcap/txcap_selector.h"
+
+#include "tinyxcap/txcap_document.h"
+#include "tinyxcap/txcap_node.h"
+
+/**@defgroup txcap_selector_group XCAP URL selector
+*/
+
+/** Internal function
+ */
+char* __txcap_selector_get_url(const txcap_stack_handle_t* stack, const char* auid_id, va_list* app)
+{
+ char* ret = tsk_null;
+ char* node = tsk_null;
+ if(!stack && !auid_id){
+ goto bail;
+ }
+
+ /* ==document== */
+ if(!(ret = txcap_selector_get_document(stack, auid_id))){
+ TSK_DEBUG_ERROR("Failed to compute XCAP document URL.");
+ goto bail;
+ }
+
+ /* ==node== */
+ if((node = txcap_selector_get_node_2(auid_id, app))){
+ /* append node root */
+ char* temp = tsk_null;
+ tsk_sprintf(&temp, "/~~/%s", auid_id);
+ tsk_strcat(&ret, temp);
+ /* append node */
+ tsk_strcat(&ret, node);
+ /* free */
+ TSK_FREE(temp);
+ TSK_FREE(node);
+ }
+
+bail:
+ return ret;
+}
+
+/** Internal function
+ */
+char* __txcap_selector_get_url_2(const char* xcap_root, const char* auid_id, const char* xui, const char* doc_name, va_list* app)
+{
+ char* ret = tsk_null;
+ char* node = tsk_null;
+ if(!xcap_root && !auid_id){
+ goto bail;
+ }
+
+ /* ==document== */
+ if(!(ret = txcap_selector_get_document_2(xcap_root, auid_id, xui, doc_name))){
+ TSK_DEBUG_ERROR("Failed to compute XCAP document URL.");
+ goto bail;
+ }
+
+ /* ==node== */
+ if((node = txcap_selector_get_node_2(auid_id, app))){
+ /* append node root */
+ char* temp = tsk_null;
+ tsk_sprintf(&temp, "/~~/%s", auid_id);
+ tsk_strcat(&ret, temp);
+ /* append node */
+ tsk_strcat(&ret, node);
+ /* free */
+ TSK_FREE(temp);
+ TSK_FREE(node);
+ }
+
+bail:
+ return ret;
+}
+
+/**@ingroup txcap_selector_group
+* Gets the full XCAP URL with both the document and node selector parts.
+* @param stack The XCAP stack from which to load the user's preference (xcap-root, AUIDs, XUI, name of the document, ...).
+* Should be created using @ref txcap_stack_create().
+* @param auid_id The Application Unique ID. Unique identifier within the namespace of application unique IDs created by this specification (RFC 4825)
+* that differentiates XCAP resources accessed by one application from XCAP resources accessed by another.
+* For more information see <a href="http://tools.ietf.org/html/rfc4825#section-4">RFC 4825 subclause 4</a>.
+* @param ... Any @a TXCAP_SELECTOR_NODE_SET*() macros. MUST ends with @ref TXCAP_SELECTOR_NODE_SET_NULL().
+* @retval A well-formed (already escaped) HTTP/HTTPS URL which can be used as Request-Uri (e.g. GET, PUT or DELETE). As a
+* result, performing a GET against the return URL would retrieve a document, element or attribute.
+*
+* @code
+// Retrieve the entry with: uri='sip:bob@example.com' and list='rcs'
+// Expected node: /resource-lists/list[@name="rcs"]/entry[@uri="sip:bob@example.com"]
+char* urlstring = txcap_selector_get_url(stack, "resource-lists",
+ TXCAP_SELECTOR_NODE_SET_ATTRIBUTE("list", "name", "rcs"),
+ TXCAP_SELECTOR_NODE_SET_ATTRIBUTE("entry", "uri", "sip:bob@example.com"),
+ TXCAP_SELECTOR_NODE_SET_NULL());
+TSK_DEBUG_INFO("%s\n", urlstring);
+TSK_FREE(urlstring);
+* @endcode
+*
+* @sa @ref txcap_selector_get_node<br>@ref txcap_selector_get_document<br> @ref txcap_selector_get_document_2
+*/
+char* txcap_selector_get_url(const txcap_stack_handle_t* stack, const char* auid_id, ...)
+{
+ char* ret;
+ va_list ap;
+
+ va_start(ap, auid_id);
+ ret = __txcap_selector_get_url(stack, auid_id, &ap);
+ va_end(ap);
+
+ return ret;
+}
+
+/**@ingroup txcap_selector_group
+* Gets the full XCAP URL with both the document and node selector parts.
+* @param xcap_root The XCAP Root URI (valid HTTP/HTTPS URL). A context that contains all the documents across all
+* application usages and users that are managed by the server. For more information see <a href="http://tools.ietf.org/html/rfc4825#section-4">RFC 4825 subclause 4</a>.
+* @param auid_id The Application Unique ID. Unique identifier within the namespace of application unique IDs created by this specification (RFC 4825)
+* that differentiates XCAP resources accessed by one application from XCAP resources accessed by another.
+* For more information see <a href="http://tools.ietf.org/html/rfc4825#section-4">RFC 4825 subclause 4</a>.
+* @param xui The XCAP User Identifier. The XUI is a string, valid as a path element in an HTTP URI, that is associated with each user served
+* by the XCAP server. For more information see <a href="http://tools.ietf.org/html/rfc4825#section-4">RFC 4825 subclause 4</a>.
+* For global document, this parameter should be NULL or equal to "global".
+* @param doc_name The name of the document (e.g. index).
+* @retval A well-formed HTTP/HTTPS URL which can be used as Request-Uri (e.g. GET, PUT or DELETE). As a
+* result, performing a GET against the return URL would retrieve a document, element or attribute.
+* @code
+* @endcode
+*
+* @sa @ref txcap_selector_get_url<br>@ref txcap_selector_get_node<br>@ref txcap_selector_get_document<br> @ref txcap_selector_get_document_2
+*/
+char* txcap_selector_get_url_2(const char* xcap_root, const char* auid_id, const char* xui, const char* doc_name, ...)
+{
+ char* ret;
+ va_list ap;
+
+ va_start(ap, doc_name);
+ ret = __txcap_selector_get_url_2(xcap_root, auid_id, xui, doc_name, &ap);
+ va_end(ap);
+
+ return ret;
+}
|