1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include <stdio.h>
30 #include <ctype.h>
31 #include <errno.h>
32 #include <pthread.h>
33 #include <strings.h>
34 #include <stdlib.h>
35 #include <sip.h>
36
37 #include "sip_msg.h"
38 #include "sip_miscdefs.h"
39
40 /*
41 * Returns number of digits in the given int
42 */
43 static int
sip_num_of_digits(int num)44 sip_num_of_digits(int num)
45 {
46 int num_of_bytes = 0;
47
48 do {
49 num_of_bytes += 1;
50 num = num / 10;
51 } while (num > 0);
52 return (num_of_bytes);
53 }
54
55 /*
56 * Return the int as a string
57 */
58 static char *
sip_int_to_str(int i)59 sip_int_to_str(int i)
60 {
61 int count;
62 int t;
63 int x;
64 char *str;
65
66 if (i < 0)
67 return (NULL);
68 /*
69 * the following two loops convert int i to str
70 */
71 count = 1;
72 t = i;
73 while ((t = t / 10) != 0) {
74 count++;
75 }
76
77 str = calloc(1, sizeof (char) * count + 1);
78 if (str == NULL)
79 return (NULL);
80 t = i;
81 for (x = 0; x < count; x++) {
82 int a;
83 a = t % 10;
84 str[count - 1 - x] = a + '0';
85 t = t / 10;
86 }
87 str[count] = '\0';
88 return (str);
89 }
90
91 /*
92 * Add quotes to the give str and return the quoted string
93 */
94 static char *
sip_add_aquot_to_str(char * str,boolean_t * alloc)95 sip_add_aquot_to_str(char *str, boolean_t *alloc)
96 {
97 char *new_str;
98 char *tmp = str;
99 int size;
100
101 while (isspace(*tmp))
102 tmp++;
103
104 *alloc = B_FALSE;
105 if (*tmp != SIP_LAQUOT) {
106 size = strlen(str) + 2 * sizeof (char);
107 new_str = calloc(1, size + 1);
108 if (new_str == NULL)
109 return (NULL);
110 new_str[0] = SIP_LAQUOT;
111 new_str[1] = '\0';
112 (void) strncat(new_str, str, strlen(str));
113 (void) strncat(new_str, ">", 1);
114 new_str[size] = '\0';
115 *alloc = B_TRUE;
116 return (new_str);
117 }
118
119 return (str);
120 }
121
122 /*
123 * Add an empty header
124 */
125 static int
sip_add_empty_hdr(sip_msg_t sip_msg,char * hdr_name)126 sip_add_empty_hdr(sip_msg_t sip_msg, char *hdr_name)
127 {
128 _sip_header_t *new_header;
129 int header_size;
130 _sip_msg_t *_sip_msg;
131 int csize = sizeof (char);
132
133 if (sip_msg == NULL || hdr_name == NULL)
134 return (EINVAL);
135 _sip_msg = (_sip_msg_t *)sip_msg;
136 (void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
137 if (_sip_msg->sip_msg_cannot_be_modified) {
138 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
139 return (ENOTSUP);
140 }
141
142 header_size = strlen(hdr_name) + SIP_SPACE_LEN + csize;
143
144 new_header = sip_new_header(header_size);
145 if (new_header == NULL) {
146 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
147 return (ENOMEM);
148 }
149
150 (void) snprintf(new_header->sip_hdr_start, header_size + 1,
151 "%s %c", hdr_name, SIP_HCOLON);
152
153 _sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, hdr_name);
154 if (_sip_msg->sip_msg_buf != NULL)
155 _sip_msg->sip_msg_modified = B_TRUE;
156 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
157
158 return (0);
159 }
160
161 /*
162 * Generic function to add a header with two strings to message
163 */
164 static int
sip_add_2strs_to_msg(sip_msg_t sip_msg,char * hdr_name,char * str1,boolean_t qstr1,char * str2,char * plist,char sep)165 sip_add_2strs_to_msg(sip_msg_t sip_msg, char *hdr_name, char *str1,
166 boolean_t qstr1, char *str2, char *plist, char sep)
167 {
168 _sip_header_t *new_header;
169 int header_size;
170 _sip_msg_t *_sip_msg;
171 int csize = sizeof (char);
172
173 if (sip_msg == NULL || str1 == NULL || str2 == NULL ||
174 (str1 != NULL && str1[0] == '\0') ||
175 (str2 != NULL && str2[0] == '\0')) {
176 return (EINVAL);
177 }
178 _sip_msg = (_sip_msg_t *)sip_msg;
179 (void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
180 if (_sip_msg->sip_msg_cannot_be_modified) {
181 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
182 return (ENOTSUP);
183 }
184
185 if (plist == NULL) {
186 header_size = strlen(hdr_name) + SIP_SPACE_LEN + csize +
187 SIP_SPACE_LEN + strlen(str1) + csize + strlen(str2) +
188 strlen(SIP_CRLF);
189 } else {
190 header_size = strlen(hdr_name) + SIP_SPACE_LEN + csize +
191 SIP_SPACE_LEN + strlen(str1) + csize + strlen(str2) +
192 csize + strlen(plist) + strlen(SIP_CRLF);
193 }
194 if (qstr1)
195 header_size += 2 * sizeof (char);
196
197 new_header = sip_new_header(header_size);
198 if (new_header == NULL) {
199 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
200 return (ENOMEM);
201 }
202
203 if (plist == NULL) {
204 if (qstr1) {
205 (void) snprintf(new_header->sip_hdr_start,
206 header_size + 1, "%s %c \"%s\"%c%s%s",
207 hdr_name, SIP_HCOLON, str1, sep, str2, SIP_CRLF);
208 } else {
209 (void) snprintf(new_header->sip_hdr_start,
210 header_size + 1, "%s %c %s%c%s%s",
211 hdr_name, SIP_HCOLON, str1, sep, str2, SIP_CRLF);
212 }
213 } else {
214 if (qstr1) {
215 (void) snprintf(new_header->sip_hdr_start,
216 header_size + 1,
217 "%s %c \"%s\"%c%s%c%s%s", hdr_name, SIP_HCOLON,
218 str1, sep, str2, SIP_SEMI, plist, SIP_CRLF);
219 } else {
220 (void) snprintf(new_header->sip_hdr_start,
221 header_size + 1, "%s %c %s%c%s%c%s%s",
222 hdr_name, SIP_HCOLON, str1, sep, str2, SIP_SEMI,
223 plist, SIP_CRLF);
224 }
225 }
226 _sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, NULL);
227 if (_sip_msg->sip_msg_buf != NULL)
228 _sip_msg->sip_msg_modified = B_TRUE;
229 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
230
231 return (0);
232 }
233
234 /*
235 * Generic function to add a header with a string to message
236 */
237 static int
sip_add_str_to_msg(sip_msg_t sip_msg,char * hdr_name,char * str,char * plist,char param_sep)238 sip_add_str_to_msg(sip_msg_t sip_msg, char *hdr_name, char *str, char *plist,
239 char param_sep)
240 {
241 _sip_header_t *new_header;
242 int header_size;
243 _sip_msg_t *_sip_msg;
244 int csize = sizeof (char);
245
246 if (sip_msg == NULL || str == NULL || (str != NULL && str[0] == '\0'))
247 return (EINVAL);
248 _sip_msg = (_sip_msg_t *)sip_msg;
249 (void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
250 if (_sip_msg->sip_msg_cannot_be_modified) {
251 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
252 return (ENOTSUP);
253 }
254
255 if (plist == NULL) {
256 header_size = strlen(hdr_name) + SIP_SPACE_LEN + csize +
257 SIP_SPACE_LEN + + strlen(str) + strlen(SIP_CRLF);
258 } else {
259 header_size = strlen(hdr_name) + SIP_SPACE_LEN + csize +
260 SIP_SPACE_LEN + + strlen(str) + csize + strlen(plist) +
261 strlen(SIP_CRLF);
262 }
263
264 new_header = sip_new_header(header_size);
265 if (new_header == NULL) {
266 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
267 return (ENOMEM);
268 }
269 if (plist == NULL) {
270 (void) snprintf(new_header->sip_hdr_start, header_size + 1,
271 "%s %c %s%s", hdr_name, SIP_HCOLON, str, SIP_CRLF);
272 } else {
273 (void) snprintf(new_header->sip_hdr_start, header_size + 1,
274 "%s %c %s%c%s%s", hdr_name, SIP_HCOLON, str, param_sep,
275 plist, SIP_CRLF);
276 }
277 _sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, NULL);
278 if (_sip_msg->sip_msg_buf != NULL)
279 _sip_msg->sip_msg_modified = B_TRUE;
280 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
281
282 return (0);
283 }
284
285 /*
286 * Add an header with an int to sip_msg
287 */
288 static int
sip_add_int_to_msg(sip_msg_t sip_msg,char * hdr_name,int i,char * plist)289 sip_add_int_to_msg(sip_msg_t sip_msg, char *hdr_name, int i, char *plist)
290 {
291 _sip_header_t *new_header;
292 int header_size;
293 _sip_msg_t *_sip_msg;
294 char *digit_str;
295 int csize = sizeof (char);
296
297 if (sip_msg == NULL || (hdr_name == NULL))
298 return (EINVAL);
299 _sip_msg = (_sip_msg_t *)sip_msg;
300 (void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
301 if (_sip_msg->sip_msg_cannot_be_modified) {
302 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
303 return (ENOTSUP);
304 }
305
306 /*
307 * the following two loops convert int i to str
308 */
309 digit_str = sip_int_to_str(i);
310 if (digit_str == NULL)
311 return (EINVAL);
312
313 if (plist == NULL) {
314 header_size = strlen(hdr_name) + SIP_SPACE_LEN + csize +
315 SIP_SPACE_LEN + strlen(digit_str) + strlen(SIP_CRLF);
316 } else {
317 header_size = strlen(hdr_name) + SIP_SPACE_LEN + csize +
318 SIP_SPACE_LEN + strlen(digit_str) + csize +
319 strlen(plist) + strlen(SIP_CRLF);
320 }
321
322 new_header = sip_new_header(header_size);
323 if (new_header == NULL) {
324 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
325 free(digit_str);
326 return (ENOMEM);
327 }
328
329 if (plist == NULL) {
330 (void) snprintf(new_header->sip_hdr_start, header_size + 1,
331 "%s %c %s%s", hdr_name, SIP_HCOLON, digit_str, SIP_CRLF);
332 } else {
333 (void) snprintf(new_header->sip_hdr_start, header_size + 1,
334 "%s %c %s%c%s%s", hdr_name, SIP_HCOLON, digit_str,
335 SIP_SEMI, plist, SIP_CRLF);
336 }
337 free(digit_str);
338 _sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, NULL);
339 if (_sip_msg->sip_msg_buf != NULL)
340 _sip_msg->sip_msg_modified = B_TRUE;
341 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
342
343 return (0);
344 }
345
346 /*
347 * Add a header with an int and string to sip_msg
348 */
349 static int
sip_add_intstr_to_msg(sip_msg_t sip_msg,char * hdr_name,int i,char * s,char * plist)350 sip_add_intstr_to_msg(sip_msg_t sip_msg, char *hdr_name, int i, char *s,
351 char *plist)
352 {
353 _sip_header_t *new_header;
354 int header_size;
355 _sip_msg_t *_sip_msg;
356 char *digit_str;
357 int csize = sizeof (char);
358
359 if (sip_msg == NULL || (hdr_name == NULL))
360 return (EINVAL);
361 _sip_msg = (_sip_msg_t *)sip_msg;
362 (void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
363 if (_sip_msg->sip_msg_cannot_be_modified) {
364 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
365 return (ENOTSUP);
366 }
367
368 /*
369 * the following two loops convert int i to str
370 */
371 digit_str = sip_int_to_str(i);
372 if (digit_str == NULL) {
373 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
374 return (EINVAL);
375 }
376 if (plist == NULL) {
377 header_size = strlen(hdr_name) + SIP_SPACE_LEN + csize +
378 SIP_SPACE_LEN + strlen(digit_str) + csize + strlen(s) +
379 strlen(SIP_CRLF);
380 } else {
381 header_size = strlen(hdr_name) + SIP_SPACE_LEN + csize +
382 SIP_SPACE_LEN + strlen(digit_str) + csize + strlen(s) +
383 csize + strlen(plist) + strlen(SIP_CRLF);
384 }
385
386 new_header = sip_new_header(header_size);
387 if (new_header == NULL) {
388 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
389 free(digit_str);
390 return (ENOMEM);
391 }
392
393 if (plist == NULL) {
394 (void) snprintf(new_header->sip_hdr_start, header_size + 1,
395 "%s %c %s %s%s", hdr_name, SIP_HCOLON, digit_str, s,
396 SIP_CRLF);
397 } else {
398 (void) snprintf(new_header->sip_hdr_start, header_size + 1,
399 "%s %c %s %s%c%s%s", hdr_name, SIP_HCOLON, digit_str,
400 s, SIP_SEMI, plist, SIP_CRLF);
401 }
402 free(digit_str);
403 _sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, NULL);
404 if (_sip_msg->sip_msg_buf != NULL)
405 _sip_msg->sip_msg_modified = B_TRUE;
406 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
407
408 return (0);
409 }
410
411 /*
412 * Generic function to add Contact, From, To, Route or Record-Route header
413 */
414 static int
sip_add_name_aspec(sip_msg_t sip_msg,char * display_name,char * uri,char * tags,boolean_t add_aquot,char * header_name,char * params)415 sip_add_name_aspec(sip_msg_t sip_msg, char *display_name, char *uri,
416 char *tags, boolean_t add_aquot, char *header_name, char *params)
417 {
418 char *t = uri;
419 boolean_t qalloc = B_FALSE;
420 boolean_t palloc = B_FALSE;
421 int r;
422
423 if (sip_msg == NULL || uri == NULL || header_name == NULL)
424 return (EINVAL);
425 if (display_name != NULL && !add_aquot)
426 return (EINVAL);
427 if (add_aquot) {
428 t = sip_add_aquot_to_str(uri, &qalloc);
429 if (t == NULL)
430 return (ENOMEM);
431 }
432 if (tags != NULL) {
433 int plen;
434
435 if (params != NULL)
436 return (EINVAL);
437
438 plen = strlen(SIP_TAG) + strlen(tags) + 1;
439 params = malloc(plen);
440 if (params == NULL)
441 return (ENOMEM);
442 (void) snprintf(params, plen, "%s%s", SIP_TAG, tags);
443 params[plen - 1] = '\0';
444 palloc = B_TRUE;
445 }
446 if (display_name == NULL) {
447 r = sip_add_2strs_to_msg(sip_msg, header_name, " ", B_FALSE,
448 t, params, SIP_SP);
449 } else {
450 r = sip_add_2strs_to_msg(sip_msg, header_name, display_name,
451 B_TRUE, t, params, SIP_SP);
452 }
453 if (qalloc)
454 free(t);
455 if (palloc)
456 free(params);
457 return (r);
458 }
459
460 /*
461 * Accept = "Accept" ":" (media-range [ accept-params ])
462 * media-range = ( "X/X" | (type "/" "*") | (type "/" subtype))*(";" parameter)
463 * accept-params = ";" "q" "=" qvalue *(accept-extension)
464 * accept-extension = ";" token [ "=" (token | quoted-str)
465 *
466 * function take two char ptrs - type and subtype - if any of them is NULL
467 * the corresponding value will be set to "*" in header
468 */
469 int
sip_add_accept(sip_msg_t sip_msg,char * type,char * subtype,char * m_par,char * a_par)470 sip_add_accept(sip_msg_t sip_msg, char *type, char *subtype, char *m_par,
471 char *a_par)
472 {
473 int ret;
474 char *plist;
475 int size;
476 boolean_t alloc = B_FALSE;
477
478 if (type == NULL && subtype == NULL) {
479 ret = sip_add_empty_hdr(sip_msg, SIP_ACCEPT);
480 return (ret);
481 }
482
483 if ((m_par != NULL) && (a_par != NULL)) {
484 size = strlen(m_par) + strlen(a_par) + 2 * sizeof (char);
485 plist = calloc(1, size * sizeof (char));
486 (void) strncpy(plist, m_par, strlen(m_par));
487 (void) strncat(plist, ";", 1);
488 (void) strncat(plist, a_par, strlen(a_par));
489 alloc = B_TRUE;
490 } else if (m_par != NULL) {
491 plist = m_par;
492 } else
493 plist = a_par;
494
495 if ((type != NULL) && (subtype != NULL)) {
496 ret = sip_add_2strs_to_msg(sip_msg, SIP_ACCEPT, type, B_FALSE,
497 subtype, plist, SIP_SLASH);
498 } else if (type != NULL) {
499 ret = sip_add_2strs_to_msg(sip_msg, SIP_ACCEPT, type, B_FALSE,
500 "*", plist, SIP_SLASH);
501 } else {
502 ret = EINVAL;
503 }
504
505 if (alloc == B_TRUE)
506 free(plist);
507
508 return (ret);
509 }
510
511
512 /*
513 * Accept-Encoding = "Accept-Encoding" ":" 1#(codings [ ";" "q" "=" qval])
514 * codings = ( content-coding | "*" )
515 * content-coding = token
516 *
517 * function take one char ptr, if NULL value will be set to "*"
518 */
519 int
sip_add_accept_enc(sip_msg_t sip_msg,char * code,char * plist)520 sip_add_accept_enc(sip_msg_t sip_msg, char *code, char *plist)
521 {
522 int ret;
523
524 if (code == NULL) {
525 ret = sip_add_str_to_msg(sip_msg, SIP_ACCEPT_ENCODE, "*", plist,
526 SIP_SEMI);
527 } else {
528 ret = sip_add_str_to_msg(sip_msg, SIP_ACCEPT_ENCODE, code,
529 plist, SIP_SEMI);
530 }
531 return (ret);
532 }
533
534 /*
535 * Accept-Language = "Accept-Language" ":" 1#( language-range [ ";" "q""=" val])
536 * language-range = ( ( 1*8ALPHA *("-" 1*8ALPHA))|"*")
537 */
538 int
sip_add_accept_lang(sip_msg_t sip_msg,char * lang,char * plist)539 sip_add_accept_lang(sip_msg_t sip_msg, char *lang, char *plist)
540 {
541 int ret;
542
543 if (lang == NULL) {
544 ret = sip_add_empty_hdr(sip_msg, SIP_ACCEPT_LANG);
545 return (ret);
546 }
547 ret = sip_add_str_to_msg(sip_msg, SIP_ACCEPT_LANG, lang, plist,
548 SIP_SEMI);
549 return (ret);
550 }
551
552 /*
553 * Alert-Info = "Alert-Info" ":" "<" URI ">"
554 */
555 int
sip_add_alert_info(sip_msg_t sip_msg,char * alert,char * plist)556 sip_add_alert_info(sip_msg_t sip_msg, char *alert, char *plist)
557 {
558 int ret;
559 char *tmp;
560 boolean_t alloc;
561
562 if (alert == NULL)
563 return (EINVAL);
564 tmp = sip_add_aquot_to_str(alert, &alloc);
565 if (tmp == NULL)
566 return (ENOMEM);
567 ret = sip_add_str_to_msg(sip_msg, SIP_ALERT_INFO, tmp, plist, SIP_SEMI);
568 if (alloc)
569 free(tmp);
570 return (ret);
571 }
572
573 /*
574 * Allow = "Allow" ":" method-name1[, method-name2..]
575 * method-name = "INVITE" | "ACK" | "OPTIONS" | "CANCEL" | "BYE"
576 */
577 int
sip_add_allow(sip_msg_t sip_msg,sip_method_t method)578 sip_add_allow(sip_msg_t sip_msg, sip_method_t method)
579 {
580 int ret;
581
582 if (method == 0 || method >= MAX_SIP_METHODS)
583 return (EINVAL);
584 ret = sip_add_str_to_msg(sip_msg, SIP_ALLOW, sip_methods[method].name,
585 NULL, (char)NULL);
586 return (ret);
587 }
588
589 /*
590 * Call-Info = "Call-Info" HCOLON info *(COMMA info)
591 * info = LAQUOT absoluteURI RAQUOT *( SEMI info-param)
592 * info-param = ( "purpose" EQUAL ( "icon" / "info"
593 * / "card" / token ) ) / generic-param
594 */
595 int
sip_add_call_info(sip_msg_t sip_msg,char * uri,char * plist)596 sip_add_call_info(sip_msg_t sip_msg, char *uri, char *plist)
597 {
598 char *tmp;
599 boolean_t alloc;
600 int r;
601
602 if (uri == NULL)
603 return (EINVAL);
604 tmp = sip_add_aquot_to_str(uri, &alloc);
605 if (tmp == NULL)
606 return (ENOMEM);
607 r = sip_add_str_to_msg(sip_msg, SIP_CALL_INFO, tmp, plist, SIP_SEMI);
608 if (alloc)
609 free(tmp);
610 return (r);
611 }
612
613 /*
614 * Content-Disposition = "Content-Disposition" HCOLON
615 * disp-type *( SEMI disp-param )
616 * disp-type = "render" / "session" / "icon" / "alert"
617 * / disp-extension-token
618 * disp-param = handling-param / generic-param
619 * handling-param = "handling" EQUAL
620 * ( "optional" / "required"
621 * / other-handling )
622 * other-handling = token
623 * disp-extension-token = token
624 */
625 int
sip_add_content_disp(sip_msg_t sip_msg,char * dis_type,char * plist)626 sip_add_content_disp(sip_msg_t sip_msg, char *dis_type, char *plist)
627 {
628 int ret;
629
630 if (dis_type == NULL)
631 return (EINVAL);
632
633 ret = sip_add_str_to_msg(sip_msg, SIP_CONTENT_DIS, dis_type, plist,
634 SIP_SEMI);
635 return (ret);
636 }
637
638 /*
639 * Content-Encoding = ( "Content-Encoding" / "e" ) HCOLON
640 * content-coding *(COMMA content-coding)
641 * content-coding = token
642 */
643 int
sip_add_content_enc(sip_msg_t sip_msg,char * code)644 sip_add_content_enc(sip_msg_t sip_msg, char *code)
645 {
646 int ret;
647
648 if (code == NULL)
649 return (EINVAL);
650
651 ret = sip_add_str_to_msg(sip_msg, SIP_CONTENT_ENCODE, code, NULL,
652 (char)NULL);
653 return (ret);
654 }
655
656 /*
657 * Content-Language = "Content-Language" HCOLON
658 * language-tag *(COMMA language-tag)
659 * language-tag = primary-tag *( "-" subtag )
660 * primary-tag = 1*8ALPHA
661 * subtag = 1*8ALPHA
662 */
663 int
sip_add_content_lang(sip_msg_t sip_msg,char * lang)664 sip_add_content_lang(sip_msg_t sip_msg, char *lang)
665 {
666 int ret;
667
668 if (lang == NULL)
669 return (EINVAL);
670 ret = sip_add_str_to_msg(sip_msg, SIP_CONTENT_LANG, lang, NULL,
671 (char)NULL);
672 return (ret);
673 }
674
675 /*
676 * Date = "Date" HCOLON SIP-date
677 * SIP-date = rfc1123-date
678 * rfc1123-date = wkday "," SP date1 SP time SP "GMT"
679 * date1 = 2DIGIT SP month SP 4DIGIT
680 * ; day month year (e.g., 02 Jun 1982)
681 * time = 2DIGIT ":" 2DIGIT ":" 2DIGIT
682 * ; 00:00:00 - 23:59:59
683 * wkday = "Mon" / "Tue" / "Wed"
684 * / "Thu" / "Fri" / "Sat" / "Sun"
685 * month = "Jan" / "Feb" / "Mar" / "Apr"
686 * / "May" / "Jun" / "Jul" / "Aug"
687 * / "Sep" / "Oct" / "Nov" / "Dec"
688 */
689 int
sip_add_date(sip_msg_t sip_msg,char * date)690 sip_add_date(sip_msg_t sip_msg, char *date)
691 {
692 int ret;
693
694 if (date == NULL)
695 return (EINVAL);
696 ret = sip_add_str_to_msg(sip_msg, SIP_DATE, date, NULL, (char)NULL);
697 return (ret);
698 }
699
700 /*
701 * Error-Info = "Error-Info" HCOLON error-uri *(COMMA error-uri)
702 * error-uri = LAQUOT absoluteURI RAQUOT *( SEMI generic-param )
703 */
704 int
sip_add_error_info(sip_msg_t sip_msg,char * uri,char * plist)705 sip_add_error_info(sip_msg_t sip_msg, char *uri, char *plist)
706 {
707 char *tmp;
708 boolean_t alloc;
709 int r;
710
711 if (uri == NULL)
712 return (EINVAL);
713 tmp = sip_add_aquot_to_str(uri, &alloc);
714 if (tmp == NULL)
715 return (EINVAL);
716
717 r = sip_add_str_to_msg(sip_msg, SIP_ERROR_INFO, tmp, plist, SIP_SEMI);
718 if (alloc)
719 free(tmp);
720 return (r);
721 }
722
723 /*
724 * Expires = "Expires" HCOLON delta-seconds
725 * delta-seconds = 1*DIGIT
726 */
727 int
sip_add_expires(sip_msg_t sip_msg,int secs)728 sip_add_expires(sip_msg_t sip_msg, int secs)
729 {
730 int ret;
731
732 if (sip_msg == NULL || (int)secs < 0)
733 return (EINVAL);
734
735 ret = sip_add_int_to_msg(sip_msg, SIP_EXPIRE, secs, NULL);
736 return (ret);
737 }
738
739 /*
740 * In-Reply-To = "In-Reply-To" HCOLON callid *(COMMA callid)
741 * callid = word [ "@" word ]
742 */
743 int
sip_add_in_reply_to(sip_msg_t sip_msg,char * reply_id)744 sip_add_in_reply_to(sip_msg_t sip_msg, char *reply_id)
745 {
746 int r;
747
748 if (reply_id == NULL)
749 return (EINVAL);
750 r = sip_add_str_to_msg(sip_msg, SIP_IN_REPLY_TO, reply_id, NULL,
751 (char)NULL);
752 return (r);
753 }
754
755 /*
756 * RSeq = "RSeq" HCOLON response-num
757 */
758 int
sip_add_rseq(sip_msg_t sip_msg,int resp_num)759 sip_add_rseq(sip_msg_t sip_msg, int resp_num)
760 {
761 int ret;
762
763 if (sip_msg == NULL || resp_num <= 0)
764 return (EINVAL);
765 ret = sip_add_int_to_msg(sip_msg, SIP_RSEQ, resp_num, NULL);
766 return (ret);
767 }
768
769 /*
770 * Min-Expires = "Min-Expires" HCOLON delta-seconds
771 */
772 int
sip_add_min_expires(sip_msg_t sip_msg,int secs)773 sip_add_min_expires(sip_msg_t sip_msg, int secs)
774 {
775 int ret;
776
777 if (sip_msg == NULL || (int)secs < 0)
778 return (EINVAL);
779 ret = sip_add_int_to_msg(sip_msg, SIP_MIN_EXPIRE, secs, NULL);
780 return (ret);
781 }
782
783 /*
784 * MIME-Version = "MIME-Version" HCOLON 1*DIGIT "." 1*DIGIT
785 */
786 int
sip_add_mime_version(sip_msg_t sip_msg,char * version)787 sip_add_mime_version(sip_msg_t sip_msg, char *version)
788 {
789 int ret;
790
791 if (version == NULL)
792 return (EINVAL);
793 ret = sip_add_str_to_msg(sip_msg, SIP_MIME_VERSION, version, NULL,
794 (char)NULL);
795 return (ret);
796 }
797
798 /*
799 * Organization = "Organization" HCOLON [TEXT-UTF8-TRIM]
800 */
801 int
sip_add_org(sip_msg_t sip_msg,char * org)802 sip_add_org(sip_msg_t sip_msg, char *org)
803 {
804 int ret;
805
806 if (org == NULL) {
807 ret = sip_add_empty_hdr(sip_msg, SIP_ORGANIZATION);
808 } else {
809 ret = sip_add_str_to_msg(sip_msg, SIP_ORGANIZATION, org, NULL,
810 (char)NULL);
811 }
812 return (ret);
813 }
814
815 /*
816 * Priority = "Priority" HCOLON priority-value
817 * priority-value = "emergency" / "urgent" / "normal"
818 * / "non-urgent" / other-priority
819 * other-priority = token
820 */
821 int
sip_add_priority(sip_msg_t sip_msg,char * prio)822 sip_add_priority(sip_msg_t sip_msg, char *prio)
823 {
824 int ret;
825
826 if (prio == NULL)
827 return (EINVAL);
828 ret = sip_add_str_to_msg(sip_msg, SIP_PRIORITY, prio, NULL, (char)NULL);
829
830 return (ret);
831 }
832
833 /*
834 * Reply-To = "Reply-To" HCOLON rplyto-spec
835 * rplyto-spec = ( name-addr / addr-spec )
836 * *( SEMI rplyto-param )
837 * rplyto-param = generic-param
838 */
839 int
sip_add_reply_to(sip_msg_t sip_msg,char * uname,char * addr,char * plist,boolean_t add_aquot)840 sip_add_reply_to(sip_msg_t sip_msg, char *uname, char *addr, char *plist,
841 boolean_t add_aquot)
842 {
843 return (sip_add_name_aspec(sip_msg, uname, addr, NULL, add_aquot,
844 SIP_REPLYTO, plist));
845 }
846
847
848 /*
849 * Privacy-hdr = "Privacy" HCOLON priv-value *(";" priv-value)
850 * priv-value = "header" / "session" / "user" / "none" / "critical"
851 * / token
852 */
853 int
sip_add_privacy(sip_msg_t sip_msg,char * priv_val)854 sip_add_privacy(sip_msg_t sip_msg, char *priv_val)
855 {
856 int ret;
857
858 if (priv_val == NULL)
859 return (EINVAL);
860 ret = sip_add_str_to_msg(sip_msg, SIP_PRIVACY, priv_val, NULL,
861 (char)NULL);
862 return (ret);
863 }
864
865 /*
866 * Require = "Require" HCOLON option-tag *(COMMA option-tag)
867 * option-tag = token
868 */
869 int
sip_add_require(sip_msg_t sip_msg,char * req)870 sip_add_require(sip_msg_t sip_msg, char *req)
871 {
872 int ret;
873
874 if (req == NULL)
875 return (EINVAL);
876 ret = sip_add_str_to_msg(sip_msg, SIP_REQUIRE, req, NULL, (char)NULL);
877 return (ret);
878 }
879
880 /*
881 * Retry-After = "Retry-After" HCOLON delta-seconds
882 * [ comment ] *( SEMI retry-param )
883 * retry-param = ("duration" EQUAL delta-seconds)
884 * / generic-param
885 */
886 int
sip_add_retry_after(sip_msg_t sip_msg,int secs,char * cmt,char * plist)887 sip_add_retry_after(sip_msg_t sip_msg, int secs, char *cmt, char *plist)
888 {
889 int r;
890
891 if (secs <= 0)
892 return (EINVAL);
893
894 if (cmt == NULL) {
895 r = sip_add_int_to_msg(sip_msg, SIP_RETRY_AFTER, secs, plist);
896 return (r);
897 }
898
899 r = sip_add_intstr_to_msg(sip_msg, SIP_RETRY_AFTER, secs, cmt, plist);
900 return (r);
901 }
902
903 /*
904 * Server = "Server" HCOLON server-val *(LWS server-val)
905 * server-val = product / comment
906 * product = token [SLASH product-version]
907 * product-version = token
908 */
909 int
sip_add_server(sip_msg_t sip_msg,char * svr)910 sip_add_server(sip_msg_t sip_msg, char *svr)
911 {
912 int ret;
913
914 if (svr == NULL)
915 return (EINVAL);
916 ret = sip_add_str_to_msg(sip_msg, SIP_SERVER, svr, NULL, (char)NULL);
917 return (ret);
918 }
919
920 /*
921 * Subject = ( "Subject" / "s" ) HCOLON [TEXT-UTF8-TRIM]
922 */
923 int
sip_add_subject(sip_msg_t sip_msg,char * subject)924 sip_add_subject(sip_msg_t sip_msg, char *subject)
925 {
926 int ret;
927
928 if (subject == NULL) {
929 ret = sip_add_empty_hdr(sip_msg, SIP_SUBJECT);
930 } else {
931 ret = sip_add_str_to_msg(sip_msg, SIP_SUBJECT, subject, NULL,
932 (char)NULL);
933 }
934 return (ret);
935 }
936
937 /*
938 * Supported = ( "Supported" / "k" ) HCOLON
939 * [option-tag *(COMMA option-tag)]
940 */
941 int
sip_add_supported(sip_msg_t sip_msg,char * support)942 sip_add_supported(sip_msg_t sip_msg, char *support)
943 {
944 int ret;
945
946 if (support == NULL) {
947 ret = sip_add_empty_hdr(sip_msg, SIP_SUPPORT);
948 } else {
949 ret = sip_add_str_to_msg(sip_msg, SIP_SUPPORT, support, NULL,
950 (char)NULL);
951 }
952 return (ret);
953 }
954
955 /*
956 * Timestamp = "Timestamp" HCOLON 1*(DIGIT)
957 * [ "." *(DIGIT) ] [ LWS delay ]
958 * delay = *(DIGIT) [ "." *(DIGIT) ]
959 */
960 int
sip_add_tstamp(sip_msg_t sip_msg,char * time,char * delay)961 sip_add_tstamp(sip_msg_t sip_msg, char *time, char *delay)
962 {
963 int ret;
964
965 if (delay == NULL) {
966 ret = sip_add_str_to_msg(sip_msg, SIP_TIMESTAMP, time, NULL,
967 (char)NULL);
968 } else {
969 ret = sip_add_2strs_to_msg(sip_msg, SIP_TIMESTAMP, time,
970 B_FALSE, delay, NULL, ' ');
971 }
972 return (ret);
973 }
974
975 /*
976 * Unsupported = "Unsupported" HCOLON option-tag *(COMMA option-tag)
977 */
978 int
sip_add_unsupported(sip_msg_t sip_msg,char * unsupport)979 sip_add_unsupported(sip_msg_t sip_msg, char *unsupport)
980 {
981 int ret;
982
983 if (unsupport == NULL)
984 return (EINVAL);
985 ret = sip_add_str_to_msg(sip_msg, SIP_UNSUPPORT, unsupport, NULL,
986 (char)NULL);
987 return (ret);
988 }
989
990 /*
991 * User-Agent = "User-Agent" HCOLON server-val *(LWS server-val)
992 */
993 int
sip_add_user_agent(sip_msg_t sip_msg,char * usr)994 sip_add_user_agent(sip_msg_t sip_msg, char *usr)
995 {
996 int r;
997
998 if (usr == NULL)
999 return (EINVAL);
1000 r = sip_add_str_to_msg(sip_msg, SIP_USER_AGENT, usr, NULL, (char)NULL);
1001 return (r);
1002 }
1003
1004 /*
1005 * Warning = "Warning" HCOLON warning-value *(COMMA warning-value)
1006 * warning-value = warn-code SP warn-agent SP warn-text
1007 * warn-code = 3DIGIT
1008 * warn-agent = hostport / pseudonym
1009 * ; the name or pseudonym of the server adding
1010 * ; the Warning header, for use in debugging
1011 * warn-text = quoted-string
1012 * pseudonym = token
1013 */
1014 int
sip_add_warning(sip_msg_t sip_msg,int code,char * addr,char * msg)1015 sip_add_warning(sip_msg_t sip_msg, int code, char *addr, char *msg)
1016 {
1017 _sip_header_t *new_header;
1018 int header_size;
1019 _sip_msg_t *_sip_msg;
1020 char *hdr_name = SIP_WARNING;
1021
1022 if (sip_msg == NULL || addr == NULL || msg == NULL ||
1023 addr[0] == '\0' || msg == '\0' || code < 100 || code > 999) {
1024 return (EINVAL);
1025 }
1026
1027 _sip_msg = (_sip_msg_t *)sip_msg;
1028 (void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
1029 if (_sip_msg->sip_msg_cannot_be_modified) {
1030 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
1031 return (ENOTSUP);
1032 }
1033
1034 header_size = strlen(hdr_name) + SIP_SPACE_LEN + sizeof (char) +
1035 SIP_SPACE_LEN + sip_num_of_digits(code) + SIP_SPACE_LEN +
1036 strlen(addr) + SIP_SPACE_LEN + sizeof (char) + strlen(msg) +
1037 sizeof (char) + strlen(SIP_CRLF);
1038
1039 new_header = sip_new_header(header_size);
1040 if (new_header == NULL) {
1041 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
1042 return (ENOMEM);
1043 }
1044
1045 (void) snprintf(new_header->sip_hdr_start, header_size + 1,
1046 "%s %c %d %s \"%s\"%s", hdr_name, SIP_HCOLON, code, addr,
1047 msg, SIP_CRLF);
1048 _sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, NULL);
1049 if (_sip_msg->sip_msg_buf != NULL)
1050 _sip_msg->sip_msg_modified = B_TRUE;
1051 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
1052
1053 return (0);
1054 }
1055
1056 /*
1057 * RAck = "RAck" HCOLON response-num LWS CSeq-num LWS Method
1058 * response-num = 1*DIGIT
1059 * CSeq-num = 1*DIGIT
1060 */
1061 int
sip_add_rack(sip_msg_t sip_msg,int resp_num,int cseq,sip_method_t method)1062 sip_add_rack(sip_msg_t sip_msg, int resp_num, int cseq, sip_method_t method)
1063 {
1064 _sip_header_t *new_header;
1065 int header_size;
1066 _sip_msg_t *_sip_msg;
1067 char *hdr_name = SIP_RACK;
1068
1069 if (sip_msg == NULL || resp_num <= 0 || cseq < 0 || method <= 0 ||
1070 method >= MAX_SIP_METHODS) {
1071 return (EINVAL);
1072 }
1073
1074 _sip_msg = (_sip_msg_t *)sip_msg;
1075 (void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
1076 if (_sip_msg->sip_msg_cannot_be_modified) {
1077 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
1078 return (ENOTSUP);
1079 }
1080
1081 header_size = strlen(hdr_name) + SIP_SPACE_LEN + sizeof (char) +
1082 SIP_SPACE_LEN + sip_num_of_digits(resp_num) + SIP_SPACE_LEN +
1083 sip_num_of_digits(cseq) + SIP_SPACE_LEN +
1084 strlen(sip_methods[method].name) + strlen(SIP_CRLF);
1085
1086 new_header = sip_new_header(header_size);
1087 if (new_header == NULL) {
1088 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
1089 return (ENOMEM);
1090 }
1091
1092 (void) snprintf(new_header->sip_hdr_start, header_size + 1,
1093 "%s %c %d %d %s%s", hdr_name, SIP_HCOLON, resp_num, cseq,
1094 sip_methods[method].name, SIP_CRLF);
1095
1096 _sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, NULL);
1097 if (_sip_msg->sip_msg_buf != NULL)
1098 _sip_msg->sip_msg_modified = B_TRUE;
1099 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
1100
1101 return (0);
1102
1103 }
1104
1105 /*
1106 * Allow-Events = ( "Allow-Events" / "u" ) HCOLON event-type
1107 * *(COMMA event-type)
1108 */
1109 int
sip_add_allow_events(sip_msg_t sip_msg,char * t_event)1110 sip_add_allow_events(sip_msg_t sip_msg, char *t_event)
1111 {
1112 return (sip_add_str_to_msg(sip_msg, SIP_ALLOW_EVENTS, t_event, NULL,
1113 (char)NULL));
1114 }
1115
1116 /*
1117 * Event = ( "Event" / "o" ) HCOLON event-type
1118 * *( SEMI event-param )
1119 * event-type = event-package *( "." event-template )
1120 * event-package = token-nodot
1121 * event-template = token-nodot
1122 * token-nodot = 1*( alphanum / "-" / "!" / "%" / "*"
1123 * / "_" / "+" / "`" / "'" / "~" )
1124 * event-param = generic-param / ( "id" EQUAL token )
1125 */
1126 int
sip_add_event(sip_msg_t sip_msg,char * t_event,char * plist)1127 sip_add_event(sip_msg_t sip_msg, char *t_event, char *plist)
1128 {
1129 return (sip_add_str_to_msg(sip_msg, SIP_EVENT, t_event, plist,
1130 SIP_SEMI));
1131 }
1132
1133 /*
1134 * Subscription-State = "Subscription-State" HCOLON substate-value
1135 * *( SEMI subexp-params )
1136 * substate-value = "active" / "pending" / "terminated"
1137 * / extension-substate
1138 * extension-substate = token
1139 * subexp-params = ("reason" EQUAL event-reason-value)
1140 * / ("expires" EQUAL delta-seconds)*
1141 * / ("retry-after" EQUAL delta-seconds)
1142 * / generic-param
1143 * event-reason-value = "deactivated"
1144 * / "probation"
1145 * / "rejected"
1146 * / "timeout"
1147 * / "giveup"
1148 * / "noresource"
1149 * / event-reason-extension
1150 * event-reason-extension = token
1151 */
1152 int
sip_add_substate(sip_msg_t sip_msg,char * sub,char * plist)1153 sip_add_substate(sip_msg_t sip_msg, char *sub, char *plist)
1154 {
1155 return (sip_add_str_to_msg(sip_msg, SIP_SUBSCRIPTION_STATE, sub, plist,
1156 SIP_SEMI));
1157 }
1158
1159 /*
1160 * Authorization = "Authorization" HCOLON credentials
1161 * credentials = ("Digest" LWS digest-response)
1162 * / other-response
1163 * digest-response = dig-resp *(COMMA dig-resp)
1164 * dig-resp = username / realm / nonce / digest-uri
1165 * / dresponse / algorithm / cnonce
1166 * / opaque / message-qop
1167 * / nonce-count / auth-param
1168 * username = "username" EQUAL username-value
1169 * username-value = quoted-string
1170 * digest-uri = "uri" EQUAL LDQUOT digest-uri-value RDQUOT
1171 * digest-uri-value = rquest-uri ; Equal to request-uri as specified
1172 * by HTTP/1.1
1173 * message-qop = "qop" EQUAL qop-value
1174 * cnonce = "cnonce" EQUAL cnonce-value
1175 * cnonce-value = nonce-value
1176 * nonce-count = "nc" EQUAL nc-value
1177 * nc-value = 8LHEX
1178 * dresponse = "response" EQUAL request-digest
1179 * request-digest = LDQUOT 32LHEX RDQUOT
1180 * auth-param = auth-param-name EQUAL
1181 * ( token / quoted-string )
1182 * auth-param-name = token
1183 * other-response = auth-scheme LWS auth-param
1184 * *(COMMA auth-param)
1185 * auth-scheme = token
1186 */
1187 int
sip_add_author(sip_msg_t sip_msg,char * scheme,char * param)1188 sip_add_author(sip_msg_t sip_msg, char *scheme, char *param)
1189 {
1190 return (sip_add_str_to_msg(sip_msg, SIP_AUTHOR, scheme, param, SIP_SP));
1191 }
1192
1193 /*
1194 * Authentication-Info = "Authentication-Info" HCOLON ainfo
1195 * *(COMMA ainfo)
1196 * ainfo = nextnonce / message-qop
1197 * / response-auth / cnonce
1198 * / nonce-count
1199 * nextnonce = "nextnonce" EQUAL nonce-value
1200 * response-auth = "rspauth" EQUAL response-digest
1201 * response-digest = LDQUOT *LHEX RDQUOT
1202 */
1203 int
sip_add_authen_info(sip_msg_t sip_msg,char * ainfo)1204 sip_add_authen_info(sip_msg_t sip_msg, char *ainfo)
1205 {
1206 return (sip_add_str_to_msg(sip_msg, SIP_AUTHEN_INFO, ainfo, NULL,
1207 (char)NULL));
1208 }
1209
1210 /*
1211 * Proxy-Authenticate = "Proxy-Authenticate" HCOLON challenge
1212 * challenge = ("Digest" LWS digest-cln *(COMMA digest-cln))
1213 * / other-challenge
1214 * other-challenge = auth-scheme LWS auth-param
1215 * *(COMMA auth-param)
1216 * digest-cln = realm / domain / nonce
1217 * / opaque / stale / algorithm
1218 * / qop-options / auth-param
1219 * realm = "realm" EQUAL realm-value
1220 * realm-value = quoted-string
1221 * domain = "domain" EQUAL LDQUOT URI
1222 * *( 1*SP URI ) RDQUOT
1223 * URI = absoluteURI / abs-path
1224 * nonce = "nonce" EQUAL nonce-value
1225 * nonce-value = quoted-string
1226 * opaque = "opaque" EQUAL quoted-string
1227 * stale = "stale" EQUAL ( "true" / "false" )
1228 * algorithm = "algorithm" EQUAL ( "MD5" / "MD5-sess"
1229 * / token )
1230 * qop-options = "qop" EQUAL LDQUOT qop-value
1231 * *("," qop-value) RDQUOT
1232 * qop-value = "auth" / "auth-int" / token
1233 */
1234 int
sip_add_proxy_authen(sip_msg_t sip_msg,char * pascheme,char * paparam)1235 sip_add_proxy_authen(sip_msg_t sip_msg, char *pascheme, char *paparam)
1236 {
1237 return (sip_add_str_to_msg(sip_msg, SIP_PROXY_AUTHEN, pascheme, paparam,
1238 SIP_SP));
1239 }
1240
1241 /*
1242 * Proxy-Authorization = "Proxy-Authorization" HCOLON credentials
1243 */
1244 int
sip_add_proxy_author(sip_msg_t sip_msg,char * paschem,char * paparam)1245 sip_add_proxy_author(sip_msg_t sip_msg, char *paschem, char *paparam)
1246 {
1247 return (sip_add_str_to_msg(sip_msg, SIP_PROXY_AUTHOR, paschem, paparam,
1248 SIP_SP));
1249 }
1250
1251 /*
1252 * Proxy-Require = "Proxy-Require" HCOLON option-tag
1253 * *(COMMA option-tag)
1254 * option-tag = token
1255 */
1256 int
sip_add_proxy_require(sip_msg_t sip_msg,char * opt)1257 sip_add_proxy_require(sip_msg_t sip_msg, char *opt)
1258 {
1259 return (sip_add_str_to_msg(sip_msg, SIP_PROXY_REQ, opt, NULL,
1260 (char)NULL));
1261 }
1262
1263 /*
1264 * WWW-Authenticate = "WWW-Authenticate" HCOLON challenge
1265 * extension-header = header-name HCOLON header-value
1266 * header-name = token
1267 * header-value = *(TEXT-UTF8char / UTF8-CONT / LWS)
1268 * message-body = *OCTET
1269 */
1270 int
sip_add_www_authen(sip_msg_t sip_msg,char * wascheme,char * waparam)1271 sip_add_www_authen(sip_msg_t sip_msg, char *wascheme, char *waparam)
1272 {
1273 return (sip_add_str_to_msg(sip_msg, SIP_WWW_AUTHEN, wascheme, waparam,
1274 SIP_SP));
1275 }
1276
1277 /*
1278 * Call-ID = ( "Call-ID" / "i" ) HCOLON callid
1279 */
1280 int
sip_add_callid(sip_msg_t sip_msg,char * callid)1281 sip_add_callid(sip_msg_t sip_msg, char *callid)
1282 {
1283 int ret;
1284 boolean_t allocd = B_FALSE;
1285
1286 if (sip_msg == NULL || (callid != NULL && callid[0] == '\0'))
1287 return (EINVAL);
1288 if (callid == NULL) {
1289 callid = (char *)sip_guid();
1290 if (callid == NULL)
1291 return (ENOMEM);
1292 allocd = B_TRUE;
1293 }
1294 ret = sip_add_str_to_msg(sip_msg, SIP_CALL_ID, callid, NULL,
1295 (char)NULL);
1296 if (allocd)
1297 free(callid);
1298 return (ret);
1299 }
1300
1301 /*
1302 * CSeq = "CSeq" HCOLON 1*DIGIT LWS Method
1303 */
1304 int
sip_add_cseq(sip_msg_t sip_msg,sip_method_t method,uint32_t cseq)1305 sip_add_cseq(sip_msg_t sip_msg, sip_method_t method, uint32_t cseq)
1306 {
1307 int r;
1308
1309 if (sip_msg == NULL || (int)cseq < 0 || method == 0 ||
1310 method >= MAX_SIP_METHODS) {
1311 return (EINVAL);
1312 }
1313 r = sip_add_intstr_to_msg(sip_msg, SIP_CSEQ, cseq,
1314 sip_methods[method].name, NULL);
1315 return (r);
1316 }
1317
1318 /*
1319 * Via = ( "Via" / "v" ) HCOLON via-parm *(COMMA via-parm)
1320 * via-parm = sent-protocol LWS sent-by *( SEMI via-params )
1321 * via-params = via-ttl / via-maddr
1322 * / via-received / via-branch
1323 * / via-extension
1324 * via-ttl = "ttl" EQUAL ttl
1325 * via-maddr = "maddr" EQUAL host
1326 * via-received = "received" EQUAL (IPv4address / IPv6address)
1327 * via-branch = "branch" EQUAL token
1328 * via-extension = generic-param
1329 * sent-protocol = protocol-name SLASH protocol-version
1330 * SLASH transport
1331 * protocol-name = "SIP" / token
1332 * protocol-version = token
1333 * transport = "UDP" / "TCP" / "TLS" / "SCTP"
1334 * / other-transport
1335 * sent-by = host [ COLON port ]
1336 * ttl = 1*3DIGIT ; 0 to 255
1337 */
1338 _sip_header_t *
sip_create_via_hdr(char * sent_protocol_transport,char * sent_by_host,int sent_by_port,char * via_params)1339 sip_create_via_hdr(char *sent_protocol_transport, char *sent_by_host,
1340 int sent_by_port, char *via_params)
1341 {
1342 _sip_header_t *new_header;
1343 int header_size;
1344 int count;
1345
1346 header_size = strlen(SIP_VIA) + SIP_SPACE_LEN + sizeof (char) +
1347 SIP_SPACE_LEN + strlen(SIP_VERSION) + sizeof (char) +
1348 strlen(sent_protocol_transport) + SIP_SPACE_LEN +
1349 strlen(sent_by_host) + strlen(SIP_CRLF);
1350
1351 if (sent_by_port > 0) {
1352 header_size += SIP_SPACE_LEN + sizeof (char) + SIP_SPACE_LEN +
1353 sip_num_of_digits(sent_by_port);
1354 }
1355
1356 if (via_params != NULL) {
1357 header_size += SIP_SPACE_LEN + sizeof (char) +
1358 strlen(via_params);
1359 }
1360 new_header = sip_new_header(header_size);
1361 if (new_header->sip_hdr_start == NULL)
1362 return (NULL);
1363 count = snprintf(new_header->sip_hdr_current, header_size + 1,
1364 "%s %c %s/%s %s",
1365 SIP_VIA, SIP_HCOLON, SIP_VERSION, sent_protocol_transport,
1366 sent_by_host);
1367 new_header->sip_hdr_current += count;
1368 header_size -= count;
1369
1370 if (sent_by_port > 0) {
1371 count = snprintf(new_header->sip_hdr_current, header_size + 1,
1372 " %c %d", SIP_HCOLON, sent_by_port);
1373 new_header->sip_hdr_current += count;
1374 header_size -= count;
1375 }
1376
1377 if (via_params != NULL) {
1378 count = snprintf(new_header->sip_hdr_current, header_size + 1,
1379 " %c%s", SIP_SEMI, via_params);
1380 new_header->sip_hdr_current += count;
1381 header_size -= count;
1382 }
1383
1384 (void) snprintf(new_header->sip_hdr_current, header_size + 1,
1385 "%s", SIP_CRLF);
1386 return (new_header);
1387 }
1388
1389 /*
1390 * There can be multiple via headers we always append the header.
1391 * We expect the via params to be a semi-colon separated list of parameters.
1392 * We will add a semi-clone, before adding the list to the header.
1393 */
1394 int
sip_add_via(sip_msg_t sip_msg,char * sent_protocol_transport,char * sent_by_host,int sent_by_port,char * via_params)1395 sip_add_via(sip_msg_t sip_msg, char *sent_protocol_transport,
1396 char *sent_by_host, int sent_by_port, char *via_params)
1397 {
1398 _sip_header_t *new_header;
1399 _sip_msg_t *_sip_msg;
1400
1401 if (sip_msg == NULL || sent_protocol_transport == NULL ||
1402 sent_by_host == NULL || sent_by_port < 0) {
1403 return (EINVAL);
1404 }
1405
1406 _sip_msg = (_sip_msg_t *)sip_msg;
1407 (void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
1408 if (_sip_msg->sip_msg_cannot_be_modified) {
1409 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
1410 return (ENOTSUP);
1411 }
1412
1413 new_header = sip_create_via_hdr(sent_protocol_transport, sent_by_host,
1414 sent_by_port, via_params);
1415 if (new_header == NULL) {
1416 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
1417 return (ENOMEM);
1418 }
1419 _sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, NULL);
1420 if (_sip_msg->sip_msg_buf != NULL)
1421 _sip_msg->sip_msg_modified = B_TRUE;
1422 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
1423 return (0);
1424 }
1425
1426 /*
1427 * Max-Forwards = "Max-Forwards" HCOLON 1*DIGIT
1428 */
1429 int
sip_add_maxforward(sip_msg_t sip_msg,uint_t maxforward)1430 sip_add_maxforward(sip_msg_t sip_msg, uint_t maxforward)
1431 {
1432 if (sip_msg == NULL || (int)maxforward < 0)
1433 return (EINVAL);
1434 return (sip_add_int_to_msg(sip_msg, SIP_MAX_FORWARDS, maxforward,
1435 NULL));
1436 }
1437
1438 /*
1439 * Content-Type = ( "Content-Type" / "c" ) HCOLON media-type
1440 * media-type = m-type SLASH m-subtype *(SEMI m-parameter)
1441 * m-type = discrete-type / composite-type
1442 * discrete-type = "text" / "image" / "audio" / "video"
1443 * / "application" / extension-token
1444 * composite-type = "message" / "multipart" / extension-token
1445 * extension-token = ietf-token / x-token
1446 * ietf-token = token
1447 * x-token = "x-" token
1448 * m-subtype = extension-token / iana-token
1449 * iana-token = token
1450 * m-parameter = m-attribute EQUAL m-value
1451 * m-attribute = token
1452 * m-value = token / quoted-string
1453 */
1454 int
sip_add_content_type(sip_msg_t sip_msg,char * type,char * subtype)1455 sip_add_content_type(sip_msg_t sip_msg, char *type, char *subtype)
1456 {
1457 if (sip_msg == NULL || type == NULL || subtype == NULL)
1458 return (EINVAL);
1459 return (sip_add_2strs_to_msg(sip_msg, SIP_CONTENT_TYPE, type, B_FALSE,
1460 subtype, NULL, SIP_SLASH));
1461 }
1462
1463 /*
1464 * Content-Length = ( "Content-Length" / "l" ) HCOLON 1*DIGIT
1465 */
1466 int
sip_add_content_length(_sip_msg_t * _sip_msg,int length)1467 sip_add_content_length(_sip_msg_t *_sip_msg, int length)
1468 {
1469 _sip_header_t *new_header;
1470 int header_size;
1471
1472 if (_sip_msg == NULL || length < 0)
1473 return (EINVAL);
1474 (void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
1475 if (_sip_msg->sip_msg_cannot_be_modified) {
1476 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
1477 return (ENOTSUP);
1478 }
1479
1480 header_size = strlen(SIP_CONTENT_LENGTH) + SIP_SPACE_LEN +
1481 sizeof (char) + SIP_SPACE_LEN + sip_num_of_digits(length) +
1482 strlen(SIP_CRLF) + strlen(SIP_CRLF);
1483
1484 new_header = sip_new_header(header_size);
1485 if (new_header == NULL) {
1486 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
1487 return (ENOMEM);
1488 }
1489 (void) snprintf(new_header->sip_hdr_start, header_size + 1,
1490 "%s %c %u%s%s", SIP_CONTENT_LENGTH, SIP_HCOLON, length,
1491 SIP_CRLF, SIP_CRLF);
1492
1493 _sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, NULL);
1494 if (_sip_msg->sip_msg_buf != NULL)
1495 _sip_msg->sip_msg_modified = B_TRUE;
1496 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
1497 return (0);
1498 }
1499
1500
1501 /*
1502 * Contact = ("Contact" / "m" ) HCOLON
1503 * ( STAR / (contact-param *(COMMA contact-param)))
1504 * contact-param = (name-addr / addr-spec) *(SEMI contact-params)
1505 * name-addr = [ display-name ] LAQUOT addr-spec RAQUOT
1506 * addr-spec = SIP-URI / SIPS-URI / absoluteURI
1507 * display-name = *(token LWS)/ quoted-string
1508 * contact-params = c-p-q / c-p-expires
1509 * / contact-extension
1510 */
1511 int
sip_add_contact(sip_msg_t sip_msg,char * display_name,char * contact_uri,boolean_t add_aquot,char * contact_params)1512 sip_add_contact(sip_msg_t sip_msg, char *display_name, char *contact_uri,
1513 boolean_t add_aquot, char *contact_params)
1514 {
1515 return (sip_add_name_aspec(sip_msg, display_name, contact_uri, NULL,
1516 add_aquot, SIP_CONTACT, contact_params));
1517 }
1518
1519 /*
1520 * From = ( "From" / "f" ) HCOLON from-spec
1521 * from-spec = ( name-addr / addr-spec )
1522 * *( SEMI from-param )
1523 * from-param = tag-param / generic-param
1524 * tag-param = "tag" EQUAL token
1525 *
1526 * Since there can be more than one tags, fromtags is a semi colon separated
1527 * list of tags.
1528 */
1529 int
sip_add_from(sip_msg_t sip_msg,char * display_name,char * from_uri,char * fromtags,boolean_t add_aquot,char * from_params)1530 sip_add_from(sip_msg_t sip_msg, char *display_name, char *from_uri,
1531 char *fromtags, boolean_t add_aquot, char *from_params)
1532 {
1533 return (sip_add_name_aspec(sip_msg, display_name, from_uri, fromtags,
1534 add_aquot, SIP_FROM, from_params));
1535 }
1536
1537 /*
1538 * To = ( "To" / "t" ) HCOLON ( name-addr
1539 * / addr-spec ) *( SEMI to-param )
1540 * to-param = tag-param / generic-param
1541 */
1542 int
sip_add_to(sip_msg_t sip_msg,char * display_name,char * to_uri,char * totags,boolean_t add_aquot,char * to_params)1543 sip_add_to(sip_msg_t sip_msg, char *display_name, char *to_uri,
1544 char *totags, boolean_t add_aquot, char *to_params)
1545 {
1546 return (sip_add_name_aspec(sip_msg, display_name, to_uri, totags,
1547 add_aquot, SIP_TO, to_params));
1548 }
1549
1550 /*
1551 * Route = "Route" HCOLON route-param *(COMMA route-param)
1552 * route-param = name-addr *( SEMI rr-param )
1553 */
1554 int
sip_add_route(sip_msg_t sip_msg,char * display_name,char * uri,char * route_params)1555 sip_add_route(sip_msg_t sip_msg, char *display_name, char *uri,
1556 char *route_params)
1557 {
1558 return (sip_add_name_aspec(sip_msg, display_name, uri, NULL, B_TRUE,
1559 SIP_ROUTE, route_params));
1560 }
1561
1562 /*
1563 * Record-Route = "Record-Route" HCOLON rec-route *(COMMA rec-route)
1564 * rec-route = name-addr *( SEMI rr-param )
1565 * rr-param = generic-param
1566 */
1567 int
sip_add_record_route(sip_msg_t sip_msg,char * display_name,char * uri,char * route_params)1568 sip_add_record_route(sip_msg_t sip_msg, char *display_name, char *uri,
1569 char *route_params)
1570 {
1571 return (sip_add_name_aspec(sip_msg, display_name, uri, NULL, B_TRUE,
1572 SIP_RECORD_ROUTE, route_params));
1573 }
1574
1575
1576 /*
1577 * PAssertedID = "P-Asserted-Identity" HCOLON PAssertedID-value
1578 * *(COMMA PAssertedID-value)
1579 * PAssertedID-value = name-addr / addr-spec
1580 */
1581 int
sip_add_passertedid(sip_msg_t sip_msg,char * display_name,char * addr,boolean_t add_aquot)1582 sip_add_passertedid(sip_msg_t sip_msg, char *display_name, char *addr,
1583 boolean_t add_aquot)
1584 {
1585 return (sip_add_name_aspec(sip_msg, display_name, addr, NULL, add_aquot,
1586 SIP_PASSERTEDID, NULL));
1587 }
1588
1589 /*
1590 * PPreferredID = "P-Preferred-Identity" HCOLON PPreferredID-value
1591 * *(COMMA PPreferredID-value)
1592 * PPreferredID-value = name-addr / addr-spec
1593 */
1594 int
sip_add_ppreferredid(sip_msg_t sip_msg,char * display_name,char * addr,boolean_t add_aquot)1595 sip_add_ppreferredid(sip_msg_t sip_msg, char *display_name, char *addr,
1596 boolean_t add_aquot)
1597 {
1598 return (sip_add_name_aspec(sip_msg, display_name, addr, NULL, add_aquot,
1599 SIP_PPREFERREDID, NULL));
1600 }
1601