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