1 /* $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/evsub_msg.h>
21 #include <pjsip/print_util.h>
22 #include <pjsip/sip_parser.h>
23 #include <pjlib-util/string.h>
24 #include <pj/pool.h>
25 #include <pj/string.h>
26 #include <pj/except.h>
27
28 /*
29 * Event header.
30 */
31 static int pjsip_event_hdr_print( pjsip_event_hdr *hdr,
32 char *buf, pj_size_t size);
33 static pjsip_event_hdr* pjsip_event_hdr_clone( pj_pool_t *pool,
34 const pjsip_event_hdr *hdr);
35 static pjsip_event_hdr* pjsip_event_hdr_shallow_clone( pj_pool_t *pool,
36 const pjsip_event_hdr*);
37
38 static pjsip_hdr_vptr event_hdr_vptr =
39 {
40 (pjsip_hdr_clone_fptr) &pjsip_event_hdr_clone,
41 (pjsip_hdr_clone_fptr) &pjsip_event_hdr_shallow_clone,
42 (pjsip_hdr_print_fptr) &pjsip_event_hdr_print,
43 };
44
45
pjsip_event_hdr_create(pj_pool_t * pool)46 PJ_DEF(pjsip_event_hdr*) pjsip_event_hdr_create(pj_pool_t *pool)
47 {
48 pjsip_event_hdr *hdr = PJ_POOL_ZALLOC_T(pool, pjsip_event_hdr);
49 hdr->type = PJSIP_H_OTHER;
50 hdr->name.ptr = "Event";
51 hdr->name.slen = 5;
52 hdr->sname.ptr = "o";
53 hdr->sname.slen = 1;
54 hdr->vptr = &event_hdr_vptr;
55 pj_list_init(hdr);
56 pj_list_init(&hdr->other_param);
57 return hdr;
58 }
59
pjsip_event_hdr_print(pjsip_event_hdr * hdr,char * buf,pj_size_t size)60 static int pjsip_event_hdr_print( pjsip_event_hdr *hdr,
61 char *buf, pj_size_t size)
62 {
63 char *p = buf;
64 char *endbuf = buf+size;
65 pj_ssize_t printed;
66 const pjsip_parser_const_t *pc = pjsip_parser_const();
67
68 copy_advance(p, hdr->name);
69 *p++ = ':';
70 *p++ = ' ';
71
72 copy_advance(p, hdr->event_type);
73 copy_advance_pair(p, ";id=", 4, hdr->id_param);
74
75 printed = pjsip_param_print_on(&hdr->other_param, p, endbuf-p,
76 &pc->pjsip_TOKEN_SPEC,
77 &pc->pjsip_TOKEN_SPEC, ';');
78 if (printed < 0)
79 return (int)printed;
80
81 p += printed;
82 return (int)(p - buf);
83 }
84
pjsip_event_hdr_clone(pj_pool_t * pool,const pjsip_event_hdr * rhs)85 static pjsip_event_hdr* pjsip_event_hdr_clone( pj_pool_t *pool,
86 const pjsip_event_hdr *rhs)
87 {
88 pjsip_event_hdr *hdr = pjsip_event_hdr_create(pool);
89 pj_strdup(pool, &hdr->event_type, &rhs->event_type);
90 pj_strdup(pool, &hdr->id_param, &rhs->id_param);
91 pjsip_param_clone(pool, &hdr->other_param, &rhs->other_param);
92 return hdr;
93 }
94
95 static pjsip_event_hdr*
pjsip_event_hdr_shallow_clone(pj_pool_t * pool,const pjsip_event_hdr * rhs)96 pjsip_event_hdr_shallow_clone( pj_pool_t *pool,
97 const pjsip_event_hdr *rhs )
98 {
99 pjsip_event_hdr *hdr = PJ_POOL_ALLOC_T(pool, pjsip_event_hdr);
100 pj_memcpy(hdr, rhs, sizeof(*hdr));
101 pjsip_param_shallow_clone(pool, &hdr->other_param, &rhs->other_param);
102 return hdr;
103 }
104
105
106 /*
107 * Allow-Events header.
108 */
pjsip_allow_events_hdr_create(pj_pool_t * pool)109 PJ_DEF(pjsip_allow_events_hdr*) pjsip_allow_events_hdr_create(pj_pool_t *pool)
110 {
111 const pj_str_t STR_ALLOW_EVENTS = { "Allow-Events", 12};
112 pjsip_allow_events_hdr *hdr;
113
114 hdr = pjsip_generic_array_hdr_create(pool, &STR_ALLOW_EVENTS);
115
116 if (hdr) {
117 hdr->sname.ptr = "u";
118 hdr->sname.slen = 1;
119 }
120
121 return hdr;
122 }
123
124
125 /*
126 * Subscription-State header.
127 */
128 static int pjsip_sub_state_hdr_print(pjsip_sub_state_hdr *hdr,
129 char *buf, pj_size_t size);
130 static pjsip_sub_state_hdr*
131 pjsip_sub_state_hdr_clone(pj_pool_t *pool,
132 const pjsip_sub_state_hdr *hdr);
133 static pjsip_sub_state_hdr*
134 pjsip_sub_state_hdr_shallow_clone(pj_pool_t *pool,
135 const pjsip_sub_state_hdr*);
136
137 static pjsip_hdr_vptr sub_state_hdr_vptr =
138 {
139 (pjsip_hdr_clone_fptr) &pjsip_sub_state_hdr_clone,
140 (pjsip_hdr_clone_fptr) &pjsip_sub_state_hdr_shallow_clone,
141 (pjsip_hdr_print_fptr) &pjsip_sub_state_hdr_print,
142 };
143
144
pjsip_sub_state_hdr_create(pj_pool_t * pool)145 PJ_DEF(pjsip_sub_state_hdr*) pjsip_sub_state_hdr_create(pj_pool_t *pool)
146 {
147 pj_str_t sub_state = { "Subscription-State", 18 };
148 pjsip_sub_state_hdr *hdr = PJ_POOL_ZALLOC_T(pool, pjsip_sub_state_hdr);
149 hdr->type = PJSIP_H_OTHER;
150 hdr->name = hdr->sname = sub_state;
151 hdr->vptr = &sub_state_hdr_vptr;
152 hdr->expires_param = PJSIP_EXPIRES_NOT_SPECIFIED;
153 hdr->retry_after = -1;
154 pj_list_init(hdr);
155 pj_list_init(&hdr->other_param);
156 return hdr;
157 }
158
pjsip_sub_state_hdr_print(pjsip_sub_state_hdr * hdr,char * buf,pj_size_t size)159 static int pjsip_sub_state_hdr_print(pjsip_sub_state_hdr *hdr,
160 char *buf, pj_size_t size)
161 {
162 char *p = buf;
163 char *endbuf = buf+size;
164 pj_ssize_t printed;
165 const pjsip_parser_const_t *pc = pjsip_parser_const();
166
167 copy_advance(p, hdr->name);
168 *p++ = ':';
169 *p++ = ' ';
170
171 copy_advance_escape(p, hdr->sub_state, pc->pjsip_TOKEN_SPEC);
172 copy_advance_pair_escape(p, ";reason=", 8, hdr->reason_param,
173 pc->pjsip_TOKEN_SPEC);
174 if (hdr->expires_param != PJSIP_EXPIRES_NOT_SPECIFIED) {
175 pj_memcpy(p, ";expires=", 9);
176 p += 9;
177 printed = pj_utoa(hdr->expires_param, p);
178 p += printed;
179 }
180 if (hdr->retry_after >= 0) {
181 pj_memcpy(p, ";retry-after=", 13);
182 p += 13;
183 printed = pj_utoa(hdr->retry_after, p);
184 p += printed;
185 }
186
187 printed = pjsip_param_print_on( &hdr->other_param, p, endbuf-p,
188 &pc->pjsip_TOKEN_SPEC,
189 &pc->pjsip_TOKEN_SPEC,
190 ';');
191 if (printed < 0)
192 return (int)printed;
193
194 p += printed;
195
196 return (int)(p - buf);
197 }
198
199 static pjsip_sub_state_hdr*
pjsip_sub_state_hdr_clone(pj_pool_t * pool,const pjsip_sub_state_hdr * rhs)200 pjsip_sub_state_hdr_clone(pj_pool_t *pool,
201 const pjsip_sub_state_hdr *rhs)
202 {
203 pjsip_sub_state_hdr *hdr = pjsip_sub_state_hdr_create(pool);
204 pj_strdup(pool, &hdr->sub_state, &rhs->sub_state);
205 pj_strdup(pool, &hdr->reason_param, &rhs->reason_param);
206 hdr->retry_after = rhs->retry_after;
207 hdr->expires_param = rhs->expires_param;
208 pjsip_param_clone(pool, &hdr->other_param, &rhs->other_param);
209 return hdr;
210 }
211
212 static pjsip_sub_state_hdr*
pjsip_sub_state_hdr_shallow_clone(pj_pool_t * pool,const pjsip_sub_state_hdr * rhs)213 pjsip_sub_state_hdr_shallow_clone(pj_pool_t *pool,
214 const pjsip_sub_state_hdr *rhs)
215 {
216 pjsip_sub_state_hdr *hdr = PJ_POOL_ALLOC_T(pool, pjsip_sub_state_hdr);
217 pj_memcpy(hdr, rhs, sizeof(*hdr));
218 pjsip_param_shallow_clone(pool, &hdr->other_param, &rhs->other_param);
219 return hdr;
220 }
221
222
223 /*
224 * Parse Event header.
225 */
parse_hdr_event(pjsip_parse_ctx * ctx)226 static pjsip_hdr *parse_hdr_event(pjsip_parse_ctx *ctx)
227 {
228 pjsip_event_hdr *hdr = pjsip_event_hdr_create(ctx->pool);
229 const pj_str_t id_param = { "id", 2 };
230 const pjsip_parser_const_t *pc = pjsip_parser_const();
231
232 pj_scan_get(ctx->scanner, &pc->pjsip_TOKEN_SPEC, &hdr->event_type);
233
234 while (*ctx->scanner->curptr == ';') {
235 pj_str_t pname, pvalue;
236
237 pj_scan_get_char(ctx->scanner);
238 pjsip_parse_param_imp(ctx->scanner, ctx->pool, &pname, &pvalue, 0);
239
240 if (pj_stricmp(&pname, &id_param)==0) {
241 hdr->id_param = pvalue;
242 } else {
243 pjsip_param *param = PJ_POOL_ALLOC_T(ctx->pool, pjsip_param);
244 param->name = pname;
245 param->value = pvalue;
246 pj_list_push_back(&hdr->other_param, param);
247 }
248 }
249 pjsip_parse_end_hdr_imp( ctx->scanner );
250 return (pjsip_hdr*)hdr;
251 }
252
253 /*
254 * Parse Subscription-State header.
255 */
parse_hdr_sub_state(pjsip_parse_ctx * ctx)256 static pjsip_hdr* parse_hdr_sub_state( pjsip_parse_ctx *ctx )
257 {
258 pjsip_sub_state_hdr *hdr = pjsip_sub_state_hdr_create(ctx->pool);
259 const pj_str_t reason = { "reason", 6 },
260 expires = { "expires", 7 },
261 retry_after = { "retry-after", 11 };
262 const pjsip_parser_const_t *pc = pjsip_parser_const();
263
264 pj_scan_get(ctx->scanner, &pc->pjsip_TOKEN_SPEC, &hdr->sub_state);
265
266 while (*ctx->scanner->curptr == ';') {
267 pj_str_t pname, pvalue;
268
269 pj_scan_get_char(ctx->scanner);
270 pjsip_parse_param_imp(ctx->scanner, ctx->pool, &pname, &pvalue, 0);
271
272 if (pj_stricmp(&pname, &reason) == 0) {
273 hdr->reason_param = pvalue;
274
275 } else if (pj_stricmp(&pname, &expires) == 0) {
276 hdr->expires_param = pj_strtoul(&pvalue);
277 if (hdr->expires_param == PJSIP_EXPIRES_NOT_SPECIFIED)
278 hdr->expires_param--;
279
280 } else if (pj_stricmp(&pname, &retry_after) == 0) {
281 hdr->retry_after = pj_strtoul(&pvalue);
282
283 } else {
284 pjsip_param *param = PJ_POOL_ALLOC_T(ctx->pool, pjsip_param);
285 param->name = pname;
286 param->value = pvalue;
287 pj_list_push_back(&hdr->other_param, param);
288 }
289 }
290
291 pjsip_parse_end_hdr_imp( ctx->scanner );
292 return (pjsip_hdr*)hdr;
293 }
294
295 /*
296 * Register header parsers.
297 */
pjsip_evsub_init_parser(void)298 PJ_DEF(void) pjsip_evsub_init_parser(void)
299 {
300 pjsip_register_hdr_parser( "Event", "o",
301 &parse_hdr_event);
302
303 pjsip_register_hdr_parser( "Subscription-State", NULL,
304 &parse_hdr_sub_state);
305 }
306
307