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