belle_sip_utils.c 19.2 KB
Newer Older
jehan's avatar
jehan committed
1 2
/*
	belle-sip - SIP (RFC3261) library.
3
	Copyright (C) 2010-2018  Belledonne Communications SARL
jehan's avatar
jehan committed
4

5 6 7 8
	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 2 of the License, or
	(at your option) any later version.
jehan's avatar
jehan committed
9

10 11 12 13
	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.
jehan's avatar
jehan committed
14

15 16
	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
jehan's avatar
jehan committed
17
*/
18

19
#define _CRT_RAND_S
20
#include <stddef.h>
21
#include <stdlib.h>
22
#include <sys/stat.h>
23
#include "belle_sip_internal.h"
jehan's avatar
jehan committed
24
#include "bctoolbox/parser.h"
25
#include "bctoolbox/crypto.h"
jehan's avatar
jehan committed
26

jehan's avatar
jehan committed
27
#include "clock_gettime.h" /*for apple*/
jehan's avatar
jehan committed
28

29
#ifndef _WIN32
30
#include <unistd.h>
Simon Morlat's avatar
Simon Morlat committed
31
#include <sys/time.h> /*for gettimeofday*/
32
#include <dirent.h> /* available on POSIX system only */
33 34
#else
#include <direct.h>
Simon Morlat's avatar
Simon Morlat committed
35 36
#endif

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;
Ghislain MARY's avatar
Ghislain MARY committed
39 40
	va_list args;
	va_start(args, fmt);
41 42 43 44 45 46 47 48 49
	ret = belle_sip_snprintf_valist(buff, buff_size, offset, fmt, args);
	va_end(args);

	return ret;
}

belle_sip_error_code belle_sip_snprintf_valist(char *buff, size_t buff_size, size_t *offset, const char *fmt, va_list args) {
	int ret;
	belle_sip_error_code error = BELLE_SIP_OK;
Ghislain MARY's avatar
Ghislain MARY committed
50 51
	ret = vsnprintf(buff + *offset, buff_size - *offset, fmt, args);
	if ((ret < 0)
52
		|| (ret >= (int)(buff_size - *offset))) {
Ghislain MARY's avatar
Ghislain MARY committed
53 54 55 56 57 58 59 60
			error = BELLE_SIP_BUFFER_OVERFLOW;
		*offset = buff_size;
	} else {
		*offset += ret;
	}
	return error;
}

61
#if defined(_WIN32) || defined(_WIN32_WCE)
jehan's avatar
jehan committed
62 63 64 65 66
#define ENDLINE "\r\n"
#else
#define ENDLINE "\n"
#endif

67
#ifdef _WIN32
Simon Morlat's avatar
Simon Morlat committed
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
static int belle_sip_gettimeofday (struct timeval *tv, void* tz)
{
	union
	{
		__int64 ns100; /*time since 1 Jan 1601 in 100ns units */
		FILETIME fileTime;
	} now;

	GetSystemTimeAsFileTime (&now.fileTime);
	tv->tv_usec = (long) ((now.ns100 / 10LL) % 1000000LL);
	tv->tv_sec = (long) ((now.ns100 - 116444736000000000LL) / 10000000LL);
	return 0;
}
#else
#define belle_sip_gettimeofday gettimeofday
#endif

85

Simon Morlat's avatar
Simon Morlat committed
86

87
#ifndef _WIN32
jehan's avatar
jehan committed
88

89
static int find_best_clock_id (void) {
90
#if 0
91
	struct timespec ts;
jehan's avatar
jehan committed
92
	static int clock_id=-1;
93
#ifndef __ANDROID__
jehan's avatar
jehan committed
94 95
#define DEFAULT_CLOCK_MODE CLOCK_MONOTONIC
#else
96
#define DEFAULT_CLOCK_MODE CLOCK_REALTIME /*monotonic clock stop during sleep mode*/
jehan's avatar
jehan committed
97 98 99
#endif
	if (clock_id==-1) {
		if (clock_gettime(DEFAULT_CLOCK_MODE,&ts)!=1){
100
			clock_id=DEFAULT_CLOCK_MODE;
jehan's avatar
jehan committed
101
		} else if (clock_gettime(CLOCK_REALTIME,&ts)!=1){
102
			clock_id=CLOCK_REALTIME;
jehan's avatar
jehan committed
103 104
		} else {
			belle_sip_fatal("Cannot find suitable clock mode");
105
		}
jehan's avatar
jehan committed
106 107
	}
	return clock_id;
108 109
#else
	/* 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 112 113 114 115
	 * 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.
	 * When the macbook resumes at T0+8000, nothing happens. The REGISTER refresh will be sent at T0+8000+3600-60.
	 * 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.
	 * As a result, we fallback to CLOCK_REALTIME until the OS correctly implement CLOCK_MONOTONIC according to POSIX specifications
	 */
116
#ifdef __APPLE__
117 118 119
	#ifdef CLOCK_REALTIME
		#undef CLOCK_REALTIME
	#endif
120 121
	#define CLOCK_REALTIME BC_CLOCK_REALTIME
#endif
122 123
	return CLOCK_REALTIME;
#endif
jehan's avatar
jehan committed
124 125
}
uint64_t belle_sip_time_ms(void){
126 127 128 129
#ifdef __APPLE__
#define clock_gettime bc_clock_gettime
#endif

jehan's avatar
jehan committed
130 131 132
	struct timespec ts;
	if (clock_gettime(find_best_clock_id(),&ts)==-1){
		belle_sip_error("clock_gettime() error for clock_id=%i: %s",find_best_clock_id(),strerror(errno));
133 134 135 136
		return 0;
	}
	return (ts.tv_sec*1000LL) + (ts.tv_nsec/1000000LL);
}
Simon Morlat's avatar
Simon Morlat committed
137 138
#else
uint64_t belle_sip_time_ms(void){
139
#ifdef BELLE_SIP_WINDOWS_DESKTOP
Simon Morlat's avatar
Simon Morlat committed
140
	return GetTickCount();
141 142
#else
	return GetTickCount64();
Ghislain MARY's avatar
Ghislain MARY committed
143
#endif
Simon Morlat's avatar
Simon Morlat committed
144 145
}
#endif
146

jehan's avatar
jehan committed
147 148 149 150 151 152 153 154
/**
 * parser parameter pair
 */



belle_sip_param_pair_t* belle_sip_param_pair_new(const char* name,const char* value) {
	belle_sip_param_pair_t* lPair = (belle_sip_param_pair_t*)belle_sip_new0(belle_sip_param_pair_t);
jehan's avatar
jehan committed
155 156
	lPair->name=name?belle_sip_strdup(name):NULL;
	lPair->value=value?belle_sip_strdup(value):NULL;
jehan's avatar
jehan committed
157 158 159
	return lPair;
}

160 161 162
void belle_sip_param_pair_destroy(belle_sip_param_pair_t*  pair) {
	if (pair->name) belle_sip_free(pair->name);
	if (pair->value) belle_sip_free(pair->value);
163
	belle_sip_free(pair);
jehan's avatar
jehan committed
164 165 166 167 168
}

int belle_sip_param_pair_comp_func(const belle_sip_param_pair_t *a, const char*b) {
	return strcmp(a->name,b);
}
jehan's avatar
jehan committed
169 170 171
int belle_sip_param_pair_case_comp_func(const belle_sip_param_pair_t *a, const char*b) {
	return strcasecmp(a->name,b);
}
jehan's avatar
jehan committed
172

173
char* _belle_sip_str_dup_and_unquote_string(const char* quoted_string) {
174 175 176 177 178
	size_t value_size = strlen(quoted_string);
	char* unquoted_string = belle_sip_malloc0(value_size-2+1);
	strncpy(unquoted_string,quoted_string+1,value_size-2);
	return unquoted_string;
}
179

180 181 182 183

char *belle_sip_unquote_strdup(const char *str){
	const char *p;
	if (str==NULL) return NULL;
184

185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
	for(p=str;*p!='\0';++p){
		switch(*p){
			case ' ':
			case '\t':
			break;
			case '"':
				return _belle_sip_str_dup_and_unquote_string(p);
			default:
				return belle_sip_strdup(str);
			break;
		}
	}
	return belle_sip_strdup(str);
}

200 201 202 203 204 205 206
uint32_t belle_sip_random(void){
	unsigned char rand_buffer[4];
	belle_sip_random_bytes(rand_buffer, 4);
	return ((((uint32_t)rand_buffer[0])<<24) |
		(((uint32_t)rand_buffer[1])<<16) |
		(((uint32_t)rand_buffer[2])<<8) |
		(((uint32_t)rand_buffer[3])<<0));
207

208 209
}

210 211 212 213 214 215

void belle_sip_set_socket_api(bctbx_vsocket_api_t* my_api){

	bctbx_vsocket_api_set_default(my_api);
}

216 217
static const char *symbols="aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789-~";

218 219 220 221
/**
 * Write a random text token of supplied size.
**/
char * belle_sip_random_token(char *ret, size_t size){
222
	unsigned int i;
223
	belle_sip_random_bytes((unsigned char *)ret, size-1);
224
	for(i=0;i<size-1;++i){
225
		ret[i]=symbols[ret[i] & 63];
226 227 228 229 230
	}
	ret[i]=0;
	return ret;
}

231 232 233 234
/**
 * Write random bytes of supplied size.
**/
unsigned char * belle_sip_random_bytes(unsigned char *ret, size_t size){
235 236 237 238 239 240 241 242 243
	// create a rng context
	bctbx_rng_context_t *RNG = bctbx_rng_context_new();

	// get the requested bytes
	bctbx_rng_get(RNG, ret, size);

	// delete rng context
	bctbx_rng_context_free(RNG);

244 245 246
	return ret;
}

247 248 249 250 251 252 253 254 255 256 257 258 259 260
typedef struct bits_reader{
	const uint8_t *buffer;
	size_t buf_size;
	int bit_index;
}bits_reader_t;

static void bits_reader_init(bits_reader_t *reader, const uint8_t *buffer, size_t bufsize){
	reader->buffer=buffer;
	reader->buf_size=bufsize;
	reader->bit_index=0;
}

static int bits_reader_read(bits_reader_t *reader, int count, unsigned int *ret){
	unsigned int tmp;
261 262
	size_t byte_index=reader->bit_index/8;
	size_t bit_index=reader->bit_index % 8;
263
	int shift=32-(int)bit_index-count;
264

265 266 267 268
	if (count>=24){
		belle_sip_error("This bit reader cannot read more than 24 bits at once.");
		return -1;
	}
269

270 271 272 273 274 275 276 277 278 279 280 281
	if (byte_index<reader->buf_size)
		tmp=((unsigned int)reader->buffer[byte_index++])<<24;
	else{
		belle_sip_error("Bit reader goes end of stream.");
		return -1;
	}
	if (byte_index<reader->buf_size)
		tmp|=((unsigned int)reader->buffer[byte_index++])<<16;
	if (byte_index<reader->buf_size)
		tmp|=((unsigned int)reader->buffer[byte_index++])<<8;
	if (byte_index<reader->buf_size)
		tmp|=((unsigned int)reader->buffer[byte_index++]);
282

283 284 285 286 287 288 289 290 291 292
	tmp=tmp>>shift;
	tmp=tmp & ((1<<count)-1);
	reader->bit_index+=count;
	*ret=tmp;
	return 0;
}

char * belle_sip_octets_to_text(const uint8_t *hash, size_t hash_len, char *ret, size_t size){
	int i;
	bits_reader_t bitctx;
293

294
	bits_reader_init(&bitctx,hash,hash_len);
295

296
	for(i=0;i<(int)size-1;++i){
297 298 299 300
		unsigned int val=0;
		if (bits_reader_read(&bitctx,6,&val)==0){
			ret[i]=symbols[val];
		}else break;
301 302 303 304 305
	}
	ret[i]=0;
	return ret;
}

306 307 308 309 310 311 312 313 314 315 316 317 318 319 320
void belle_sip_util_copy_headers(belle_sip_message_t *orig, belle_sip_message_t *dest, const char*header, int multiple){
	const belle_sip_list_t *elem;
	elem=belle_sip_message_get_headers(orig,header);
	for (;elem!=NULL;elem=elem->next){
		belle_sip_header_t *ref_header=(belle_sip_header_t*)elem->data;
		if (ref_header){
			ref_header=(belle_sip_header_t*)belle_sip_object_clone((belle_sip_object_t*)ref_header);
			if (!multiple){
				belle_sip_message_set_header(dest,ref_header);
				break;
			}else
				belle_sip_message_add_header(dest,ref_header);
		}
	}
}
jehan's avatar
jehan committed
321

322

323
char* belle_sip_to_unescaped_string(const char* buff) {
jehan's avatar
jehan committed
324
	return bctbx_unescaped_string(buff);
325
}
326

jehan's avatar
jehan committed
327 328
size_t belle_sip_get_char(const char* a, char *b) {
	return bctbx_get_char(a,b);
329 330 331 332 333 334 335 336 337 338 339 340 341
}
/*
static void print_noescapes_map(char noescapes[BELLE_SIP_NO_ESCAPES_SIZE], const char *name) {
	unsigned int i;
	printf("Noescapes %s :", name);
	for (i=' '; i <= '~'; ++i) {
		if (noescapes[i] == 1) printf ("%c", i);
		//if (noescapes[i] == 1) printf ("%c %d - %d\n", i, (char)i, noescapes[i]);
	}
	printf ("init: %d\n", noescapes[BELLE_SIP_NO_ESCAPES_SIZE-1]);
}
*/

jehan's avatar
jehan committed
342 343 344
static const bctbx_noescape_rules_t* get_sip_uri_username_noescapes(void) {
	static bctbx_noescape_rules_t noescapes = {0};
	if (noescapes[BCTBX_NOESCAPE_RULES_USER_INDEX] == 0) {
345
		// concurrent initialization should not be an issue
jehan's avatar
jehan committed
346 347 348 349 350 351
		/*user             =  1*( unreserved / escaped / user-unreserved )
		 unreserved  =  alphanum / mark
		 mark        =  "-" / "_" / "." / "!" / "~" / "*" / "'"
		 / "(" / ")"
		user-unreserved  =  "&" / "=" / "+" / "$" / "," / ";" / "?" / "/"
		*/
jehan's avatar
jehan committed
352
		bctbx_noescape_rules_add_alfanums(noescapes);
jehan's avatar
jehan committed
353
		/*mark*/
jehan's avatar
jehan committed
354
		bctbx_noescape_rules_add_list(noescapes, "-_.!~*'()");
jehan's avatar
jehan committed
355
		/*user-unreserved*/
jehan's avatar
jehan committed
356
		bctbx_noescape_rules_add_list(noescapes, "&=+$,;?/");
jehan's avatar
jehan committed
357

jehan's avatar
jehan committed
358
		noescapes[BCTBX_NOESCAPE_RULES_USER_INDEX] = 1; // initialized
359 360
//		print_noescapes_map(noescapes, "uri_username");
	}
jehan's avatar
jehan committed
361
	return (const bctbx_noescape_rules_t*)&noescapes;/*gcc asks for a cast, clang not*/
362
}
jehan's avatar
jehan committed
363 364 365 366 367
/*
 *
 * password         =  *( unreserved / escaped /
                    "&" / "=" / "+" / "$" / "," )
 * */
jehan's avatar
jehan committed
368 369 370
static const bctbx_noescape_rules_t* get_sip_uri_userpasswd_noescapes(void) {
	static bctbx_noescape_rules_t noescapes = {0};
	if (noescapes[BCTBX_NOESCAPE_RULES_USER_INDEX] == 0) {
jehan's avatar
jehan committed
371
		// unreserved
jehan's avatar
jehan committed
372 373 374
		bctbx_noescape_rules_add_alfanums(noescapes);
		bctbx_noescape_rules_add_list(noescapes, "-_.!~*'()");
		bctbx_noescape_rules_add_list(noescapes, "&=+$,");
jehan's avatar
jehan committed
375

jehan's avatar
jehan committed
376
		noescapes[BCTBX_NOESCAPE_RULES_USER_INDEX] = 1; // initialized
jehan's avatar
jehan committed
377 378

	}
jehan's avatar
jehan committed
379
	return (const bctbx_noescape_rules_t*)&noescapes;/*gcc asks for a cast, clang not*/
jehan's avatar
jehan committed
380
}
381

jehan's avatar
jehan committed
382 383 384
static  const bctbx_noescape_rules_t* get_sip_uri_parameter_noescapes(void) {
	static bctbx_noescape_rules_t  noescapes= {0};
	if (noescapes[BCTBX_NOESCAPE_RULES_USER_INDEX] == 0) {
385 386 387 388 389 390 391 392 393 394 395 396 397
		/*
		 other-param       =  pname [ "=" pvalue ]
		 pname             =  1*paramchar
		 pvalue            =  1*paramchar
		 paramchar         =  param-unreserved / unreserved / escaped
		 param-unreserved  =  "[" / "]" / "/" / ":" / "&" / "+" / "$"
		 unreserved  =  alphanum / mark
		 mark        =  "-" / "_" / "." / "!" / "~" / "*" / "'"
		 / "(" / ")"
		 escaped     =  "%" HEXDIG HEXDIG
		 token       =  1*(alphanum / "-" / "." / "!" / "%" / "*"
		 / "_" / "+" / "`" / "'" / "~" )
		 */
jehan's avatar
jehan committed
398 399
		//param-unreserved  =

jehan's avatar
jehan committed
400
		bctbx_noescape_rules_add_list(noescapes,"[]/:&+$");
jehan's avatar
jehan committed
401

402
		// token
jehan's avatar
jehan committed
403 404
		bctbx_noescape_rules_add_alfanums(noescapes);
		bctbx_noescape_rules_add_list(noescapes, "-.!%*_+`'~");
405 406

		// unreserved
jehan's avatar
jehan committed
407
		bctbx_noescape_rules_add_list(noescapes, "-_.!~*'()");
408

jehan's avatar
jehan committed
409
		noescapes[BCTBX_NOESCAPE_RULES_USER_INDEX] = 1; // initialized
410 411
//		print_noescapes_map(noescapes, "uri_parameter");
	}
jehan's avatar
jehan committed
412
	return (const bctbx_noescape_rules_t*)&noescapes;/*gcc asks for a cast, clang not*/
413
}
jehan's avatar
jehan committed
414 415 416
static const bctbx_noescape_rules_t* get_sip_uri_header_noescapes(void) {
	static bctbx_noescape_rules_t  noescapes= {0};
	if (noescapes[BCTBX_NOESCAPE_RULES_USER_INDEX] == 0) {
417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432
		/*
		 unreserved  =  alphanum / mark
		 mark        =  "-" / "_" / "." / "!" / "~" / "*" / "'"
		 / "(" / ")"
		 escaped     =  "%" HEXDIG HEXDIG

		 //....
		header          =  hname "=" hvalue
		hname           =  1*( hnv-unreserved / unreserved / escaped )
		hvalue          =  *( hnv-unreserved / unreserved / escaped )
		hnv-unreserved  =  "[" / "]" / "/" / "?" / ":" / "+" / "$"

		 */

		// unreserved
		//alphanum
jehan's avatar
jehan committed
433
		bctbx_noescape_rules_add_alfanums(noescapes);
434
		//mark
jehan's avatar
jehan committed
435
		bctbx_noescape_rules_add_list(noescapes, "-_.!~*'()");
436

jehan's avatar
jehan committed
437
		bctbx_noescape_rules_add_list(noescapes, "[]/?:+$");
438
		//hnv-unreserved
jehan's avatar
jehan committed
439
		noescapes[BCTBX_NOESCAPE_RULES_USER_INDEX] = 1; // initialized
440 441
//		print_noescapes_map(noescapes, "uri_parameter");
	}
jehan's avatar
jehan committed
442
	return (const bctbx_noescape_rules_t*)&noescapes;/*gcc asks for a cast, clang not*/
443
}
444 445 446


char* belle_sip_uri_to_escaped_username(const char* buff) {
jehan's avatar
jehan committed
447
	return bctbx_escape(buff, *get_sip_uri_username_noescapes());
448
}
jehan's avatar
jehan committed
449
char* belle_sip_uri_to_escaped_userpasswd(const char* buff) {
jehan's avatar
jehan committed
450
	return bctbx_escape(buff, *get_sip_uri_userpasswd_noescapes());
jehan's avatar
jehan committed
451
}
452
char* belle_sip_uri_to_escaped_parameter(const char* buff) {
jehan's avatar
jehan committed
453
	return bctbx_escape(buff, *get_sip_uri_parameter_noescapes());
454
}
455
char* belle_sip_uri_to_escaped_header(const char* buff) {
jehan's avatar
jehan committed
456
	return bctbx_escape(buff, *get_sip_uri_header_noescapes());
457
}
458 459 460


/*uri (I.E RFC 2396)*/
jehan's avatar
jehan committed
461 462 463
static const bctbx_noescape_rules_t *get_generic_uri_query_noescapes(void) {
	static bctbx_noescape_rules_t  noescapes= {0};
	if (noescapes[BCTBX_NOESCAPE_RULES_USER_INDEX] == 0) {
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478
		/*
	    uric          = reserved | unreserved | escaped
		reserved      = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
		                "$" | ","
		unreserved    = alphanum | mark
		mark          = "-" | "_" | "." | "!" | "~" | "*" | "'" |
		                      "(" | ")"

		3.4. Query Component
      	  query         = *uric
   	   Within a query component, the characters ";", "/", "?", ":", "@",
   	   "&", "=", "+", ",", and "$" are reserved.

		*/
		/*unreserved*/
jehan's avatar
jehan committed
479
		bctbx_noescape_rules_add_alfanums(noescapes);
480
		/*mark*/
jehan's avatar
jehan committed
481 482 483
		bctbx_noescape_rules_add_list(noescapes, "-_.!~*'()");
		bctbx_noescape_rules_add_list(noescapes, "=&"); // otherwise how to pass parameters?
		noescapes[BCTBX_NOESCAPE_RULES_USER_INDEX] = 1; // initialized
484
	}
jehan's avatar
jehan committed
485
	return (const bctbx_noescape_rules_t*)&noescapes;/*gcc asks for a cast, clang not*/
486 487
}

jehan's avatar
jehan committed
488 489 490
static const bctbx_noescape_rules_t *get_generic_uri_path_noescapes(void) {
	static bctbx_noescape_rules_t  noescapes= {0};
	if (noescapes[BCTBX_NOESCAPE_RULES_USER_INDEX] == 0) {
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515
		/*
	    3.3. Path Component

   The path component contains data, specific to the authority (or the
   scheme if there is no authority component), identifying the resource
   within the scope of that scheme and authority.

      path          = [ abs_path | opaque_part ]

      path_segments = segment *( "/" segment )
      segment       = *pchar *( ";" param )
      param         = *pchar

      pchar         = unreserved | escaped |
                      ":" | "@" | "&" | "=" | "+" | "$" | ","

   The path may consist of a sequence of path segments separated by a
   single slash "/" character.  Within a path segment, the characters
   "/", ";", "=", and "?" are reserved.  Each path segment may include a
   sequence of parameters, indicated by the semicolon ";" character.
   The parameters are not significant to the parsing of relative
   references.

		*/
		/*unreserved*/
jehan's avatar
jehan committed
516
		bctbx_noescape_rules_add_alfanums(noescapes);
517
		/*mark*/
jehan's avatar
jehan committed
518
		bctbx_noescape_rules_add_list(noescapes, "-_.!~*'()");
519
		/*pchar*/
jehan's avatar
jehan committed
520
		bctbx_noescape_rules_add_list(noescapes, ":@&=+$,");
521
		/*;*/
jehan's avatar
jehan committed
522 523
		bctbx_noescape_rules_add_list(noescapes, ";");
		bctbx_noescape_rules_add_list(noescapes, "/");
524

jehan's avatar
jehan committed
525
		noescapes[BCTBX_NOESCAPE_RULES_USER_INDEX] = 1; // initialized
526
	}
jehan's avatar
jehan committed
527
	return (const bctbx_noescape_rules_t*)&noescapes;/*gcc asks for a cast, clang not*/
528 529 530
}

char* belle_generic_uri_to_escaped_query(const char* buff) {
jehan's avatar
jehan committed
531
	return bctbx_escape(buff, *get_generic_uri_query_noescapes());
532 533
}
char* belle_generic_uri_to_escaped_path(const char* buff) {
jehan's avatar
jehan committed
534
	return bctbx_escape(buff, *get_generic_uri_path_noescapes());
535 536
}

537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566
char* belle_sip_string_to_backslash_less_unescaped_string(const char* buff) {
	char *output_buff=belle_sip_malloc(strlen(buff)+1);
	unsigned int i;
	unsigned int out_buff_index=0;

	for(i=0; buff[i] != '\0'; i++) {
		if (buff[i] == '\\') {
			i++;/*skip \*/
		}
		/*make sure to only remove one \ in case of \\*/
		output_buff[out_buff_index++]=buff[i];
	}
	output_buff[out_buff_index]='\0';
	return output_buff;
}
char* belle_sip_display_name_to_backslashed_escaped_string(const char* buff) {
	char output_buff[BELLE_SIP_MAX_TO_STRING_SIZE];
	unsigned int i;
	unsigned int out_buff_index=0;
	for(i=0; buff[i] != '\0' && out_buff_index < sizeof(output_buff)-2; i++) {
		/*-3 to make sure last param can be stored in escaped form*/
		const char c = buff[i];
		if (c == '\"' || c == '\\') {
			output_buff[out_buff_index++]='\\'; /*insert escape character*/
		}
		output_buff[out_buff_index++]=c;
	}
	output_buff[out_buff_index]='\0';
	return belle_sip_strdup(output_buff);
}
567 568 569

belle_sip_list_t *belle_sip_parse_directory(const char *path, const char *file_type) {
	belle_sip_list_t* file_list = NULL;
570
#ifdef _WIN32
571 572 573 574 575 576 577
	WIN32_FIND_DATA FileData;
	HANDLE hSearch;
	BOOL fFinished = FALSE;
	char szDirPath[1024];
#ifdef UNICODE
	wchar_t wszDirPath[1024];
#endif
578

579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595
	if (file_type == NULL) {
		file_type = ".*";
	}
	snprintf(szDirPath, sizeof(szDirPath), "%s\\*%s", path, file_type);
#ifdef UNICODE
	mbstowcs(wszDirPath, szDirPath, sizeof(wszDirPath));
	hSearch = FindFirstFileExW(wszDirPath, FindExInfoStandard, &FileData, FindExSearchNameMatch, NULL, 0);
#else
	hSearch = FindFirstFileExA(szDirPath, FindExInfoStandard, &FileData, FindExSearchNameMatch, NULL, 0);
#endif
	if (hSearch == INVALID_HANDLE_VALUE) {
		belle_sip_message("No file (*%s) found in [%s] [%d].", file_type, szDirPath, (int)GetLastError());
		return NULL;
	}
	snprintf(szDirPath, sizeof(szDirPath), "%s", path);
	while (!fFinished) {
		char szFilePath[1024];
596
#ifdef UNICODE
597 598 599 600 601 602 603 604 605 606 607 608 609 610
		char filename[512];
		wcstombs(filename, FileData.cFileName, sizeof(filename));
		snprintf(szFilePath, sizeof(szFilePath), "%s\\%s", szDirPath, filename);
#else
		snprintf(szFilePath, sizeof(szFilePath), "%s\\%s", szDirPath, FileData.cFileName);
#endif
		file_list = belle_sip_list_append(file_list, belle_sip_strdup(szFilePath));
		if (!FindNextFile(hSearch, &FileData)) {
			if (GetLastError() == ERROR_NO_MORE_FILES) {
				fFinished = TRUE;
			}
			else {
				belle_sip_error("Couldn't find next (*%s) file.", file_type);
				fFinished = TRUE;
611 612
			}
		}
613 614 615 616 617 618 619 620 621
	}
	/* Close the search handle. */
	FindClose(hSearch);
#else
	DIR *dir;
	struct dirent *ent;

	if ((dir = opendir(path)) == NULL) {
		belle_sip_error("Could't open [%s] directory.", path);
622 623
		return NULL;
	}
624 625

	/* loop on all directory files */
626
	errno = 0;
627 628
	ent = readdir(dir);
	while (ent != NULL) {
629 630 631
		/* filter on file type if given */
		if (file_type==NULL
			|| (strncmp(ent->d_name+strlen(ent->d_name)-strlen(file_type), file_type, strlen(file_type))==0) ) {
632 633
			char *name_with_path=belle_sip_strdup_printf("%s/%s",path,ent->d_name);
			file_list = belle_sip_list_append(file_list, name_with_path);
634
		}
635
		ent = readdir(dir);
636
	}
637
	if (errno != 0) {
638
		belle_sip_error("Error while reading the [%s] directory: %s.", path, strerror(errno));
639 640 641 642
	}
	closedir(dir);
#endif
	return file_list;
643 644 645
}

int belle_sip_mkdir(const char *path) {
646
#ifdef _WIN32
647
	return _mkdir(path);
648
#else
649 650 651
	return mkdir(path, 0700);
#endif
}