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