blob: f02b1372ac8c6c0b467a6c05996559b67e1a3a1e [file] [log] [blame]
Alexandre Lision67916dd2014-01-24 13:33:04 -05001/* $Id$ */
2/*
3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#include <pjsip-simple/rpid.h>
21#include <pjsip-simple/errno.h>
22#include <pj/assert.h>
23#include <pj/guid.h>
24#include <pj/pool.h>
25#include <pj/string.h>
26
27
28static const pj_str_t DM_NAME = {"xmlns:dm", 8};
29static const pj_str_t DM_VAL = {"urn:ietf:params:xml:ns:pidf:data-model", 38};
30static const pj_str_t RPID_NAME = {"xmlns:rpid", 10};
31static const pj_str_t RPID_VAL = {"urn:ietf:params:xml:ns:pidf:rpid", 32};
32
33static const pj_str_t DM_NOTE = {"dm:note", 7};
34static const pj_str_t DM_PERSON = {"dm:person", 9};
35static const pj_str_t ID = {"id", 2};
36static const pj_str_t NOTE = {"note", 4};
37static const pj_str_t RPID_ACTIVITIES = {"rpid:activities", 15};
38static const pj_str_t RPID_AWAY = {"rpid:away", 9};
39static const pj_str_t RPID_BUSY = {"rpid:busy", 9};
40static const pj_str_t RPID_UNKNOWN = {"rpid:unknown", 12};
41
42
43/* Duplicate RPID element */
44PJ_DEF(void) pjrpid_element_dup(pj_pool_t *pool, pjrpid_element *dst,
45 const pjrpid_element *src)
46{
47 pj_memcpy(dst, src, sizeof(pjrpid_element));
48 pj_strdup(pool, &dst->id, &src->id);
49 pj_strdup(pool, &dst->note, &src->note);
50}
51
52
53/* Update RPID namespaces. */
54static void update_namespaces(pjpidf_pres *pres,
55 pj_pool_t *pool)
56{
57 /* Check if namespace is already present. */
58 if (pj_xml_find_attr(pres, &DM_NAME, NULL) != NULL)
59 return;
60
61 pj_xml_add_attr(pres, pj_xml_attr_new(pool, &DM_NAME, &DM_VAL));
62 pj_xml_add_attr(pres, pj_xml_attr_new(pool, &RPID_NAME, &RPID_VAL));
63}
64
65
66/* Comparison function to find node name substring */
67static pj_bool_t substring_match(const pj_xml_node *node,
68 const char *part_name,
69 pj_ssize_t part_len)
70{
71 pj_str_t end_name;
72
73 if (part_len < 1)
74 part_len = pj_ansi_strlen(part_name);
75
76 if (node->name.slen < part_len)
77 return PJ_FALSE;
78
79 end_name.ptr = node->name.ptr + (node->name.slen - part_len);
80 end_name.slen = part_len;
81
82 return pj_strnicmp2(&end_name, part_name, part_len)==0;
83}
84
85/* Util to find child node with the specified substring */
86static pj_xml_node *find_node(const pj_xml_node *parent,
87 const char *part_name)
88{
89 const pj_xml_node *node = parent->node_head.next,
90 *head = (pj_xml_node*) &parent->node_head;
91 pj_ssize_t part_len = pj_ansi_strlen(part_name);
92
93 while (node != head) {
94 if (substring_match(node, part_name, part_len))
95 return (pj_xml_node*) node;
96
97 node = node->next;
98 }
99
100 return NULL;
101}
102
103/*
104 * Add RPID element into existing PIDF document.
105 */
106PJ_DEF(pj_status_t) pjrpid_add_element(pjpidf_pres *pres,
107 pj_pool_t *pool,
108 unsigned options,
109 const pjrpid_element *elem)
110{
111 pj_xml_node *nd_person, *nd_activities, *nd_activity, *nd_note;
112 pj_xml_attr *attr;
113
114 PJ_ASSERT_RETURN(pres && pool && options==0 && elem, PJ_EINVAL);
115
116 PJ_UNUSED_ARG(options);
117
118 /* Check if we need to add RPID information into the PIDF document. */
119 if (elem->id.slen==0 &&
120 elem->activity==PJRPID_ACTIVITY_UNKNOWN &&
121 elem->note.slen==0)
122 {
123 /* No RPID information to be added. */
124 return PJ_SUCCESS;
125 }
126
127 /* Add <note> to <tuple> */
128 if (elem->note.slen != 0) {
129 pj_xml_node *nd_tuple;
130
131 nd_tuple = find_node(pres, "tuple");
132
133 if (nd_tuple) {
134 nd_note = pj_xml_node_new(pool, &NOTE);
135 pj_strdup(pool, &nd_note->content, &elem->note);
136 pj_xml_add_node(nd_tuple, nd_note);
137 nd_note = NULL;
138 }
139 }
140
141 /* Update namespace */
142 update_namespaces(pres, pool);
143
144 /* Add <person> */
145 nd_person = pj_xml_node_new(pool, &DM_PERSON);
146 if (elem->id.slen != 0) {
147 attr = pj_xml_attr_new(pool, &ID, &elem->id);
148 } else {
149 pj_str_t person_id;
150 /* xs:ID must start with letter */
151 //pj_create_unique_string(pool, &person_id);
152 person_id.ptr = (char*)pj_pool_alloc(pool, PJ_GUID_STRING_LENGTH+2);
153 person_id.ptr += 2;
154 pj_generate_unique_string(&person_id);
155 person_id.ptr -= 2;
156 person_id.ptr[0] = 'p';
157 person_id.ptr[1] = 'j';
158 person_id.slen += 2;
159
160 attr = pj_xml_attr_new(pool, &ID, &person_id);
161 }
162 pj_xml_add_attr(nd_person, attr);
163 pj_xml_add_node(pres, nd_person);
164
165 /* Add <activities> */
166 nd_activities = pj_xml_node_new(pool, &RPID_ACTIVITIES);
167 pj_xml_add_node(nd_person, nd_activities);
168
169 /* Add the activity */
170 switch (elem->activity) {
171 case PJRPID_ACTIVITY_AWAY:
172 nd_activity = pj_xml_node_new(pool, &RPID_AWAY);
173 break;
174 case PJRPID_ACTIVITY_BUSY:
175 nd_activity = pj_xml_node_new(pool, &RPID_BUSY);
176 break;
177 case PJRPID_ACTIVITY_UNKNOWN:
178 default:
179 nd_activity = pj_xml_node_new(pool, &RPID_UNKNOWN);
180 break;
181 }
182 pj_xml_add_node(nd_activities, nd_activity);
183
184 /* Add custom text if required. */
185 if (elem->note.slen != 0) {
186 nd_note = pj_xml_node_new(pool, &DM_NOTE);
187 pj_strdup(pool, &nd_note->content, &elem->note);
188 pj_xml_add_node(nd_person, nd_note);
189 }
190
191 /* Done */
192 return PJ_SUCCESS;
193}
194
195
196/* Get <note> element from PIDF <tuple> element */
197static pj_status_t get_tuple_note(const pjpidf_pres *pres,
198 pj_pool_t *pool,
199 pjrpid_element *elem)
200{
201 const pj_xml_node *nd_tuple, *nd_note;
202
203 nd_tuple = find_node(pres, "tuple");
204 if (!nd_tuple)
205 return PJSIP_SIMPLE_EBADRPID;
206
207 nd_note = find_node(pres, "note");
208 if (nd_note) {
209 pj_strdup(pool, &elem->note, &nd_note->content);
210 return PJ_SUCCESS;
211 }
212
213 return PJSIP_SIMPLE_EBADRPID;
214}
215
216/*
217 * Get RPID element from PIDF document, if any.
218 */
219PJ_DEF(pj_status_t) pjrpid_get_element(const pjpidf_pres *pres,
220 pj_pool_t *pool,
221 pjrpid_element *elem)
222{
223 const pj_xml_node *nd_person, *nd_activities, *nd_note = NULL;
224 const pj_xml_attr *attr;
225
226 /* Reset */
227 pj_bzero(elem, sizeof(*elem));
228 elem->activity = PJRPID_ACTIVITY_UNKNOWN;
229
230 /* Find <person> */
231 nd_person = find_node(pres, "person");
232 if (!nd_person) {
233 /* <person> not found, try to get <note> from <tuple> */
234 return get_tuple_note(pres, pool, elem);
235 }
236
237 /* Get element id attribute */
238 attr = pj_xml_find_attr((pj_xml_node*)nd_person, &ID, NULL);
239 if (attr)
240 pj_strdup(pool, &elem->id, &attr->value);
241
242 /* Get <activities> */
243 nd_activities = find_node(nd_person, "activities");
244 if (nd_activities) {
245 const pj_xml_node *nd_activity;
246
247 /* Try to get <note> from <activities> */
248 nd_note = find_node(nd_activities, "note");
249
250 /* Get the activity */
251 nd_activity = nd_activities->node_head.next;
252 if (nd_activity == nd_note)
253 nd_activity = nd_activity->next;
254
255 if (nd_activity != (pj_xml_node*) &nd_activities->node_head) {
256 if (substring_match(nd_activity, "busy", -1))
257 elem->activity = PJRPID_ACTIVITY_BUSY;
258 else if (substring_match(nd_activity, "away", -1))
259 elem->activity = PJRPID_ACTIVITY_AWAY;
260 else
261 elem->activity = PJRPID_ACTIVITY_UNKNOWN;
262
263 }
264 }
265
266 /* If <note> is not found, get <note> from <person> */
267 if (nd_note == NULL)
268 nd_note = find_node(nd_person, "note");
269
270 if (nd_note) {
271 pj_strdup(pool, &elem->note, &nd_note->content);
272 } else {
273 get_tuple_note(pres, pool, elem);
274 }
275
276 return PJ_SUCCESS;
277}
278
279