~ubuntu-branches/ubuntu/trusty/sflphone/trusty

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.1.0/pjsip/src/pjsip/sip_tel_uri.c

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (4.3.4 sid)
  • Revision ID: package-import@ubuntu.com-20140128182336-jrsv0k9u6cawc068
Tags: 1.3.0-1
* New upstream release 
  - Fixes "New Upstream Release" (Closes: #735846)
  - Fixes "Ringtone does not stop" (Closes: #727164)
  - Fixes "[sflphone-kde] crash on startup" (Closes: #718178)
  - Fixes "sflphone GUI crashes when call is hung up" (Closes: #736583)
* Build-Depends: ensure GnuTLS 2.6
  - libucommon-dev (>= 6.0.7-1.1), libccrtp-dev (>= 2.0.6-3)
  - Fixes "FTBFS Build-Depends libgnutls{26,28}-dev" (Closes: #722040)
* Fix "boost 1.49 is going away" unversioned Build-Depends: (Closes: #736746)
* Add Build-Depends: libsndfile-dev, nepomuk-core-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: sip_tel_uri.c 4322 2013-01-17 10:09:09Z bennylp $ */
 
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/sip_tel_uri.h>
 
21
#include <pjsip/sip_msg.h>
 
22
#include <pjsip/sip_parser.h>
 
23
#include <pjsip/print_util.h>
 
24
#include <pj/pool.h>
 
25
#include <pj/assert.h>
 
26
#include <pj/string.h>
 
27
#include <pj/ctype.h>
 
28
#include <pj/except.h>
 
29
#include <pjlib-util/string.h>
 
30
#include <pjlib-util/scanner.h>
 
31
 
 
32
#define ALPHA
 
33
#define DIGITS              "0123456789"
 
34
#define HEX                 "aAbBcCdDeEfF"
 
35
#define HEX_DIGITS          DIGITS HEX
 
36
#define VISUAL_SEP          "-.()"
 
37
#define PHONE_DIGITS        DIGITS VISUAL_SEP
 
38
#define GLOBAL_DIGITS       "+" PHONE_DIGITS
 
39
#define LOCAL_DIGITS        HEX_DIGITS "*#" VISUAL_SEP
 
40
#define NUMBER_SPEC         LOCAL_DIGITS GLOBAL_DIGITS
 
41
#define PHONE_CONTEXT       ALPHA GLOBAL_DIGITS
 
42
//#define RESERVED          ";/?:@&=+$,"
 
43
#define RESERVED            "/:@&$,+"
 
44
#define MARK                "-_.!~*'()"
 
45
#define UNRESERVED          ALPHA DIGITS MARK
 
46
#define ESCAPED             "%"
 
47
#define URIC                RESERVED UNRESERVED ESCAPED "[]+"
 
48
#define PARAM_UNRESERVED    "[]/:&+$"
 
49
#define PARAM_CHAR          PARAM_UNRESERVED UNRESERVED ESCAPED
 
50
 
 
51
static pj_cis_buf_t cis_buf;
 
52
static pj_cis_t pjsip_TEL_NUMBER_SPEC;
 
53
static pj_cis_t pjsip_TEL_EXT_VALUE_SPEC;
 
54
static pj_cis_t pjsip_TEL_PHONE_CONTEXT_SPEC;
 
55
static pj_cis_t pjsip_TEL_URIC_SPEC;
 
56
static pj_cis_t pjsip_TEL_VISUAL_SEP_SPEC;
 
57
static pj_cis_t pjsip_TEL_PNAME_SPEC;
 
58
static pj_cis_t pjsip_TEL_PVALUE_SPEC;
 
59
static pj_cis_t pjsip_TEL_PVALUE_SPEC_ESC;
 
60
static pj_cis_t pjsip_TEL_PARSING_PVALUE_SPEC;
 
61
static pj_cis_t pjsip_TEL_PARSING_PVALUE_SPEC_ESC;
 
62
 
 
63
static pj_str_t pjsip_ISUB_STR = { "isub", 4 };
 
64
static pj_str_t pjsip_EXT_STR = { "ext", 3 };
 
65
static pj_str_t pjsip_PH_CTX_STR = { "phone-context", 13 };
 
66
 
 
67
 
 
68
static const pj_str_t *tel_uri_get_scheme( const pjsip_tel_uri* );
 
69
static void *tel_uri_get_uri( pjsip_tel_uri* );
 
70
static pj_ssize_t tel_uri_print( pjsip_uri_context_e context,
 
71
                                 const pjsip_tel_uri *url, 
 
72
                                 char *buf, pj_size_t size);
 
73
static int tel_uri_cmp( pjsip_uri_context_e context,
 
74
                        const pjsip_tel_uri *url1, const pjsip_tel_uri *url2);
 
75
static pjsip_tel_uri* tel_uri_clone(pj_pool_t *pool, const pjsip_tel_uri *rhs);
 
76
static void*          tel_uri_parse( pj_scanner *scanner, pj_pool_t *pool,
 
77
                                     pj_bool_t parse_params);
 
78
 
 
79
typedef const pj_str_t* (*P_GET_SCHEME)(const void*);
 
80
typedef void*           (*P_GET_URI)(void*);
 
81
typedef pj_ssize_t      (*P_PRINT_URI)(pjsip_uri_context_e,const void *,
 
82
                                       char*,pj_size_t);
 
83
typedef int             (*P_CMP_URI)(pjsip_uri_context_e, const void*, 
 
84
                                     const void*);
 
85
typedef void*           (*P_CLONE)(pj_pool_t*, const void*);
 
86
 
 
87
static pjsip_uri_vptr tel_uri_vptr = 
 
88
{
 
89
    (P_GET_SCHEME)      &tel_uri_get_scheme,
 
90
    (P_GET_URI)         &tel_uri_get_uri,
 
91
    (P_PRINT_URI)       &tel_uri_print,
 
92
    (P_CMP_URI)         &tel_uri_cmp,
 
93
    (P_CLONE)           &tel_uri_clone
 
94
};
 
95
 
 
96
 
 
97
PJ_DEF(pjsip_tel_uri*) pjsip_tel_uri_create(pj_pool_t *pool)
 
98
{
 
99
    pjsip_tel_uri *uri = PJ_POOL_ZALLOC_T(pool, pjsip_tel_uri);
 
100
    uri->vptr = &tel_uri_vptr;
 
101
    pj_list_init(&uri->other_param);
 
102
    return uri;
 
103
}
 
104
 
 
105
 
 
106
static const pj_str_t *tel_uri_get_scheme( const pjsip_tel_uri *uri )
 
107
{
 
108
    PJ_UNUSED_ARG(uri);
 
109
    return &pjsip_parser_const()->pjsip_TEL_STR;
 
110
}
 
111
 
 
112
static void *tel_uri_get_uri( pjsip_tel_uri *uri )
 
113
{
 
114
    return uri;
 
115
}
 
116
 
 
117
 
 
118
pj_status_t pjsip_tel_uri_subsys_init(void)
 
119
{
 
120
    pj_status_t status;
 
121
 
 
122
    pj_cis_buf_init(&cis_buf);
 
123
 
 
124
    status = pj_cis_init(&cis_buf, &pjsip_TEL_EXT_VALUE_SPEC);
 
125
    PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
 
126
    pj_cis_add_str(&pjsip_TEL_EXT_VALUE_SPEC, PHONE_DIGITS);
 
127
 
 
128
    status = pj_cis_init(&cis_buf, &pjsip_TEL_NUMBER_SPEC);
 
129
    PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
 
130
    pj_cis_add_str(&pjsip_TEL_NUMBER_SPEC, NUMBER_SPEC);
 
131
 
 
132
    status = pj_cis_init(&cis_buf, &pjsip_TEL_VISUAL_SEP_SPEC);
 
133
    PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
 
134
    pj_cis_add_str(&pjsip_TEL_VISUAL_SEP_SPEC, VISUAL_SEP);
 
135
 
 
136
    status = pj_cis_init(&cis_buf, &pjsip_TEL_PHONE_CONTEXT_SPEC);
 
137
    PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
 
138
    pj_cis_add_alpha(&pjsip_TEL_PHONE_CONTEXT_SPEC);
 
139
    pj_cis_add_num(&pjsip_TEL_PHONE_CONTEXT_SPEC);
 
140
    pj_cis_add_str(&pjsip_TEL_PHONE_CONTEXT_SPEC, PHONE_CONTEXT);
 
141
 
 
142
    status = pj_cis_init(&cis_buf, &pjsip_TEL_URIC_SPEC);
 
143
    PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
 
144
    pj_cis_add_alpha(&pjsip_TEL_URIC_SPEC);
 
145
    pj_cis_add_num(&pjsip_TEL_URIC_SPEC);
 
146
    pj_cis_add_str(&pjsip_TEL_URIC_SPEC, URIC);
 
147
 
 
148
    status = pj_cis_init(&cis_buf, &pjsip_TEL_PNAME_SPEC);
 
149
    PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
 
150
    pj_cis_add_alpha(&pjsip_TEL_PNAME_SPEC);
 
151
    pj_cis_add_num(&pjsip_TEL_PNAME_SPEC);
 
152
    pj_cis_add_str(&pjsip_TEL_PNAME_SPEC, "-");
 
153
 
 
154
    status = pj_cis_init(&cis_buf, &pjsip_TEL_PVALUE_SPEC);
 
155
    PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
 
156
    pj_cis_add_alpha(&pjsip_TEL_PVALUE_SPEC);
 
157
    pj_cis_add_num(&pjsip_TEL_PVALUE_SPEC);
 
158
    pj_cis_add_str(&pjsip_TEL_PVALUE_SPEC, PARAM_CHAR);
 
159
 
 
160
    status = pj_cis_dup(&pjsip_TEL_PVALUE_SPEC_ESC, &pjsip_TEL_PVALUE_SPEC);
 
161
    pj_cis_del_str(&pjsip_TEL_PVALUE_SPEC_ESC, "%");
 
162
 
 
163
    status = pj_cis_dup(&pjsip_TEL_PARSING_PVALUE_SPEC, &pjsip_TEL_URIC_SPEC);
 
164
    PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
 
165
    pj_cis_add_cis(&pjsip_TEL_PARSING_PVALUE_SPEC, &pjsip_TEL_PVALUE_SPEC);
 
166
    pj_cis_add_str(&pjsip_TEL_PARSING_PVALUE_SPEC, "=");
 
167
 
 
168
    status = pj_cis_dup(&pjsip_TEL_PARSING_PVALUE_SPEC_ESC, 
 
169
                        &pjsip_TEL_PARSING_PVALUE_SPEC);
 
170
    pj_cis_del_str(&pjsip_TEL_PARSING_PVALUE_SPEC_ESC, "%");
 
171
 
 
172
    status = pjsip_register_uri_parser("tel", &tel_uri_parse);
 
173
    PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
 
174
 
 
175
    return PJ_SUCCESS;
 
176
}
 
177
 
 
178
/* Print tel: URI */
 
179
static pj_ssize_t tel_uri_print( pjsip_uri_context_e context,
 
180
                                 const pjsip_tel_uri *uri, 
 
181
                                 char *buf, pj_size_t size)
 
182
{
 
183
    int printed;
 
184
    char *startbuf = buf;
 
185
    char *endbuf = buf+size-1;
 
186
    const pjsip_parser_const_t *pc = pjsip_parser_const();
 
187
 
 
188
    PJ_UNUSED_ARG(context);
 
189
 
 
190
    /* Print scheme. */
 
191
    copy_advance(buf, pc->pjsip_TEL_STR);
 
192
    *buf++ = ':';
 
193
 
 
194
    /* Print number. */
 
195
    copy_advance_escape(buf, uri->number, pjsip_TEL_NUMBER_SPEC);
 
196
 
 
197
    /* ISDN sub-address or extension must appear first. */
 
198
 
 
199
    /* Extension param. */
 
200
    copy_advance_pair_escape(buf, ";ext=", 5, uri->ext_param, 
 
201
                             pjsip_TEL_EXT_VALUE_SPEC);
 
202
 
 
203
    /* ISDN sub-address. */
 
204
    copy_advance_pair_escape(buf, ";isub=", 6, uri->isub_param, 
 
205
                             pjsip_TEL_URIC_SPEC);
 
206
 
 
207
    /* Followed by phone context, if present. */
 
208
    copy_advance_pair_escape(buf, ";phone-context=", 15, uri->context, 
 
209
                             pjsip_TEL_PHONE_CONTEXT_SPEC);
 
210
 
 
211
 
 
212
    /* Print other parameters. */
 
213
    printed = pjsip_param_print_on(&uri->other_param, buf, (endbuf-buf), 
 
214
                                   &pjsip_TEL_PNAME_SPEC, 
 
215
                                   &pjsip_TEL_PVALUE_SPEC, ';');
 
216
    if (printed < 0)
 
217
        return -1;
 
218
    buf += printed;
 
219
 
 
220
    *buf = '\0';
 
221
 
 
222
    return (buf-startbuf);
 
223
}
 
224
 
 
225
/* Compare two numbers, according to RFC 3966:
 
226
 *  - both must be either local or global numbers.
 
227
 *  - The 'global-number-digits' and the 'local-number-digits' must be
 
228
 *    equal, after removing all visual separators.
 
229
 */
 
230
PJ_DEF(int) pjsip_tel_nb_cmp(const pj_str_t *number1, const pj_str_t *number2)
 
231
{
 
232
    const char *s1 = number1->ptr,
 
233
               *e1 = number1->ptr + number1->slen,
 
234
               *s2 = number2->ptr,
 
235
               *e2 = number2->ptr + number2->slen;
 
236
 
 
237
    /* Compare each number, ignoreing visual separators. */
 
238
    while (s1!=e1 && s2!=e2) {
 
239
        int diff;
 
240
 
 
241
        if (pj_cis_match(&pjsip_TEL_VISUAL_SEP_SPEC, *s1)) {
 
242
            ++s1;
 
243
            continue;
 
244
        }
 
245
        if (pj_cis_match(&pjsip_TEL_VISUAL_SEP_SPEC, *s2)) {
 
246
            ++s2;
 
247
            continue;
 
248
        }
 
249
 
 
250
        diff = pj_tolower(*s1) - pj_tolower(*s2);
 
251
        if (!diff) {
 
252
            ++s1, ++s2;
 
253
            continue;
 
254
        } else
 
255
            return diff;
 
256
    }
 
257
 
 
258
    /* Exhaust remaining visual separators. */
 
259
    while (s1!=e1 && pj_cis_match(&pjsip_TEL_VISUAL_SEP_SPEC, *s1))
 
260
        ++s1;
 
261
    while (s2!=e2 && pj_cis_match(&pjsip_TEL_VISUAL_SEP_SPEC, *s2))
 
262
        ++s2;
 
263
 
 
264
    if (s1==e1 && s2==e2)
 
265
        return 0;
 
266
    else if (s1==e1)
 
267
        return -1;
 
268
    else
 
269
        return 1;
 
270
}
 
271
 
 
272
/* Compare two tel: URI */
 
273
static int tel_uri_cmp( pjsip_uri_context_e context,
 
274
                        const pjsip_tel_uri *url1, const pjsip_tel_uri *url2)
 
275
{
 
276
    int result;
 
277
 
 
278
    PJ_UNUSED_ARG(context);
 
279
 
 
280
    /* Scheme must match. */
 
281
    if (url1->vptr != url2->vptr)
 
282
        return -1;
 
283
 
 
284
    /* Compare number. */
 
285
    result = pjsip_tel_nb_cmp(&url1->number, &url2->number);
 
286
    if (result != 0)
 
287
        return result;
 
288
 
 
289
    /* Compare phone-context as hostname or as as global nb. */
 
290
    if (url1->context.slen) {
 
291
        if (*url1->context.ptr != '+')
 
292
            result = pj_stricmp(&url1->context, &url2->context);
 
293
        else
 
294
            result = pjsip_tel_nb_cmp(&url1->context, &url2->context);
 
295
 
 
296
        if (result != 0)
 
297
            return result;
 
298
 
 
299
    } else if (url2->context.slen)
 
300
        return -1;
 
301
 
 
302
    /* Compare extension. */
 
303
    if (url1->ext_param.slen) {
 
304
        result = pjsip_tel_nb_cmp(&url1->ext_param, &url2->ext_param);
 
305
        if (result != 0)
 
306
            return result;
 
307
    }
 
308
 
 
309
    /* Compare isub bytes by bytes. */
 
310
    if (url1->isub_param.slen) {
 
311
        result = pj_stricmp(&url1->isub_param, &url2->isub_param);
 
312
        if (result != 0)
 
313
            return result;
 
314
    }
 
315
 
 
316
    /* Other parameters are compared regardless of the order.
 
317
     * If one URI has parameter not found in the other URI, the URIs are
 
318
     * not equal.
 
319
     */
 
320
    if (url1->other_param.next != &url1->other_param) {
 
321
        const pjsip_param *p1, *p2;
 
322
        int cnt1 = 0, cnt2 = 0;
 
323
 
 
324
        p1 = url1->other_param.next;
 
325
        while (p1 != &url1->other_param) {
 
326
            p2 = pjsip_param_cfind(&url2->other_param, &p1->name);
 
327
            if (!p2 )
 
328
                return 1;
 
329
 
 
330
            result = pj_stricmp(&p1->value, &p2->value);
 
331
            if (result != 0)
 
332
                return result;
 
333
 
 
334
            p1 = p1->next;
 
335
            ++cnt1;
 
336
        }
 
337
 
 
338
        p2 = url2->other_param.next;
 
339
        while (p2 != &url2->other_param)
 
340
            ++cnt2, p2 = p2->next;
 
341
 
 
342
        if (cnt1 < cnt2)
 
343
            return -1;
 
344
        else if (cnt1 > cnt2)
 
345
            return 1;
 
346
 
 
347
    } else if (url2->other_param.next != &url2->other_param)
 
348
        return -1;
 
349
 
 
350
    /* Equal. */
 
351
    return 0;
 
352
}
 
353
 
 
354
/* Clone tel: URI */
 
355
static pjsip_tel_uri* tel_uri_clone(pj_pool_t *pool, const pjsip_tel_uri *rhs)
 
356
{
 
357
    pjsip_tel_uri *uri = pjsip_tel_uri_create(pool);
 
358
 
 
359
    pj_strdup(pool, &uri->number, &rhs->number);
 
360
    pj_strdup(pool, &uri->context, &rhs->context);
 
361
    pj_strdup(pool, &uri->ext_param, &rhs->ext_param);
 
362
    pj_strdup(pool, &uri->isub_param, &rhs->isub_param);
 
363
    pjsip_param_clone(pool, &uri->other_param, &rhs->other_param);
 
364
 
 
365
    return uri;
 
366
}
 
367
 
 
368
/* Parse tel: URI 
 
369
 * THis actually returns (pjsip_tel_uri *) type.
 
370
 */
 
371
static void* tel_uri_parse( pj_scanner *scanner, pj_pool_t *pool,
 
372
                            pj_bool_t parse_params)
 
373
{
 
374
    pjsip_tel_uri *uri;
 
375
    pj_str_t token;
 
376
    int skip_ws = scanner->skip_ws;
 
377
    const pjsip_parser_const_t *pc = pjsip_parser_const();
 
378
 
 
379
    scanner->skip_ws = 0;
 
380
 
 
381
    /* Parse scheme. */
 
382
    pj_scan_get(scanner, &pc->pjsip_TOKEN_SPEC, &token);
 
383
    if (pj_scan_get_char(scanner) != ':')
 
384
        PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
 
385
    if (pj_stricmp_alnum(&token, &pc->pjsip_TEL_STR) != 0)
 
386
        PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
 
387
 
 
388
    /* Create URI */
 
389
    uri = pjsip_tel_uri_create(pool);
 
390
 
 
391
    /* Get the phone number. */
 
392
#if defined(PJSIP_UNESCAPE_IN_PLACE) && PJSIP_UNESCAPE_IN_PLACE!=0
 
393
    pj_scan_get_unescape(scanner, &pjsip_TEL_NUMBER_SPEC, &uri->number);
 
394
#else
 
395
    pj_scan_get(scanner, &pjsip_TEL_NUMBER_SPEC, &uri->number);
 
396
    uri->number = pj_str_unescape(pool, &uri->number);
 
397
#endif
 
398
 
 
399
    /* Get all parameters. */
 
400
    if (parse_params && *scanner->curptr==';') {
 
401
        pj_str_t pname, pvalue;
 
402
        const pjsip_parser_const_t *pc = pjsip_parser_const();
 
403
 
 
404
        do {
 
405
            /* Eat the ';' separator. */
 
406
            pj_scan_get_char(scanner);
 
407
 
 
408
            /* Get pname. */
 
409
            pj_scan_get(scanner, &pc->pjsip_PARAM_CHAR_SPEC, &pname);
 
410
 
 
411
            if (*scanner->curptr == '=') {
 
412
                pj_scan_get_char(scanner);
 
413
 
 
414
#               if defined(PJSIP_UNESCAPE_IN_PLACE) && PJSIP_UNESCAPE_IN_PLACE!=0
 
415
                    pj_scan_get_unescape(scanner, 
 
416
                                         &pjsip_TEL_PARSING_PVALUE_SPEC_ESC,
 
417
                                         &pvalue);
 
418
#               else
 
419
                    pj_scan_get(scanner, &pjsip_TEL_PARSING_PVALUE_SPEC, 
 
420
                                &pvalue);
 
421
                    pvalue = pj_str_unescape(pool, &pvalue);
 
422
#               endif
 
423
 
 
424
            } else {
 
425
                pvalue.slen = 0;
 
426
                pvalue.ptr = NULL;
 
427
            }
 
428
 
 
429
            /* Save the parameters. */
 
430
            if (pj_stricmp_alnum(&pname, &pjsip_ISUB_STR)==0) {
 
431
                uri->isub_param = pvalue;
 
432
            } else if (pj_stricmp_alnum(&pname, &pjsip_EXT_STR)==0) {
 
433
                uri->ext_param = pvalue;
 
434
            } else if (pj_stricmp_alnum(&pname, &pjsip_PH_CTX_STR)==0) {
 
435
                uri->context = pvalue;
 
436
            } else {
 
437
                pjsip_param *param = PJ_POOL_ALLOC_T(pool, pjsip_param);
 
438
                param->name = pname;
 
439
                param->value = pvalue;
 
440
                pj_list_insert_before(&uri->other_param, param);
 
441
            }
 
442
 
 
443
        } while (*scanner->curptr==';');
 
444
    }
 
445
 
 
446
    scanner->skip_ws = skip_ws;
 
447
    pj_scan_skip_whitespace(scanner);
 
448
    return uri;
 
449
}
 
450