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