modules/ims_qos: added patch for flow-description bug when request originates from...
[sip-router] / lib / xcap / xcap_client.c
1 /* 
2  * Copyright (C) 2005 iptelorg GmbH
3  *
4  * This file is part of ser, a free SIP server.
5  *
6  * ser 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  * For a license to use the ser software under conditions
12  * other than those described here, or to purchase support for this
13  * software, please contact iptel.org by e-mail at the following addresses:
14  *    info@iptel.org
15  *
16  * ser is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
24  */
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include <xcap/xcap_client.h>
31 #include <cds/dstring.h>
32 #include <cds/memory.h>
33 #include <cds/logger.h>
34 #include <cds/serialize.h>
35
36 static const str_t *get_xcap_doc_dir(xcap_document_type_t doc_type)
37 {
38         static str_t pres_rules = STR_STATIC_INIT("pres-rules");
39         static str_t im_rules = STR_STATIC_INIT("im-rules");
40         static str_t rls_services = STR_STATIC_INIT("rls-services");
41         static str_t resource_lists = STR_STATIC_INIT("resource-lists");
42
43         switch (doc_type) {
44                 case xcap_doc_pres_rules: return &pres_rules;
45                 case xcap_doc_im_rules: return &im_rules;
46                 case xcap_doc_rls_services: return &rls_services;
47                 case xcap_doc_resource_lists: return &resource_lists;
48                 /* when new doc_type added, there will be a warning -> add it there */
49         }
50         WARN_LOG("unknown XCAP document type\n");
51         return NULL;
52 }
53
54 static const str_t *get_default_user_doc(xcap_document_type_t doc_type)
55 {
56         static str_t pres_rules = STR_STATIC_INIT("presence-rules.xml");
57         static str_t im_rules = STR_STATIC_INIT("im-rules.xml");
58         static str_t rls_services = STR_STATIC_INIT("rls-services.xml");
59         static str_t resource_lists = STR_STATIC_INIT("resource-list.xml");
60
61         switch (doc_type) {
62                 case xcap_doc_pres_rules: return &pres_rules;
63                 case xcap_doc_im_rules: return &im_rules;
64                 case xcap_doc_rls_services: return &rls_services;
65                 case xcap_doc_resource_lists: return &resource_lists;
66                 /* when new doc_type added, there will be a warning -> add it there */
67         }
68         WARN_LOG("unknown XCAP document type\n");
69         return NULL;
70 }
71
72 static int ends_with_separator(str_t *s)
73 {
74         if (!is_str_empty(s))
75                 if (s->s[s->len - 1] == '/') return 1;
76         return 0;
77 }
78
79 char *xcap_uri_for_users_document(xcap_document_type_t doc_type,
80                 const str_t *username, 
81                 const str_t*filename,
82                 xcap_query_params_t *params)
83 {
84         dstring_t s;
85         /* int res = RES_OK; */
86         int l = 0;
87         char *dst = NULL;
88
89         dstr_init(&s, 128);
90         if (params) {
91                 dstr_append_str(&s, &params->xcap_root);
92                 if (!ends_with_separator(&params->xcap_root))
93                         dstr_append(&s, "/", 1);
94         }
95         else dstr_append(&s, "/", 1);
96         dstr_append_str(&s, get_xcap_doc_dir(doc_type));
97         dstr_append_zt(&s, "/users/");
98         dstr_append_str(&s, username);
99         dstr_append(&s, "/", 1);
100         if (filename) dstr_append_str(&s, filename);
101         else {
102                 /* default filename if NULL */
103                 dstr_append_str(&s, get_default_user_doc(doc_type));
104         }
105         /* res = dstr_get_str(&s, dst); */
106         
107         l = dstr_get_data_length(&s);
108         if (l > 0) {
109                 dst = (char *)cds_malloc(l + 1);
110                 if (dst) {
111                         dstr_get_data(&s, dst);
112                         dst[l] = 0;
113                 }
114                 else ERROR_LOG("can't allocate memory (%d bytes)\n", l);
115         }
116         
117         dstr_destroy(&s);
118         return dst;
119 }
120
121
122 char *xcap_uri_for_global_document(xcap_document_type_t doc_type,
123                 const str_t *filename, 
124                 xcap_query_params_t *params)
125 {
126         dstring_t s;
127         /* int res = RES_OK; */
128         char *dst = NULL;
129         int l = 0;
130
131         dstr_init(&s, 128);
132         if (params) {
133                 dstr_append_str(&s, &params->xcap_root);
134                 if (!ends_with_separator(&params->xcap_root))
135                         dstr_append(&s, "/", 1);
136         }
137         else dstr_append(&s, "/", 1);
138         dstr_append_str(&s, get_xcap_doc_dir(doc_type));
139         if (filename) {
140                 dstr_append_zt(&s, "/global/");
141                 dstr_append_str(&s, filename);
142         }
143         else {
144                 /* default filename if NULL */
145                 dstr_append_zt(&s, "/global/index");
146         }
147         /* res = dstr_get_str(&s, dst); */
148         
149         l = dstr_get_data_length(&s);
150         if (l > 0) {
151                 dst = (char *)cds_malloc(l + 1);
152                 if (dst) {
153                         dstr_get_data(&s, dst);
154                         dst[l] = 0;
155                 }
156         }
157         
158         dstr_destroy(&s);
159         return dst;
160 }
161
162 #ifdef SER
163
164 #include "sr_module.h"
165
166 int xcap_query(const char *uri, 
167                 xcap_query_params_t *params, char **buf, int *bsize)
168 {
169         static xcap_query_func query = NULL;
170         static int initialized = 0;
171
172         if (!initialized) {
173                 query = (xcap_query_func)find_export("xcap_query", 0, -1);
174                 initialized = 1;
175                 if (!query) WARN_LOG("No XCAP query support! (Missing module?)\n");
176         }
177         if (!query) {
178                 /* no function for doing XCAP queries */
179                 return -1;
180         }
181         
182         /* all XCAP queries are done through XCAP module */
183         return query(uri, params, buf, bsize);
184 }
185
186 #else /* compiled WITHOUT SER */
187
188 #include <curl/curl.h>
189
190 static size_t write_data_func(void *ptr, size_t size, size_t nmemb, void *stream)
191 {
192         int s = size * nmemb;
193 /*      TRACE_LOG("%d bytes writen\n", s);*/
194         if (s != 0) {
195                 if (dstr_append((dstring_t*)stream, ptr, s) != 0) {
196                         ERROR_LOG("can't append %d bytes into data buffer\n", s);
197                         return 0;
198                 }
199         }
200         return s;
201 }
202
203
204 int xcap_query(const char *uri, xcap_query_params_t *params, char **buf, int *bsize)
205 {
206         CURLcode res = -1;
207         static CURL *handle = NULL;
208         dstring_t data;
209         char *auth = NULL;
210         int i;
211         long auth_methods;
212         
213         if (!uri) {
214                 ERROR_LOG("BUG: no uri given\n");
215                 return -1;
216         }
217         if (!buf) {
218                 ERROR_LOG("BUG: no buf given\n");
219                 return -1;
220         }
221
222         i = 0;
223         if (params) {
224                 if (params->auth_user.s) i += params->auth_user.len;
225                 if (params->auth_pass.s) i += params->auth_pass.len;
226         }
227         if (i > 0) {
228                 /* do authentication */
229                 auth = (char *)cds_malloc(i + 2);
230                 if (!auth) return -1;
231                 sprintf(auth, "%s:%s", params->auth_user.s ? params->auth_user.s: "",
232                                 params->auth_pass.s ? params->auth_pass.s: "");
233         }
234
235         auth_methods = CURLAUTH_BASIC | CURLAUTH_DIGEST;
236         
237         dstr_init(&data, 512);
238         
239         if (!handle) handle = curl_easy_init(); 
240         if (handle) {
241                 curl_easy_setopt(handle, CURLOPT_URL, uri);
242                 /* TRACE_LOG("uri: %s\n", uri ? uri : "<null>"); */
243                 
244                 /* do not store data into a file - store them in memory */
245                 curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_data_func);
246                 curl_easy_setopt(handle, CURLOPT_WRITEDATA, &data);
247
248 #ifdef CURLOPT_MUTE
249                 /* be quiet */
250                 curl_easy_setopt(handle, CURLOPT_MUTE, 1);
251 #endif /* CURLOPT_MUTE */
252                 
253                 /* non-2xx => error */
254                 curl_easy_setopt(handle, CURLOPT_FAILONERROR, 1);
255
256                 /* auth */
257                 curl_easy_setopt(handle, CURLOPT_HTTPAUTH, auth_methods); /* TODO possibility of selection */
258                 curl_easy_setopt(handle, CURLOPT_NETRC, CURL_NETRC_IGNORED);
259                 curl_easy_setopt(handle, CURLOPT_USERPWD, auth);
260
261                 /* SSL */
262                 if (params) {
263                         if (params->enable_unverified_ssl_peer) {
264                                 curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0);
265                                 curl_easy_setopt(handle, CURLOPT_SSL_VERIFYHOST, 0);
266                         }
267                 }
268                 
269                 /* follow redirects (needed for apache mod_speling - case insesitive names) */
270                 curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1);
271                 
272         /*      curl_easy_setopt(handle, CURLOPT_TCP_NODELAY, 1);
273                 curl_easy_setopt(handle, CURLOPT_CONNECTTIMEOUT, 10);*/
274                 
275                 /* Accept headers */
276                 
277                 res = curl_easy_perform(handle);
278                 /* curl_easy_cleanup(handle); */ /* FIXME: experimental */
279         }
280         else ERROR_LOG("can't initialize curl handle\n");
281         if (res == 0) {
282                 *bsize = dstr_get_data_length(&data);
283                 if (*bsize) {
284                         *buf = (char*)cds_malloc(*bsize);
285                         if (!*buf) {
286                                 ERROR_LOG("can't allocate %d bytes\n", *bsize);
287                                 res = -1;
288                                 *bsize = 0;
289                         }
290                         else dstr_get_data(&data, *buf);
291                 }
292         }
293         else DEBUG_LOG("curl error: %d\n", res);
294         dstr_destroy(&data);
295         if (auth) cds_free(auth);
296         return res;
297 }
298
299 #endif
300
301 void free_xcap_params_content(xcap_query_params_t *params)
302 {
303         if (params) {
304                 str_free_content(&params->xcap_root);
305                 str_free_content(&params->auth_user);
306                 str_free_content(&params->auth_pass);
307                 memset(params, 0, sizeof(*params));
308         }
309 }
310
311 int dup_xcap_params(xcap_query_params_t *dst, xcap_query_params_t *src)
312 {
313         int res = -10;
314         
315         if (dst) memset(dst, 0, sizeof(*dst));
316         
317         if (src && dst) {
318                 res = 0;
319                 
320                 res = str_dup(&dst->xcap_root, &src->xcap_root);
321                 if (res == 0) res = str_dup(&dst->auth_user, &src->auth_user);
322                 if (res == 0) res = str_dup(&dst->auth_pass, &src->auth_pass);
323                 
324                 if (res != 0) free_xcap_params_content(dst);
325         }
326         
327         return res;
328 }
329
330 int get_inline_xcap_buf_len(xcap_query_params_t *params)
331 {
332         int len;
333         
334         /* counts the length for data buffer storing values of
335          * xcap parameter members */
336         if (!params) {
337                 ERROR_LOG("BUG: empty params given\n");
338                 return 0;
339         }
340
341         len = params->xcap_root.len;
342         len += params->auth_user.len;
343         len += params->auth_pass.len;
344
345         return len;
346 }
347
348 int dup_xcap_params_inline(xcap_query_params_t *dst, xcap_query_params_t *src, char *data_buffer)
349 {
350         int res = -10;
351         
352         /* copies structure into existing buffer */
353         if (dst) {
354                 memset(dst, 0, sizeof(*dst));
355                 res = 0;
356         }
357         
358         if (src && dst) {
359                 dst->xcap_root.s = data_buffer;
360                 str_cpy(&dst->xcap_root, &src->xcap_root);
361
362                 dst->auth_user.s = after_str_ptr(&dst->xcap_root);
363                 str_cpy(&dst->auth_user, &src->auth_user);
364                 dst->auth_pass.s = after_str_ptr(&dst->auth_user);
365                 str_cpy(&dst->auth_pass, &src->auth_pass);
366         }
367         return res;
368 }
369
370 int serialize_xcap_params(sstream_t *ss, xcap_query_params_t *xp)
371 {
372         int res = 0;
373         
374         if (is_input_sstream(ss)) {
375                 memset(xp, 0, sizeof(*xp));
376         }
377         res = serialize_str(ss, &xp->xcap_root) | res;
378         res = serialize_str(ss, &xp->auth_user) | res;
379         res = serialize_str(ss, &xp->auth_pass) | res;
380
381         return res;
382 }
383
384 int str2xcap_params(xcap_query_params_t *dst, const str_t *src)
385 {
386         int res = 0;
387         sstream_t store;
388
389         if (!src) return -1;
390         
391         init_input_sstream(&store, src->s, src->len);
392         if (serialize_xcap_params(&store, dst) != 0) {
393                 ERROR_LOG("can't de-serialize xcap_params\n");
394                 res = -1;
395         }       
396         destroy_sstream(&store);
397         
398         return res;
399 }
400
401 int xcap_params2str(str_t *dst, xcap_query_params_t *src)
402 {
403         int res = 0;
404         sstream_t store;
405         
406         init_output_sstream(&store, 256);
407         
408         if (serialize_xcap_params(&store, src) != 0) {
409                 ERROR_LOG("can't serialize dialog\n");
410                 res = -1;
411         }
412         else {
413                 if (get_serialized_sstream(&store, dst) != 0) {
414                         ERROR_LOG("can't get serialized data\n");
415                         res = -1;
416                 }
417         }
418
419         destroy_sstream(&store);
420         return res;
421 }
422