1 /*
2 	belle-sip - SIP (RFC3261) library.
3     Copyright (C) 2010  Belledonne Communications SARL
4 
5     This program is free software: you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation, either version 2 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 
20 #define _CRT_RAND_S
21 #include <stddef.h>
22 #include <stdlib.h>
23 #include <sys/stat.h>
24 #include "belle_sip_internal.h"
25 #include "bctoolbox/parser.h"
26 
27 #include "clock_gettime.h" /*for apple*/
28 
29 #ifndef _WIN32
30 #include <unistd.h>
31 #include <sys/time.h> /*for gettimeofday*/
32 #include <dirent.h> /* available on POSIX system only */
33 #else
34 #include <direct.h>
35 #endif
36 
belle_sip_snprintf(char * buff,size_t buff_size,size_t * offset,const char * fmt,...)37 belle_sip_error_code belle_sip_snprintf(char *buff, size_t buff_size, size_t *offset, const char *fmt, ...) {
38 	belle_sip_error_code ret;
39 	va_list args;
40 	va_start(args, fmt);
41 	ret = belle_sip_snprintf_valist(buff, buff_size, offset, fmt, args);
42 	va_end(args);
43 
44 	return ret;
45 }
46 
belle_sip_snprintf_valist(char * buff,size_t buff_size,size_t * offset,const char * fmt,va_list args)47 belle_sip_error_code belle_sip_snprintf_valist(char *buff, size_t buff_size, size_t *offset, const char *fmt, va_list args) {
48 	int ret;
49 	belle_sip_error_code error = BELLE_SIP_OK;
50 	ret = vsnprintf(buff + *offset, buff_size - *offset, fmt, args);
51 	if ((ret < 0)
52 		|| (ret >= (int)(buff_size - *offset))) {
53 			error = BELLE_SIP_BUFFER_OVERFLOW;
54 		*offset = buff_size;
55 	} else {
56 		*offset += ret;
57 	}
58 	return error;
59 }
60 
61 #if defined(_WIN32) || defined(_WIN32_WCE)
62 #define ENDLINE "\r\n"
63 #else
64 #define ENDLINE "\n"
65 #endif
66 
67 #ifdef _WIN32
belle_sip_gettimeofday(struct timeval * tv,void * tz)68 static int belle_sip_gettimeofday (struct timeval *tv, void* tz)
69 {
70 	union
71 	{
72 		__int64 ns100; /*time since 1 Jan 1601 in 100ns units */
73 		FILETIME fileTime;
74 	} now;
75 
76 	GetSystemTimeAsFileTime (&now.fileTime);
77 	tv->tv_usec = (long) ((now.ns100 / 10LL) % 1000000LL);
78 	tv->tv_sec = (long) ((now.ns100 - 116444736000000000LL) / 10000000LL);
79 	return 0;
80 }
81 #else
82 #define belle_sip_gettimeofday gettimeofday
83 #endif
84 
85 
86 
87 #ifndef _WIN32
88 
find_best_clock_id(void)89 static int find_best_clock_id (void) {
90 #if 0
91 	struct timespec ts;
92 	static int clock_id=-1;
93 #ifndef __ANDROID__
94 #define DEFAULT_CLOCK_MODE CLOCK_MONOTONIC
95 #else
96 #define DEFAULT_CLOCK_MODE CLOCK_REALTIME /*monotonic clock stop during sleep mode*/
97 #endif
98 	if (clock_id==-1) {
99 		if (clock_gettime(DEFAULT_CLOCK_MODE,&ts)!=1){
100 			clock_id=DEFAULT_CLOCK_MODE;
101 		} else if (clock_gettime(CLOCK_REALTIME,&ts)!=1){
102 			clock_id=CLOCK_REALTIME;
103 		} else {
104 			belle_sip_fatal("Cannot find suitable clock mode");
105 		}
106 	}
107 	return clock_id;
108 #else
109 	/* Tt seems that both Linux, iOS, and MacOS stop incrementing the CLOCK_MONOTONIC during sleep time.
110 	 * This is a real problem, because all refreshable requests (SUBSCRIBE, REGISTER, PUBLISH) won't be sent on time due to
111 	 * system going to sleep. Let's take an example: a REGISTER is sent at T0 with expire 3600, then the macbook suspends at T0+60s.
112 	 * When the macbook resumes at T0+8000, nothing happens. The REGISTER refresh will be sent at T0+8000+3600-60.
113 	 * The only reason for seeing the register is if the network address has changed, in which case it will trigger a shutdown of all sockets.
114 	 * As a result, we fallback to CLOCK_REALTIME until the OS correctly implement CLOCK_MONOTONIC according to POSIX specifications
115 	 */
116 #ifdef __APPLE__
117 	#ifdef CLOCK_REALTIME
118 		#undef CLOCK_REALTIME
119 	#endif
120 	#define CLOCK_REALTIME BC_CLOCK_REALTIME
121 #endif
122 	return CLOCK_REALTIME;
123 #endif
124 }
belle_sip_time_ms(void)125 uint64_t belle_sip_time_ms(void){
126 #ifdef __APPLE__
127 #define clock_gettime bc_clock_gettime
128 #endif
129 
130 	struct timespec ts;
131 	if (clock_gettime(find_best_clock_id(),&ts)==-1){
132 		belle_sip_error("clock_gettime() error for clock_id=%i: %s",find_best_clock_id(),strerror(errno));
133 		return 0;
134 	}
135 	return (ts.tv_sec*1000LL) + (ts.tv_nsec/1000000LL);
136 }
137 #else
belle_sip_time_ms(void)138 uint64_t belle_sip_time_ms(void){
139 #ifdef BELLE_SIP_WINDOWS_DESKTOP
140 	return GetTickCount();
141 #else
142 	return GetTickCount64();
143 #endif
144 }
145 #endif
146 
147 /**
148  * parser parameter pair
149  */
150 
151 
152 
belle_sip_param_pair_new(const char * name,const char * value)153 belle_sip_param_pair_t* belle_sip_param_pair_new(const char* name,const char* value) {
154 	belle_sip_param_pair_t* lPair = (belle_sip_param_pair_t*)belle_sip_new0(belle_sip_param_pair_t);
155 	lPair->name=name?belle_sip_strdup(name):NULL;
156 	lPair->value=value?belle_sip_strdup(value):NULL;
157 	return lPair;
158 }
159 
belle_sip_param_pair_destroy(belle_sip_param_pair_t * pair)160 void belle_sip_param_pair_destroy(belle_sip_param_pair_t*  pair) {
161 	if (pair->name) belle_sip_free(pair->name);
162 	if (pair->value) belle_sip_free(pair->value);
163 	belle_sip_free(pair);
164 }
165 
belle_sip_param_pair_comp_func(const belle_sip_param_pair_t * a,const char * b)166 int belle_sip_param_pair_comp_func(const belle_sip_param_pair_t *a, const char*b) {
167 	return strcmp(a->name,b);
168 }
belle_sip_param_pair_case_comp_func(const belle_sip_param_pair_t * a,const char * b)169 int belle_sip_param_pair_case_comp_func(const belle_sip_param_pair_t *a, const char*b) {
170 	return strcasecmp(a->name,b);
171 }
172 
_belle_sip_str_dup_and_unquote_string(const char * quoted_string)173 char* _belle_sip_str_dup_and_unquote_string(const char* quoted_string) {
174 	size_t value_size = strlen(quoted_string);
175 	char* unquoted_string = belle_sip_malloc0(value_size-2+1);
176 	strncpy(unquoted_string,quoted_string+1,value_size-2);
177 	return unquoted_string;
178 }
179 
180 
belle_sip_unquote_strdup(const char * str)181 char *belle_sip_unquote_strdup(const char *str){
182 	const char *p;
183 	if (str==NULL) return NULL;
184 
185 	for(p=str;*p!='\0';++p){
186 		switch(*p){
187 			case ' ':
188 			case '\t':
189 			break;
190 			case '"':
191 				return _belle_sip_str_dup_and_unquote_string(p);
192 			default:
193 				return belle_sip_strdup(str);
194 			break;
195 		}
196 	}
197 	return belle_sip_strdup(str);
198 }
199 
200 #if defined(_WIN32) && !defined(_MSC_VER)
201 #include <wincrypt.h>
belle_sip_wincrypto_random(unsigned int * rand_number)202 static int belle_sip_wincrypto_random(unsigned int *rand_number){
203 	static HCRYPTPROV hProv=(HCRYPTPROV)-1;
204 	static int initd=0;
205 
206 	if (!initd){
207 		if (!CryptAcquireContext(&hProv,NULL,NULL,PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)){
208 			belle_sip_error("Could not acquire a windows crypto context");
209 			return -1;
210 		}
211 		initd=TRUE;
212 	}
213 	if (hProv==(HCRYPTPROV)-1)
214 		return -1;
215 
216 	if (!CryptGenRandom(hProv,4,(BYTE*)rand_number)){
217 		belle_sip_error("CryptGenRandom() failed.");
218 		return -1;
219 	}
220 	return 0;
221 }
222 #endif
223 
belle_sip_random(void)224 unsigned int belle_sip_random(void){
225 #if  defined(__linux) || defined(__APPLE__)
226 	static int fd=-1;
227 	if (fd==-1) fd=open("/dev/urandom",O_RDONLY);
228 	if (fd!=-1){
229 		unsigned int tmp;
230 		if (read(fd,&tmp,4)!=4){
231 			belle_sip_error("Reading /dev/urandom failed.");
232 		}else return tmp;
233 	}else belle_sip_error("Could not open /dev/urandom");
234 #elif defined(_WIN32)
235 	static int initd=0;
236 	unsigned int ret;
237 #ifdef _MSC_VER
238 	/*rand_s() is pretty nice and simple function but is not wrapped by mingw.*/
239 
240 	if (rand_s(&ret)==0){
241 		return ret;
242 	}
243 #else
244 	if (belle_sip_wincrypto_random(&ret)==0){
245 		return ret;
246 	}
247 #endif
248 	/* Windows's rand() is unsecure but is used as a fallback*/
249 	if (!initd) {
250 		srand((unsigned int)belle_sip_time_ms());
251 		initd=1;
252 		belle_sip_warning("Random generator is using rand(), this is unsecure !");
253 	}
254 	return rand()<<16 | rand();
255 #endif
256 	/*fallback to UNIX random()*/
257 #ifndef _WIN32
258 	return (unsigned int) random();
259 #endif
260 }
261 
262 
belle_sip_set_socket_api(bctbx_vsocket_api_t * my_api)263 void belle_sip_set_socket_api(bctbx_vsocket_api_t* my_api){
264 
265 	bctbx_vsocket_api_set_default(my_api);
266 }
267 
268 static const char *symbols="aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789-~";
269 
270 /**
271  * Write a random text token of supplied size.
272 **/
belle_sip_random_token(char * ret,size_t size)273 char * belle_sip_random_token(char *ret, size_t size){
274 	unsigned int val=0;
275 	unsigned int i;
276 
277 	for(i=0;i<size-1;++i){
278 		if (i%5==0) val=belle_sip_random();
279 		ret[i]=symbols[val & 63];
280 		val=val>>6;
281 	}
282 	ret[i]=0;
283 	return ret;
284 }
285 
286 /**
287  * Write random bytes of supplied size.
288 **/
belle_sip_random_bytes(unsigned char * ret,size_t size)289 unsigned char * belle_sip_random_bytes(unsigned char *ret, size_t size){
290 	unsigned int val=0;
291 	unsigned int i;
292 	for(i=0;i<size;++i){
293 		if (i%4==0) val=belle_sip_random();
294 		ret[i]=val & 0xff;
295 		val=val>>8;
296 	}
297 	return ret;
298 }
299 
300 typedef struct bits_reader{
301 	const uint8_t *buffer;
302 	size_t buf_size;
303 	int bit_index;
304 }bits_reader_t;
305 
bits_reader_init(bits_reader_t * reader,const uint8_t * buffer,size_t bufsize)306 static void bits_reader_init(bits_reader_t *reader, const uint8_t *buffer, size_t bufsize){
307 	reader->buffer=buffer;
308 	reader->buf_size=bufsize;
309 	reader->bit_index=0;
310 }
311 
bits_reader_read(bits_reader_t * reader,int count,unsigned int * ret)312 static int bits_reader_read(bits_reader_t *reader, int count, unsigned int *ret){
313 	unsigned int tmp;
314 	size_t byte_index=reader->bit_index/8;
315 	size_t bit_index=reader->bit_index % 8;
316 	int shift=32-(int)bit_index-count;
317 
318 	if (count>=24){
319 		belle_sip_error("This bit reader cannot read more than 24 bits at once.");
320 		return -1;
321 	}
322 
323 	if (byte_index<reader->buf_size)
324 		tmp=((unsigned int)reader->buffer[byte_index++])<<24;
325 	else{
326 		belle_sip_error("Bit reader goes end of stream.");
327 		return -1;
328 	}
329 	if (byte_index<reader->buf_size)
330 		tmp|=((unsigned int)reader->buffer[byte_index++])<<16;
331 	if (byte_index<reader->buf_size)
332 		tmp|=((unsigned int)reader->buffer[byte_index++])<<8;
333 	if (byte_index<reader->buf_size)
334 		tmp|=((unsigned int)reader->buffer[byte_index++]);
335 
336 	tmp=tmp>>shift;
337 	tmp=tmp & ((1<<count)-1);
338 	reader->bit_index+=count;
339 	*ret=tmp;
340 	return 0;
341 }
342 
belle_sip_octets_to_text(const uint8_t * hash,size_t hash_len,char * ret,size_t size)343 char * belle_sip_octets_to_text(const uint8_t *hash, size_t hash_len, char *ret, size_t size){
344 	int i;
345 	bits_reader_t bitctx;
346 
347 	bits_reader_init(&bitctx,hash,hash_len);
348 
349 	for(i=0;i<(int)size-1;++i){
350 		unsigned int val=0;
351 		if (bits_reader_read(&bitctx,6,&val)==0){
352 			ret[i]=symbols[val];
353 		}else break;
354 	}
355 	ret[i]=0;
356 	return ret;
357 }
358 
belle_sip_util_copy_headers(belle_sip_message_t * orig,belle_sip_message_t * dest,const char * header,int multiple)359 void belle_sip_util_copy_headers(belle_sip_message_t *orig, belle_sip_message_t *dest, const char*header, int multiple){
360 	const belle_sip_list_t *elem;
361 	elem=belle_sip_message_get_headers(orig,header);
362 	for (;elem!=NULL;elem=elem->next){
363 		belle_sip_header_t *ref_header=(belle_sip_header_t*)elem->data;
364 		if (ref_header){
365 			ref_header=(belle_sip_header_t*)belle_sip_object_clone((belle_sip_object_t*)ref_header);
366 			if (!multiple){
367 				belle_sip_message_set_header(dest,ref_header);
368 				break;
369 			}else
370 				belle_sip_message_add_header(dest,ref_header);
371 		}
372 	}
373 }
374 
375 
belle_sip_to_unescaped_string(const char * buff)376 char* belle_sip_to_unescaped_string(const char* buff) {
377 	return bctbx_unescaped_string(buff);
378 }
379 
belle_sip_get_char(const char * a,char * b)380 size_t belle_sip_get_char(const char* a, char *b) {
381 	return bctbx_get_char(a,b);
382 }
383 /*
384 static void print_noescapes_map(char noescapes[BELLE_SIP_NO_ESCAPES_SIZE], const char *name) {
385 	unsigned int i;
386 	printf("Noescapes %s :", name);
387 	for (i=' '; i <= '~'; ++i) {
388 		if (noescapes[i] == 1) printf ("%c", i);
389 		//if (noescapes[i] == 1) printf ("%c %d - %d\n", i, (char)i, noescapes[i]);
390 	}
391 	printf ("init: %d\n", noescapes[BELLE_SIP_NO_ESCAPES_SIZE-1]);
392 }
393 */
394 
get_sip_uri_username_noescapes(void)395 static const bctbx_noescape_rules_t* get_sip_uri_username_noescapes(void) {
396 	static bctbx_noescape_rules_t noescapes = {0};
397 	if (noescapes[BCTBX_NOESCAPE_RULES_USER_INDEX] == 0) {
398 		// concurrent initialization should not be an issue
399 		/*user             =  1*( unreserved / escaped / user-unreserved )
400 		 unreserved  =  alphanum / mark
401 		 mark        =  "-" / "_" / "." / "!" / "~" / "*" / "'"
402 		 / "(" / ")"
403 		user-unreserved  =  "&" / "=" / "+" / "$" / "," / ";" / "?" / "/"
404 		*/
405 		bctbx_noescape_rules_add_alfanums(noescapes);
406 		/*mark*/
407 		bctbx_noescape_rules_add_list(noescapes, "-_.!~*'()");
408 		/*user-unreserved*/
409 		bctbx_noescape_rules_add_list(noescapes, "&=+$,;?/");
410 
411 		noescapes[BCTBX_NOESCAPE_RULES_USER_INDEX] = 1; // initialized
412 //		print_noescapes_map(noescapes, "uri_username");
413 	}
414 	return (const bctbx_noescape_rules_t*)&noescapes;/*gcc asks for a cast, clang not*/
415 }
416 /*
417  *
418  * password         =  *( unreserved / escaped /
419                     "&" / "=" / "+" / "$" / "," )
420  * */
get_sip_uri_userpasswd_noescapes(void)421 static const bctbx_noescape_rules_t* get_sip_uri_userpasswd_noescapes(void) {
422 	static bctbx_noescape_rules_t noescapes = {0};
423 	if (noescapes[BCTBX_NOESCAPE_RULES_USER_INDEX] == 0) {
424 		// unreserved
425 		bctbx_noescape_rules_add_alfanums(noescapes);
426 		bctbx_noescape_rules_add_list(noescapes, "-_.!~*'()");
427 		bctbx_noescape_rules_add_list(noescapes, "&=+$,");
428 
429 		noescapes[BCTBX_NOESCAPE_RULES_USER_INDEX] = 1; // initialized
430 
431 	}
432 	return (const bctbx_noescape_rules_t*)&noescapes;/*gcc asks for a cast, clang not*/
433 }
434 
get_sip_uri_parameter_noescapes(void)435 static  const bctbx_noescape_rules_t* get_sip_uri_parameter_noescapes(void) {
436 	static bctbx_noescape_rules_t  noescapes= {0};
437 	if (noescapes[BCTBX_NOESCAPE_RULES_USER_INDEX] == 0) {
438 		/*
439 		 other-param       =  pname [ "=" pvalue ]
440 		 pname             =  1*paramchar
441 		 pvalue            =  1*paramchar
442 		 paramchar         =  param-unreserved / unreserved / escaped
443 		 param-unreserved  =  "[" / "]" / "/" / ":" / "&" / "+" / "$"
444 		 unreserved  =  alphanum / mark
445 		 mark        =  "-" / "_" / "." / "!" / "~" / "*" / "'"
446 		 / "(" / ")"
447 		 escaped     =  "%" HEXDIG HEXDIG
448 		 token       =  1*(alphanum / "-" / "." / "!" / "%" / "*"
449 		 / "_" / "+" / "`" / "'" / "~" )
450 		 */
451 		//param-unreserved  =
452 
453 		bctbx_noescape_rules_add_list(noescapes,"[]/:&+$");
454 
455 		// token
456 		bctbx_noescape_rules_add_alfanums(noescapes);
457 		bctbx_noescape_rules_add_list(noescapes, "-.!%*_+`'~");
458 
459 		// unreserved
460 		bctbx_noescape_rules_add_list(noescapes, "-_.!~*'()");
461 
462 		noescapes[BCTBX_NOESCAPE_RULES_USER_INDEX] = 1; // initialized
463 //		print_noescapes_map(noescapes, "uri_parameter");
464 	}
465 	return (const bctbx_noescape_rules_t*)&noescapes;/*gcc asks for a cast, clang not*/
466 }
get_sip_uri_header_noescapes(void)467 static const bctbx_noescape_rules_t* get_sip_uri_header_noescapes(void) {
468 	static bctbx_noescape_rules_t  noescapes= {0};
469 	if (noescapes[BCTBX_NOESCAPE_RULES_USER_INDEX] == 0) {
470 		/*
471 		 unreserved  =  alphanum / mark
472 		 mark        =  "-" / "_" / "." / "!" / "~" / "*" / "'"
473 		 / "(" / ")"
474 		 escaped     =  "%" HEXDIG HEXDIG
475 
476 		 //....
477 		header          =  hname "=" hvalue
478 		hname           =  1*( hnv-unreserved / unreserved / escaped )
479 		hvalue          =  *( hnv-unreserved / unreserved / escaped )
480 		hnv-unreserved  =  "[" / "]" / "/" / "?" / ":" / "+" / "$"
481 
482 		 */
483 
484 		// unreserved
485 		//alphanum
486 		bctbx_noescape_rules_add_alfanums(noescapes);
487 		//mark
488 		bctbx_noescape_rules_add_list(noescapes, "-_.!~*'()");
489 
490 		bctbx_noescape_rules_add_list(noescapes, "[]/?:+$");
491 		//hnv-unreserved
492 		noescapes[BCTBX_NOESCAPE_RULES_USER_INDEX] = 1; // initialized
493 //		print_noescapes_map(noescapes, "uri_parameter");
494 	}
495 	return (const bctbx_noescape_rules_t*)&noescapes;/*gcc asks for a cast, clang not*/
496 }
497 
498 
belle_sip_uri_to_escaped_username(const char * buff)499 char* belle_sip_uri_to_escaped_username(const char* buff) {
500 	return bctbx_escape(buff, *get_sip_uri_username_noescapes());
501 }
belle_sip_uri_to_escaped_userpasswd(const char * buff)502 char* belle_sip_uri_to_escaped_userpasswd(const char* buff) {
503 	return bctbx_escape(buff, *get_sip_uri_userpasswd_noescapes());
504 }
belle_sip_uri_to_escaped_parameter(const char * buff)505 char* belle_sip_uri_to_escaped_parameter(const char* buff) {
506 	return bctbx_escape(buff, *get_sip_uri_parameter_noescapes());
507 }
belle_sip_uri_to_escaped_header(const char * buff)508 char* belle_sip_uri_to_escaped_header(const char* buff) {
509 	return bctbx_escape(buff, *get_sip_uri_header_noescapes());
510 }
511 
512 
513 /*uri (I.E RFC 2396)*/
get_generic_uri_query_noescapes(void)514 static const bctbx_noescape_rules_t *get_generic_uri_query_noescapes(void) {
515 	static bctbx_noescape_rules_t  noescapes= {0};
516 	if (noescapes[BCTBX_NOESCAPE_RULES_USER_INDEX] == 0) {
517 		/*
518 	    uric          = reserved | unreserved | escaped
519 		reserved      = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
520 		                "$" | ","
521 		unreserved    = alphanum | mark
522 		mark          = "-" | "_" | "." | "!" | "~" | "*" | "'" |
523 		                      "(" | ")"
524 
525 		3.4. Query Component
526       	  query         = *uric
527    	   Within a query component, the characters ";", "/", "?", ":", "@",
528    	   "&", "=", "+", ",", and "$" are reserved.
529 
530 		*/
531 		/*unreserved*/
532 		bctbx_noescape_rules_add_alfanums(noescapes);
533 		/*mark*/
534 		bctbx_noescape_rules_add_list(noescapes, "-_.!~*'()");
535 		bctbx_noescape_rules_add_list(noescapes, "=&"); // otherwise how to pass parameters?
536 		noescapes[BCTBX_NOESCAPE_RULES_USER_INDEX] = 1; // initialized
537 	}
538 	return (const bctbx_noescape_rules_t*)&noescapes;/*gcc asks for a cast, clang not*/
539 }
540 
get_generic_uri_path_noescapes(void)541 static const bctbx_noescape_rules_t *get_generic_uri_path_noescapes(void) {
542 	static bctbx_noescape_rules_t  noescapes= {0};
543 	if (noescapes[BCTBX_NOESCAPE_RULES_USER_INDEX] == 0) {
544 		/*
545 	    3.3. Path Component
546 
547    The path component contains data, specific to the authority (or the
548    scheme if there is no authority component), identifying the resource
549    within the scope of that scheme and authority.
550 
551       path          = [ abs_path | opaque_part ]
552 
553       path_segments = segment *( "/" segment )
554       segment       = *pchar *( ";" param )
555       param         = *pchar
556 
557       pchar         = unreserved | escaped |
558                       ":" | "@" | "&" | "=" | "+" | "$" | ","
559 
560    The path may consist of a sequence of path segments separated by a
561    single slash "/" character.  Within a path segment, the characters
562    "/", ";", "=", and "?" are reserved.  Each path segment may include a
563    sequence of parameters, indicated by the semicolon ";" character.
564    The parameters are not significant to the parsing of relative
565    references.
566 
567 		*/
568 		/*unreserved*/
569 		bctbx_noescape_rules_add_alfanums(noescapes);
570 		/*mark*/
571 		bctbx_noescape_rules_add_list(noescapes, "-_.!~*'()");
572 		/*pchar*/
573 		bctbx_noescape_rules_add_list(noescapes, ":@&=+$,");
574 		/*;*/
575 		bctbx_noescape_rules_add_list(noescapes, ";");
576 		bctbx_noescape_rules_add_list(noescapes, "/");
577 
578 		noescapes[BCTBX_NOESCAPE_RULES_USER_INDEX] = 1; // initialized
579 	}
580 	return (const bctbx_noescape_rules_t*)&noescapes;/*gcc asks for a cast, clang not*/
581 }
582 
belle_generic_uri_to_escaped_query(const char * buff)583 char* belle_generic_uri_to_escaped_query(const char* buff) {
584 	return bctbx_escape(buff, *get_generic_uri_query_noescapes());
585 }
belle_generic_uri_to_escaped_path(const char * buff)586 char* belle_generic_uri_to_escaped_path(const char* buff) {
587 	return bctbx_escape(buff, *get_generic_uri_path_noescapes());
588 }
589 
belle_sip_string_to_backslash_less_unescaped_string(const char * buff)590 char* belle_sip_string_to_backslash_less_unescaped_string(const char* buff) {
591 	char *output_buff=belle_sip_malloc(strlen(buff)+1);
592 	unsigned int i;
593 	unsigned int out_buff_index=0;
594 
595 	for(i=0; buff[i] != '\0'; i++) {
596 		if (buff[i] == '\\') {
597 			i++;/*skip \*/
598 		}
599 		/*make sure to only remove one \ in case of \\*/
600 		output_buff[out_buff_index++]=buff[i];
601 	}
602 	output_buff[out_buff_index]='\0';
603 	return output_buff;
604 }
belle_sip_display_name_to_backslashed_escaped_string(const char * buff)605 char* belle_sip_display_name_to_backslashed_escaped_string(const char* buff) {
606 	char output_buff[BELLE_SIP_MAX_TO_STRING_SIZE];
607 	unsigned int i;
608 	unsigned int out_buff_index=0;
609 	for(i=0; buff[i] != '\0' && out_buff_index < sizeof(output_buff)-2; i++) {
610 		/*-3 to make sure last param can be stored in escaped form*/
611 		const char c = buff[i];
612 		if (c == '\"' || c == '\\') {
613 			output_buff[out_buff_index++]='\\'; /*insert escape character*/
614 		}
615 		output_buff[out_buff_index++]=c;
616 	}
617 	output_buff[out_buff_index]='\0';
618 	return belle_sip_strdup(output_buff);
619 }
620 
belle_sip_parse_directory(const char * path,const char * file_type)621 belle_sip_list_t *belle_sip_parse_directory(const char *path, const char *file_type) {
622 	belle_sip_list_t* file_list = NULL;
623 #ifdef _WIN32
624 	WIN32_FIND_DATA FileData;
625 	HANDLE hSearch;
626 	BOOL fFinished = FALSE;
627 	char szDirPath[1024];
628 #ifdef UNICODE
629 	wchar_t wszDirPath[1024];
630 #endif
631 
632 	if (file_type == NULL) {
633 		file_type = ".*";
634 	}
635 	snprintf(szDirPath, sizeof(szDirPath), "%s\\*%s", path, file_type);
636 #ifdef UNICODE
637 	mbstowcs(wszDirPath, szDirPath, sizeof(wszDirPath));
638 	hSearch = FindFirstFileExW(wszDirPath, FindExInfoStandard, &FileData, FindExSearchNameMatch, NULL, 0);
639 #else
640 	hSearch = FindFirstFileExA(szDirPath, FindExInfoStandard, &FileData, FindExSearchNameMatch, NULL, 0);
641 #endif
642 	if (hSearch == INVALID_HANDLE_VALUE) {
643 		belle_sip_message("No file (*%s) found in [%s] [%d].", file_type, szDirPath, (int)GetLastError());
644 		return NULL;
645 	}
646 	snprintf(szDirPath, sizeof(szDirPath), "%s", path);
647 	while (!fFinished) {
648 		char szFilePath[1024];
649 #ifdef UNICODE
650 		char filename[512];
651 		wcstombs(filename, FileData.cFileName, sizeof(filename));
652 		snprintf(szFilePath, sizeof(szFilePath), "%s\\%s", szDirPath, filename);
653 #else
654 		snprintf(szFilePath, sizeof(szFilePath), "%s\\%s", szDirPath, FileData.cFileName);
655 #endif
656 		file_list = belle_sip_list_append(file_list, belle_sip_strdup(szFilePath));
657 		if (!FindNextFile(hSearch, &FileData)) {
658 			if (GetLastError() == ERROR_NO_MORE_FILES) {
659 				fFinished = TRUE;
660 			}
661 			else {
662 				belle_sip_error("Couldn't find next (*%s) file.", file_type);
663 				fFinished = TRUE;
664 			}
665 		}
666 	}
667 	/* Close the search handle. */
668 	FindClose(hSearch);
669 #else
670 	DIR *dir;
671 	struct dirent *ent;
672 
673 	if ((dir = opendir(path)) == NULL) {
674 		belle_sip_error("Could't open [%s] directory.", path);
675 		return NULL;
676 	}
677 
678 	/* loop on all directory files */
679 	errno = 0;
680 	ent = readdir(dir);
681 	while (ent != NULL) {
682 		/* filter on file type if given */
683 		if (file_type==NULL
684 			|| (strncmp(ent->d_name+strlen(ent->d_name)-strlen(file_type), file_type, strlen(file_type))==0) ) {
685 			char *name_with_path=belle_sip_strdup_printf("%s/%s",path,ent->d_name);
686 			file_list = belle_sip_list_append(file_list, name_with_path);
687 		}
688 		ent = readdir(dir);
689 	}
690 	if (errno != 0) {
691 		belle_sip_error("Error while reading the [%s] directory: %s.", path, strerror(errno));
692 	}
693 	closedir(dir);
694 #endif
695 	return file_list;
696 }
697 
belle_sip_mkdir(const char * path)698 int belle_sip_mkdir(const char *path) {
699 #ifdef _WIN32
700 	return _mkdir(path);
701 #else
702 	return mkdir(path, 0700);
703 #endif
704 }
705 
706