~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (1.1.11)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: package-import@ubuntu.com-20140128182336-3xenud1kbnwmf3mz
* 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 3553 2011-05-05 06:14:19Z nanang $ */
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;
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
 
    return (buf-startbuf);
221
 
}
222
 
 
223
 
/* Compare two numbers, according to RFC 3966:
224
 
 *  - both must be either local or global numbers.
225
 
 *  - The 'global-number-digits' and the 'local-number-digits' must be
226
 
 *    equal, after removing all visual separators.
227
 
 */
228
 
PJ_DEF(int) pjsip_tel_nb_cmp(const pj_str_t *number1, const pj_str_t *number2)
229
 
{
230
 
    const char *s1 = number1->ptr,
231
 
               *e1 = number1->ptr + number1->slen,
232
 
               *s2 = number2->ptr,
233
 
               *e2 = number2->ptr + number2->slen;
234
 
 
235
 
    /* Compare each number, ignoreing visual separators. */
236
 
    while (s1!=e1 && s2!=e2) {
237
 
        int diff;
238
 
 
239
 
        if (pj_cis_match(&pjsip_TEL_VISUAL_SEP_SPEC, *s1)) {
240
 
            ++s1;
241
 
            continue;
242
 
        }
243
 
        if (pj_cis_match(&pjsip_TEL_VISUAL_SEP_SPEC, *s2)) {
244
 
            ++s2;
245
 
            continue;
246
 
        }
247
 
 
248
 
        diff = pj_tolower(*s1) - pj_tolower(*s2);
249
 
        if (!diff) {
250
 
            ++s1, ++s2;
251
 
            continue;
252
 
        } else
253
 
            return diff;
254
 
    }
255
 
 
256
 
    /* Exhaust remaining visual separators. */
257
 
    while (s1!=e1 && pj_cis_match(&pjsip_TEL_VISUAL_SEP_SPEC, *s1))
258
 
        ++s1;
259
 
    while (s2!=e2 && pj_cis_match(&pjsip_TEL_VISUAL_SEP_SPEC, *s2))
260
 
        ++s2;
261
 
 
262
 
    if (s1==e1 && s2==e2)
263
 
        return 0;
264
 
    else if (s1==e1)
265
 
        return -1;
266
 
    else
267
 
        return 1;
268
 
}
269
 
 
270
 
/* Compare two tel: URI */
271
 
static int tel_uri_cmp( pjsip_uri_context_e context,
272
 
                        const pjsip_tel_uri *url1, const pjsip_tel_uri *url2)
273
 
{
274
 
    int result;
275
 
 
276
 
    PJ_UNUSED_ARG(context);
277
 
 
278
 
    /* Scheme must match. */
279
 
    if (url1->vptr != url2->vptr)
280
 
        return -1;
281
 
 
282
 
    /* Compare number. */
283
 
    result = pjsip_tel_nb_cmp(&url1->number, &url2->number);
284
 
    if (result != 0)
285
 
        return result;
286
 
 
287
 
    /* Compare phone-context as hostname or as as global nb. */
288
 
    if (url1->context.slen) {
289
 
        if (*url1->context.ptr != '+')
290
 
            result = pj_stricmp(&url1->context, &url2->context);
291
 
        else
292
 
            result = pjsip_tel_nb_cmp(&url1->context, &url2->context);
293
 
 
294
 
        if (result != 0)
295
 
            return result;
296
 
 
297
 
    } else if (url2->context.slen)
298
 
        return -1;
299
 
 
300
 
    /* Compare extension. */
301
 
    if (url1->ext_param.slen) {
302
 
        result = pjsip_tel_nb_cmp(&url1->ext_param, &url2->ext_param);
303
 
        if (result != 0)
304
 
            return result;
305
 
    }
306
 
 
307
 
    /* Compare isub bytes by bytes. */
308
 
    if (url1->isub_param.slen) {
309
 
        result = pj_stricmp(&url1->isub_param, &url2->isub_param);
310
 
        if (result != 0)
311
 
            return result;
312
 
    }
313
 
 
314
 
    /* Other parameters are compared regardless of the order.
315
 
     * If one URI has parameter not found in the other URI, the URIs are
316
 
     * not equal.
317
 
     */
318
 
    if (url1->other_param.next != &url1->other_param) {
319
 
        const pjsip_param *p1, *p2;
320
 
        int cnt1 = 0, cnt2 = 0;
321
 
 
322
 
        p1 = url1->other_param.next;
323
 
        while (p1 != &url1->other_param) {
324
 
            p2 = pjsip_param_cfind(&url2->other_param, &p1->name);
325
 
            if (!p2 )
326
 
                return 1;
327
 
 
328
 
            result = pj_stricmp(&p1->value, &p2->value);
329
 
            if (result != 0)
330
 
                return result;
331
 
 
332
 
            p1 = p1->next;
333
 
            ++cnt1;
334
 
        }
335
 
 
336
 
        p2 = url2->other_param.next;
337
 
        while (p2 != &url2->other_param)
338
 
            ++cnt2, p2 = p2->next;
339
 
 
340
 
        if (cnt1 < cnt2)
341
 
            return -1;
342
 
        else if (cnt1 > cnt2)
343
 
            return 1;
344
 
 
345
 
    } else if (url2->other_param.next != &url2->other_param)
346
 
        return -1;
347
 
 
348
 
    /* Equal. */
349
 
    return 0;
350
 
}
351
 
 
352
 
/* Clone tel: URI */
353
 
static pjsip_tel_uri* tel_uri_clone(pj_pool_t *pool, const pjsip_tel_uri *rhs)
354
 
{
355
 
    pjsip_tel_uri *uri = pjsip_tel_uri_create(pool);
356
 
 
357
 
    pj_strdup(pool, &uri->number, &rhs->number);
358
 
    pj_strdup(pool, &uri->context, &rhs->context);
359
 
    pj_strdup(pool, &uri->ext_param, &rhs->ext_param);
360
 
    pj_strdup(pool, &uri->isub_param, &rhs->isub_param);
361
 
    pjsip_param_clone(pool, &uri->other_param, &rhs->other_param);
362
 
 
363
 
    return uri;
364
 
}
365
 
 
366
 
/* Parse tel: URI
367
 
 * THis actually returns (pjsip_tel_uri *) type.
368
 
 */
369
 
static void* tel_uri_parse( pj_scanner *scanner, pj_pool_t *pool,
370
 
                            pj_bool_t parse_params)
371
 
{
372
 
    pjsip_tel_uri *uri;
373
 
    pj_str_t token;
374
 
    int skip_ws = scanner->skip_ws;
375
 
    const pjsip_parser_const_t *pc = pjsip_parser_const();
376
 
 
377
 
    scanner->skip_ws = 0;
378
 
 
379
 
    /* Parse scheme. */
380
 
    pj_scan_get(scanner, &pc->pjsip_TOKEN_SPEC, &token);
381
 
    if (pj_scan_get_char(scanner) != ':')
382
 
        PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
383
 
    if (pj_stricmp_alnum(&token, &pc->pjsip_TEL_STR) != 0)
384
 
        PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
385
 
 
386
 
    /* Create URI */
387
 
    uri = pjsip_tel_uri_create(pool);
388
 
 
389
 
    /* Get the phone number. */
390
 
#if defined(PJSIP_UNESCAPE_IN_PLACE) && PJSIP_UNESCAPE_IN_PLACE!=0
391
 
    pj_scan_get_unescape(scanner, &pjsip_TEL_NUMBER_SPEC, &uri->number);
392
 
#else
393
 
    pj_scan_get(scanner, &pjsip_TEL_NUMBER_SPEC, &uri->number);
394
 
    uri->number = pj_str_unescape(pool, &uri->number);
395
 
#endif
396
 
 
397
 
    /* Get all parameters. */
398
 
    if (parse_params && *scanner->curptr==';') {
399
 
        pj_str_t pname, pvalue;
400
 
        const pjsip_parser_const_t *pc = pjsip_parser_const();
401
 
 
402
 
        do {
403
 
            /* Eat the ';' separator. */
404
 
            pj_scan_get_char(scanner);
405
 
 
406
 
            /* Get pname. */
407
 
            pj_scan_get(scanner, &pc->pjsip_PARAM_CHAR_SPEC, &pname);
408
 
 
409
 
            if (*scanner->curptr == '=') {
410
 
                pj_scan_get_char(scanner);
411
 
 
412
 
#               if defined(PJSIP_UNESCAPE_IN_PLACE) && PJSIP_UNESCAPE_IN_PLACE!=0
413
 
                    pj_scan_get_unescape(scanner,
414
 
                                         &pjsip_TEL_PARSING_PVALUE_SPEC_ESC,
415
 
                                         &pvalue);
416
 
#               else
417
 
                    pj_scan_get(scanner, &pjsip_TEL_PARSING_PVALUE_SPEC,
418
 
                                &pvalue);
419
 
                    pvalue = pj_str_unescape(pool, &pvalue);
420
 
#               endif
421
 
 
422
 
            } else {
423
 
                pvalue.slen = 0;
424
 
                pvalue.ptr = NULL;
425
 
            }
426
 
 
427
 
            /* Save the parameters. */
428
 
            if (pj_stricmp_alnum(&pname, &pjsip_ISUB_STR)==0) {
429
 
                uri->isub_param = pvalue;
430
 
            } else if (pj_stricmp_alnum(&pname, &pjsip_EXT_STR)==0) {
431
 
                uri->ext_param = pvalue;
432
 
            } else if (pj_stricmp_alnum(&pname, &pjsip_PH_CTX_STR)==0) {
433
 
                uri->context = pvalue;
434
 
            } else {
435
 
                pjsip_param *param = PJ_POOL_ALLOC_T(pool, pjsip_param);
436
 
                param->name = pname;
437
 
                param->value = pvalue;
438
 
                pj_list_insert_before(&uri->other_param, param);
439
 
            }
440
 
 
441
 
        } while (*scanner->curptr==';');
442
 
    }
443
 
 
444
 
    scanner->skip_ws = skip_ws;
445
 
    pj_scan_skip_whitespace(scanner);
446
 
    return uri;
447
 
}