]> git.ipfire.org Git - thirdparty/freeswitch.git/blob - src/switch_utils.c
[mod_rtmp] Add OpenSSL 3 support.
[thirdparty/freeswitch.git] / src / switch_utils.c
1 /*
2 * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3 * Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
4 *
5 * Version: MPL 1.1
6 *
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
11 *
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
15 * License.
16 *
17 * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
18 *
19 * The Initial Developer of the Original Code is
20 * Anthony Minessale II <anthm@freeswitch.org>
21 * Portions created by the Initial Developer are Copyright (C)
22 * the Initial Developer. All Rights Reserved.
23 *
24 * Contributor(s):
25 *
26 * Anthony Minessale II <anthm@freeswitch.org>
27 * Juan Jose Comellas <juanjo@comellas.org>
28 * Seven Du <dujinfang@gmail.com>
29 * Windy Wang <xiaofengcanyuexp@163.com>
30 *
31 * switch_utils.c -- Compatibility and Helper Code
32 *
33 */
34
35 #include <switch.h>
36 #include "private/switch_apr_pvt.h"
37 #ifndef WIN32
38 #include <arpa/inet.h>
39 #if defined(HAVE_SYS_TIME_H) && defined(HAVE_SYS_RESOURCE_H)
40 #include <sys/time.h>
41 #include <sys/resource.h>
42 #endif
43 #include <sys/types.h>
44 #include <unistd.h>
45 #else
46 #include <intsafe.h> /* SIZETMult() */
47 /* process.h is required for _getpid() */
48 #include <process.h>
49 #endif
50 #include "private/switch_core_pvt.h"
51 #define ESCAPE_META '\\'
52 #ifdef SWITCH_HAVE_GUMBO
53 #include "gumbo.h"
54 #endif
55
56 #if defined(HAVE_OPENSSL)
57 #include <openssl/evp.h>
58 #endif
59
60 #ifdef __GLIBC__
61 #include <malloc.h> /* mallinfo() */
62 #endif
63
64 struct switch_network_node {
65 ip_t ip;
66 ip_t mask;
67 uint32_t bits;
68 int family;
69 switch_bool_t ok;
70 char *token;
71 char *str;
72 switch_network_port_range_t port_range;
73 struct switch_network_node *next;
74 };
75 typedef struct switch_network_node switch_network_node_t;
76
77 struct switch_network_list {
78 struct switch_network_node *node_head;
79 switch_bool_t default_type;
80 switch_memory_pool_t *pool;
81 char *name;
82 };
83
84 SWITCH_DECLARE(void *) switch_calloc(size_t nmemb, size_t size)
85 {
86 return calloc(nmemb, size);
87 }
88
89 #ifndef WIN32
90 SWITCH_DECLARE(int) switch_inet_pton(int af, const char *src, void *dst)
91 {
92 return inet_pton(af, src, dst);
93 }
94 #endif
95
96 SWITCH_DECLARE(char *) switch_print_host(switch_sockaddr_t *addr, char *buf, switch_size_t len)
97 {
98 switch_port_t port;
99
100 switch_get_addr(buf, len, addr);
101 port = switch_sockaddr_get_port(addr);
102
103 snprintf(buf + strlen(buf), len - strlen(buf), ":%d", port);
104 return buf;
105 }
106
107 SWITCH_DECLARE(switch_status_t) switch_frame_alloc(switch_frame_t **frame, switch_size_t size)
108 {
109 switch_frame_t *new_frame;
110
111 switch_zmalloc(new_frame, sizeof(*new_frame));
112
113 switch_set_flag(new_frame, SFF_DYNAMIC);
114 new_frame->buflen = (uint32_t)size;
115 new_frame->data = malloc(size);
116 switch_assert(new_frame->data);
117
118 *frame = new_frame;
119
120 return SWITCH_STATUS_SUCCESS;
121 }
122
123
124 typedef struct switch_frame_node_s {
125 switch_frame_t *frame;
126 int inuse;
127 struct switch_frame_node_s *prev;
128 struct switch_frame_node_s *next;
129 } switch_frame_node_t;
130
131 struct switch_frame_buffer_s {
132 switch_frame_node_t *head;
133 switch_memory_pool_t *pool;
134 switch_queue_t *queue;
135 switch_mutex_t *mutex;
136 uint32_t total;
137 };
138
139 static switch_frame_t *find_free_frame(switch_frame_buffer_t *fb, switch_frame_t *orig)
140 {
141 switch_frame_node_t *np;
142
143 switch_mutex_lock(fb->mutex);
144
145 for (np = fb->head; np; np = np->next) {
146 if (!np->inuse && ((orig->packet && np->frame->packet) || (!orig->packet && !np->frame->packet))) {
147
148 if (np == fb->head) {
149 fb->head = np->next;
150 } else if (np->prev) {
151 np->prev->next = np->next;
152 }
153
154 if (np->next) {
155 np->next->prev = np->prev;
156 }
157
158 fb->total--;
159 np->prev = np->next = NULL;
160 break;
161 }
162 }
163
164 if (!np) {
165 np = switch_core_alloc(fb->pool, sizeof(*np));
166 np->frame = switch_core_alloc(fb->pool, sizeof(*np->frame));
167
168 if (orig->packet) {
169 np->frame->packet = switch_core_alloc(fb->pool, SWITCH_RTP_MAX_BUF_LEN);
170 } else {
171 np->frame->packet = NULL;
172 np->frame->data = switch_core_alloc(fb->pool, SWITCH_RTP_MAX_BUF_LEN);
173 np->frame->buflen = SWITCH_RTP_MAX_BUF_LEN;
174 }
175 }
176
177 np->frame->samples = orig->samples;
178 np->frame->rate = orig->rate;
179 np->frame->channels = orig->channels;
180 np->frame->payload = orig->payload;
181 np->frame->timestamp = orig->timestamp;
182 np->frame->seq = orig->seq;
183 np->frame->ssrc = orig->ssrc;
184 np->frame->m = orig->m;
185 np->frame->flags = orig->flags;
186 np->frame->codec = orig->codec;
187 np->frame->pmap = orig->pmap;
188 np->frame->img = NULL;
189 np->frame->extra_data = np;
190 np->inuse = 1;
191
192 switch_set_flag(np->frame, SFF_DYNAMIC);
193
194 if (orig->packet) {
195 memcpy(np->frame->packet, orig->packet, orig->packetlen);
196 np->frame->packetlen = orig->packetlen;
197 np->frame->data = ((unsigned char *)np->frame->packet) + 12;
198 np->frame->datalen = orig->datalen;
199 } else {
200 np->frame->packet = NULL;
201 np->frame->packetlen = 0;
202 memcpy(np->frame->data, orig->data, orig->datalen);
203 np->frame->datalen = orig->datalen;
204 }
205
206 if (orig->img && !switch_test_flag(orig, SFF_ENCODED)) {
207 switch_img_copy(orig->img, &np->frame->img);
208 }
209
210 switch_mutex_unlock(fb->mutex);
211
212 return np->frame;
213 }
214
215 SWITCH_DECLARE(switch_status_t) switch_frame_buffer_free(switch_frame_buffer_t *fb, switch_frame_t **frameP)
216 {
217 switch_frame_t *old_frame;
218 switch_frame_node_t *node;
219
220 switch_mutex_lock(fb->mutex);
221
222 old_frame = *frameP;
223 *frameP = NULL;
224
225 node = (switch_frame_node_t *) old_frame->extra_data;
226 node->inuse = 0;
227 switch_img_free(&node->frame->img);
228
229 fb->total++;
230
231 if (fb->head) {
232 fb->head->prev = node;
233 }
234
235 node->next = fb->head;
236 node->prev = NULL;
237 fb->head = node;
238
239 switch_assert(node->next != node);
240 switch_assert(node->prev != node);
241
242
243 switch_mutex_unlock(fb->mutex);
244
245 return SWITCH_STATUS_SUCCESS;
246 }
247
248 SWITCH_DECLARE(switch_status_t) switch_frame_buffer_dup(switch_frame_buffer_t *fb, switch_frame_t *orig, switch_frame_t **clone)
249 {
250 switch_frame_t *new_frame;
251
252 if (!orig) {
253 return SWITCH_STATUS_FALSE;
254 }
255
256 switch_assert(orig->buflen);
257
258 new_frame = find_free_frame(fb, orig);
259
260 *clone = new_frame;
261
262 return SWITCH_STATUS_SUCCESS;
263 }
264
265 SWITCH_DECLARE(switch_status_t) switch_frame_buffer_push(switch_frame_buffer_t *fb, void *ptr)
266 {
267 return switch_queue_push(fb->queue, ptr);
268 }
269
270 SWITCH_DECLARE(switch_status_t) switch_frame_buffer_trypush(switch_frame_buffer_t *fb, void *ptr)
271 {
272 return switch_queue_trypush(fb->queue, ptr);
273 }
274
275 SWITCH_DECLARE(switch_status_t) switch_frame_buffer_pop(switch_frame_buffer_t *fb, void **ptr)
276 {
277 return switch_queue_pop(fb->queue, ptr);
278 }
279
280 SWITCH_DECLARE(switch_status_t) switch_frame_buffer_trypop(switch_frame_buffer_t *fb, void **ptr)
281 {
282 return switch_queue_trypop(fb->queue, ptr);
283 }
284
285 SWITCH_DECLARE(int) switch_frame_buffer_size(switch_frame_buffer_t *fb)
286 {
287 return switch_queue_size(fb->queue);
288 }
289
290 SWITCH_DECLARE(switch_status_t) switch_frame_buffer_destroy(switch_frame_buffer_t **fbP)
291 {
292 switch_frame_buffer_t *fb = *fbP;
293 switch_memory_pool_t *pool;
294 *fbP = NULL;
295 pool = fb->pool;
296 switch_core_destroy_memory_pool(&pool);
297
298 return SWITCH_STATUS_SUCCESS;
299 }
300
301 SWITCH_DECLARE(switch_status_t) switch_frame_buffer_create(switch_frame_buffer_t **fbP, switch_size_t qlen)
302 {
303 switch_frame_buffer_t *fb;
304 switch_memory_pool_t *pool;
305
306 if (!qlen) qlen = 500;
307
308 switch_core_new_memory_pool(&pool);
309 fb = switch_core_alloc(pool, sizeof(*fb));
310 fb->pool = pool;
311 switch_queue_create(&fb->queue, qlen, fb->pool);
312 switch_mutex_init(&fb->mutex, SWITCH_MUTEX_NESTED, pool);
313 *fbP = fb;
314
315 return SWITCH_STATUS_SUCCESS;
316 }
317
318
319 SWITCH_DECLARE(switch_status_t) switch_frame_dup(switch_frame_t *orig, switch_frame_t **clone)
320 {
321 switch_frame_t *new_frame;
322
323 if (!orig) {
324 return SWITCH_STATUS_FALSE;
325 }
326
327 switch_assert(orig->buflen);
328
329 new_frame = malloc(sizeof(*new_frame));
330 switch_assert(new_frame);
331
332 *new_frame = *orig;
333 switch_set_flag(new_frame, SFF_DYNAMIC);
334
335 if (orig->packet) {
336 new_frame->packet = malloc(SWITCH_RTP_MAX_BUF_LEN);
337 switch_assert(new_frame->packet);
338 memcpy(new_frame->packet, orig->packet, orig->packetlen);
339 new_frame->data = ((unsigned char *)new_frame->packet) + 12;
340 } else {
341 new_frame->packet = NULL;
342 new_frame->data = malloc(new_frame->buflen);
343 switch_assert(new_frame->data);
344 memcpy(new_frame->data, orig->data, orig->datalen);
345 }
346
347
348 new_frame->codec = orig->codec;
349 new_frame->pmap = orig->pmap;
350 new_frame->img = NULL;
351
352
353 if (orig->img && !switch_test_flag(orig, SFF_ENCODED)) {
354 switch_img_copy(orig->img, &new_frame->img);
355 }
356 *clone = new_frame;
357
358 return SWITCH_STATUS_SUCCESS;
359 }
360
361 SWITCH_DECLARE(switch_status_t) switch_frame_free(switch_frame_t **frame)
362 {
363 switch_frame_t * f;
364
365 if (!frame) {
366 return SWITCH_STATUS_FALSE;
367 }
368
369 f = *frame;
370
371 if (!f || !switch_test_flag(f, SFF_DYNAMIC)) {
372 return SWITCH_STATUS_FALSE;
373 }
374
375 *frame = NULL;
376
377 if (f->img) {
378 switch_img_free(&(f->img));
379 }
380
381 if (f->packet) {
382 switch_safe_free(f->packet);
383 } else {
384 switch_safe_free(f->data);
385 }
386
387 free(f);
388
389 return SWITCH_STATUS_SUCCESS;
390 }
391
392 SWITCH_DECLARE(int) switch_strcasecmp_any(const char *str, ...)
393 {
394 va_list ap;
395 const char *next_str = 0;
396 int r = 0;
397
398 va_start(ap, str);
399
400 while ((next_str = va_arg(ap, const char *))) {
401 if (!strcasecmp(str, next_str)) {
402 r = 1;
403 break;
404 }
405 }
406
407 va_end(ap);
408
409 return r;
410 }
411
412
413 SWITCH_DECLARE(char *) switch_find_parameter(const char *str, const char *param, switch_memory_pool_t *pool)
414 {
415 char *e, *r = NULL, *ptr = NULL, *next = NULL;
416 size_t len;
417
418 ptr = (char *) str;
419
420 while (ptr) {
421 len = strlen(param);
422 e = ptr+len;
423 next = strchr(ptr, ';');
424
425 if (!strncasecmp(ptr, param, len) && *e == '=') {
426 size_t mlen;
427
428 ptr = ++e;
429
430 if (next) {
431 e = next;
432 } else {
433 e = ptr + strlen(ptr);
434 }
435
436 mlen = (e - ptr) + 1;
437
438 if (pool) {
439 r = switch_core_alloc(pool, mlen);
440 } else {
441 r = malloc(mlen);
442 }
443
444 switch_snprintf(r, mlen, "%s", ptr);
445
446 break;
447 }
448
449 if (next) {
450 ptr = next + 1;
451 } else break;
452 }
453
454 return r;
455 }
456
457 SWITCH_DECLARE(switch_status_t) switch_network_list_create(switch_network_list_t **list, const char *name, switch_bool_t default_type,
458 switch_memory_pool_t *pool)
459 {
460 switch_network_list_t *new_list;
461
462 if (!pool) {
463 switch_core_new_memory_pool(&pool);
464 }
465
466 new_list = switch_core_alloc(pool, sizeof(**list));
467 new_list->pool = pool;
468 new_list->default_type = default_type;
469 new_list->name = switch_core_strdup(new_list->pool, name);
470
471 *list = new_list;
472
473 return SWITCH_STATUS_SUCCESS;
474 }
475
476 #define IN6_AND_MASK(result, ip, mask) \
477 ((uint32_t *) (result))[0] =((const uint32_t *) (ip))[0] & ((const uint32_t *)(mask))[0]; \
478 ((uint32_t *) (result))[1] =((const uint32_t *) (ip))[1] & ((const uint32_t *)(mask))[1]; \
479 ((uint32_t *) (result))[2] =((const uint32_t *) (ip))[2] & ((const uint32_t *)(mask))[2]; \
480 ((uint32_t *) (result))[3] =((const uint32_t *) (ip))[3] & ((const uint32_t *)(mask))[3];
481 SWITCH_DECLARE(switch_bool_t) switch_testv6_subnet(ip_t _ip, ip_t _net, ip_t _mask) {
482 if (!IN6_IS_ADDR_UNSPECIFIED(&_mask.v6)) {
483 struct in6_addr a, b;
484 IN6_AND_MASK(&a, &_net, &_mask);
485 IN6_AND_MASK(&b, &_ip, &_mask);
486 return !memcmp(&a,&b, sizeof(struct in6_addr));
487 } else {
488 if (!IN6_IS_ADDR_UNSPECIFIED(&_net.v6)) {
489 return !memcmp(&_net,&_ip,sizeof(struct in6_addr));
490 }
491 else return SWITCH_TRUE;
492 }
493 }
494
495 SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip6_port_token(switch_network_list_t *list, ip_t ip, int port, const char **token)
496 {
497 switch_network_node_t *node;
498 switch_bool_t ok = list->default_type;
499 uint32_t bits = 0;
500
501 for (node = list->node_head; node; node = node->next) {
502 if (node->family == AF_INET) continue;
503
504 if (node->bits >= bits && switch_testv6_subnet(ip, node->ip, node->mask)) {
505 if (node->ok) {
506 ok = SWITCH_TRUE;
507 } else {
508 ok = SWITCH_FALSE;
509 }
510
511 bits = node->bits;
512
513 if (token) {
514 *token = node->token;
515 }
516 }
517 }
518
519 return ok;
520 }
521
522 SWITCH_DECLARE(switch_bool_t) is_port_in_node(int port, switch_network_node_t *node)
523 {
524 if(port == 0)
525 return SWITCH_TRUE;
526 if(node->port_range.port != 0 && node->port_range.port != port)
527 return SWITCH_FALSE;
528 if(node->port_range.ports[0] != 0) {
529 int i;
530 for(i=0; i < MAX_NETWORK_PORTS && node->port_range.ports[i] != 0; i++) {
531 if(port == node->port_range.ports[i])
532 return SWITCH_TRUE;
533 }
534 return SWITCH_FALSE;
535 }
536 if(node->port_range.min_port != 0 || node->port_range.max_port != 0) {
537 if(port >= node->port_range.min_port && port <= node->port_range.max_port)
538 return SWITCH_TRUE;
539 return SWITCH_FALSE;
540 }
541 return SWITCH_TRUE;
542 }
543
544 SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip_port_token(switch_network_list_t *list, uint32_t ip, int port, const char **token)
545 {
546 switch_network_node_t *node;
547 switch_bool_t ok = list->default_type;
548 uint32_t bits = 0;
549
550 for (node = list->node_head; node; node = node->next) {
551 if (node->family == AF_INET6) continue; /* want AF_INET */
552 if (node->bits >= bits && switch_test_subnet(ip, node->ip.v4, node->mask.v4) && is_port_in_node(port, node)) {
553 if (node->ok) {
554 ok = SWITCH_TRUE;
555 } else {
556 ok = SWITCH_FALSE;
557 }
558
559 bits = node->bits;
560
561 if (token) {
562 *token = node->token;
563 }
564 }
565 }
566
567 return ok;
568 }
569
570 SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip6_token(switch_network_list_t *list, ip_t ip, const char **token)
571 {
572 return switch_network_list_validate_ip6_port_token(list, ip, 0, token);
573 }
574
575 SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip_token(switch_network_list_t *list, uint32_t ip, const char **token)
576 {
577 return switch_network_list_validate_ip_port_token(list, ip, 0, token);
578 }
579
580 SWITCH_DECLARE(char *) switch_network_ipv4_mapped_ipv6_addr(const char* ip_str)
581 {
582 /* ipv4 mapped ipv6 address */
583
584 if (strncasecmp(ip_str, "::ffff:", 7)) {
585 return NULL;
586 }
587
588 return strdup(ip_str + 7);
589 }
590
591 SWITCH_DECLARE(char*) switch_network_port_range_to_string(switch_network_port_range_p port)
592 {
593 if (!port) {
594 return NULL;
595 }
596
597 if (port->port != 0) {
598 return switch_mprintf("port: %i ", port->port);
599 }
600
601 if (port->ports[0] != 0) {
602 int i, written = 0;
603 char buf[MAX_NETWORK_PORTS * 6];
604 for (i = 0; i < MAX_NETWORK_PORTS && port->ports[i] != 0; i++) {
605 written += snprintf(buf + written, sizeof(buf) - written, (i != 0 ? ", %u" : "%u"), port->ports[i]);
606 }
607 return switch_mprintf("ports: [%s] ", buf);
608 }
609
610 if (port->min_port != 0 || port->max_port != 0) {
611 return switch_mprintf("port range: [%i-%i] ", port->min_port, port->max_port);
612 }
613
614 return NULL;
615 }
616
617 SWITCH_DECLARE(switch_status_t) switch_network_list_perform_add_cidr_token(switch_network_list_t *list, const char *cidr_str, switch_bool_t ok,
618 const char *token, switch_network_port_range_p port)
619 {
620 ip_t ip, mask;
621 uint32_t bits;
622 switch_network_node_t *node;
623 char *ipv4 = NULL;
624 char *ports = NULL;
625
626 if ((ipv4 = switch_network_ipv4_mapped_ipv6_addr(cidr_str))) {
627 cidr_str = ipv4;
628 }
629
630 ports = switch_network_port_range_to_string(port);
631
632 if (switch_parse_cidr(cidr_str, &ip, &mask, &bits)) {
633 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Adding %s %s(%s) [%s] to list %s\n",
634 cidr_str, ports ? ports : "", ok ? "allow" : "deny", switch_str_nil(token), list->name);
635 switch_safe_free(ipv4);
636 switch_safe_free(ports);
637 return SWITCH_STATUS_GENERR;
638 }
639
640 node = switch_core_alloc(list->pool, sizeof(*node));
641
642 node->ip = ip;
643 node->mask = mask;
644 node->ok = ok;
645 node->bits = bits;
646 node->str = switch_core_strdup(list->pool, cidr_str);
647 if(port) {
648 memcpy(&node->port_range, port, sizeof(switch_network_port_range_t));
649 }
650
651
652 if (strchr(cidr_str,':')) {
653 node->family = AF_INET6;
654 } else {
655 node->family = AF_INET;
656 }
657
658 if (!zstr(token)) {
659 node->token = switch_core_strdup(list->pool, token);
660 }
661
662 node->next = list->node_head;
663 list->node_head = node;
664
665 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Adding %s %s(%s) [%s] to list %s\n",
666 cidr_str, ports ? ports : "", ok ? "allow" : "deny", switch_str_nil(token), list->name);
667
668 switch_safe_free(ipv4);
669 switch_safe_free(ports);
670 return SWITCH_STATUS_SUCCESS;
671 }
672
673 SWITCH_DECLARE(switch_status_t) switch_network_list_add_cidr_port_token(switch_network_list_t *list, const char *cidr_str, switch_bool_t ok, const char *token, switch_network_port_range_p port)
674 {
675 char *cidr_str_dup = NULL;
676 switch_status_t status = SWITCH_STATUS_SUCCESS;
677
678 if (strchr(cidr_str, ',')) {
679 char *argv[32] = { 0 };
680 int i, argc;
681 cidr_str_dup = strdup(cidr_str);
682
683 switch_assert(cidr_str_dup);
684 if ((argc = switch_separate_string(cidr_str_dup, ',', argv, (sizeof(argv) / sizeof(argv[0]))))) {
685 for (i = 0; i < argc; i++) {
686 switch_status_t this_status;
687 if ((this_status = switch_network_list_perform_add_cidr_token(list, argv[i], ok, token, port)) != SWITCH_STATUS_SUCCESS) {
688 status = this_status;
689 }
690 }
691 }
692 } else {
693 status = switch_network_list_perform_add_cidr_token(list, cidr_str, ok, token, port);
694 }
695
696 switch_safe_free(cidr_str_dup);
697 return status;
698 }
699
700 SWITCH_DECLARE(switch_status_t) switch_network_list_add_cidr_token(switch_network_list_t *list, const char *cidr_str, switch_bool_t ok, const char *token)
701 {
702 return switch_network_list_add_cidr_port_token(list, cidr_str, ok, token, NULL);
703 }
704
705 SWITCH_DECLARE(switch_status_t) switch_network_list_add_host_port_mask(switch_network_list_t *list, const char *host, const char *mask_str, switch_bool_t ok, switch_network_port_range_p port)
706 {
707 ip_t ip, mask;
708 switch_network_node_t *node;
709
710 switch_inet_pton(AF_INET, host, &ip);
711 switch_inet_pton(AF_INET, mask_str, &mask);
712
713 node = switch_core_alloc(list->pool, sizeof(*node));
714
715 node->ip.v4 = ntohl(ip.v4);
716 node->mask.v4 = ntohl(mask.v4);
717 node->ok = ok;
718 if(port) {
719 memcpy(&node->port_range, port, sizeof(switch_network_port_range_t));
720 }
721
722 /* http://graphics.stanford.edu/~seander/bithacks.html */
723 mask.v4 = mask.v4 - ((mask.v4 >> 1) & 0x55555555);
724 mask.v4 = (mask.v4 & 0x33333333) + ((mask.v4 >> 2) & 0x33333333);
725 node->bits = (((mask.v4 + (mask.v4 >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
726
727 node->str = switch_core_sprintf(list->pool, "%s:%s", host, mask_str);
728
729 node->next = list->node_head;
730 list->node_head = node;
731
732 return SWITCH_STATUS_SUCCESS;
733 }
734
735 SWITCH_DECLARE(switch_status_t) switch_network_list_add_host_mask(switch_network_list_t *list, const char *host, const char *mask_str, switch_bool_t ok)
736 {
737 return switch_network_list_add_host_port_mask(list, host, mask_str, ok, NULL);
738 }
739
740
741 SWITCH_DECLARE(int) switch_parse_cidr(const char *string, ip_t *ip, ip_t *mask, uint32_t *bitp)
742 {
743 char host[128];
744 char *bit_str;
745 int32_t bits;
746 const char *ipv6;
747 ip_t *maskv = mask;
748 ip_t *ipv = ip;
749
750 switch_copy_string(host, string, sizeof(host)-1);
751 bit_str = strchr(host, '/');
752
753 if (!bit_str) {
754 return -1;
755 }
756
757 *bit_str++ = '\0';
758 bits = atoi(bit_str);
759 ipv6 = strchr(string, ':');
760 if (ipv6) {
761 int i,n;
762 if (bits < 0 || bits > 128) {
763 return -2;
764 }
765 bits = atoi(bit_str);
766 switch_inet_pton(AF_INET6, host, (unsigned char *)ip);
767 for (n=bits,i=0 ;i < 16; i++){
768 if (n >= 8) {
769 maskv->v6.s6_addr[i] = 0xFF;
770 n -= 8;
771 } else if (n < 8) {
772 maskv->v6.s6_addr[i] = 0xFF & ~(0xFF >> n);
773 n -= n;
774 } else if (n == 0) {
775 maskv->v6.s6_addr[i] = 0x00;
776 }
777 }
778 } else {
779 if (bits < 0 || bits > 32) {
780 return -2;
781 }
782
783 bits = atoi(bit_str);
784 switch_inet_pton(AF_INET, host, (unsigned char *)ip);
785 ipv->v4 = htonl(ipv->v4);
786
787 maskv->v4 = 0xFFFFFFFF & ~(0xFFFFFFFF >> bits);
788 }
789 *bitp = bits;
790
791 return 0;
792 }
793
794
795 SWITCH_DECLARE(char *) switch_find_end_paren(const char *s, char open, char close)
796 {
797 const char *e = NULL;
798 int depth = 0;
799
800 while (s && *s && *s == ' ') {
801 s++;
802 }
803
804 if (s && *s == open) {
805 depth++;
806 for (e = s + 1; e && *e; e++) {
807 if (*e == open && open != close) {
808 depth++;
809 } else if (*e == close) {
810 depth--;
811 if (!depth) {
812 break;
813 }
814 }
815 }
816 }
817
818 return (e && *e == close) ? (char *) e : NULL;
819 }
820
821 SWITCH_DECLARE(switch_size_t) switch_fd_read_line(int fd, char *buf, switch_size_t len)
822 {
823 char c, *p;
824 int cur;
825 switch_size_t total = 0;
826
827 p = buf;
828 while (total + 2 < len && (cur = read(fd, &c, 1)) == 1) {
829 total += cur;
830 *p++ = c;
831 if (c == '\r' || c == '\n') {
832 break;
833 }
834 }
835
836 *p++ = '\0';
837 assert(total < len);
838 return total;
839 }
840
841 #define DLINE_BLOCK_SIZE 1024
842 #define DLINE_MAX_SIZE 1048576
843 SWITCH_DECLARE(switch_size_t) switch_fd_read_dline(int fd, char **buf, switch_size_t *len)
844 {
845 char c, *p;
846 int cur;
847 switch_size_t total = 0;
848 char *data = *buf;
849 switch_size_t ilen = *len;
850
851 if (!data) {
852 *len = ilen = DLINE_BLOCK_SIZE;
853 data = malloc(ilen);
854 memset(data, 0, ilen);
855 }
856
857 p = data;
858 while ((cur = read(fd, &c, 1)) == 1) {
859
860 if (total + 2 >= ilen) {
861 if (ilen + DLINE_BLOCK_SIZE > DLINE_MAX_SIZE) {
862 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Single line limit reached!\n");
863 break;
864 }
865
866 ilen += DLINE_BLOCK_SIZE;
867 data = realloc(data, ilen);
868 switch_assert(data);
869 p = data + total;
870
871 }
872
873 total += cur;
874 *p++ = c;
875
876 if (c == '\r' || c == '\n') {
877 break;
878 }
879 }
880
881 *p++ = '\0';
882
883 *len = ilen;
884 *buf = data;
885
886 return total;
887 }
888
889
890
891 SWITCH_DECLARE(switch_size_t) switch_fp_read_dline(FILE *fd, char **buf, switch_size_t *len)
892 {
893 char c, *p;
894 switch_size_t total = 0;
895 char *data = *buf;
896 switch_size_t ilen = *len;
897
898 if (!data) {
899 *len = ilen = DLINE_BLOCK_SIZE;
900 data = malloc(ilen);
901 memset(data, 0, ilen);
902 }
903
904 p = data;
905 //while ((c = fgetc(fd)) != EOF) {
906
907 while (fread(&c, 1, 1, fd) == 1) {
908
909 if (total + 2 >= ilen) {
910 if (ilen + DLINE_BLOCK_SIZE > DLINE_MAX_SIZE) {
911 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Single line limit reached!\n");
912 break;
913 }
914
915 ilen += DLINE_BLOCK_SIZE;
916 data = realloc(data, ilen);
917 switch_assert(data);
918 p = data + total;
919
920 }
921
922 total++;
923 *p++ = c;
924
925 if (c == '\r' || c == '\n') {
926 break;
927 }
928 }
929
930 *p++ = '\0';
931
932 *len = ilen;
933 *buf = data;
934
935 return total;
936 }
937
938 SWITCH_DECLARE(char *) switch_amp_encode(char *s, char *buf, switch_size_t len)
939 {
940 char *p, *q;
941 switch_size_t x = 0;
942 switch_assert(s);
943
944 q = buf;
945
946 for (p = s; x < len; p++) {
947 switch (*p) {
948
949 case '"':
950 if (x + 6 > len - 1) {
951 goto end;
952 }
953 *q++ = '&';
954 *q++ = 'q';
955 *q++ = 'u';
956 *q++ = 'o';
957 *q++ = 't';
958 *q++ = ';';
959 x += 6;
960 break;
961 case '\'':
962 if (x + 6 > len - 1) {
963 goto end;
964 }
965 *q++ = '&';
966 *q++ = 'a';
967 *q++ = 'p';
968 *q++ = 'o';
969 *q++ = 's';
970 *q++ = ';';
971 x += 6;
972 break;
973 case '&':
974 if (x + 5 > len - 1) {
975 goto end;
976 }
977 *q++ = '&';
978 *q++ = 'a';
979 *q++ = 'm';
980 *q++ = 'p';
981 *q++ = ';';
982 x += 5;
983 break;
984 case '<':
985 if (x + 4 > len - 1) {
986 goto end;
987 }
988 *q++ = '&';
989 *q++ = 'l';
990 *q++ = 't';
991 *q++ = ';';
992 x += 4;
993 break;
994 case '>':
995 if (x + 4 > len - 1) {
996 goto end;
997 }
998 *q++ = '&';
999 *q++ = 'g';
1000 *q++ = 't';
1001 *q++ = ';';
1002 x += 4;
1003 break;
1004 default:
1005 if (x + 1 > len - 1) {
1006 goto end;
1007 }
1008 *q++ = *p;
1009 x++;
1010 if (*p == '\0') {
1011 goto end;
1012 }
1013 break;
1014 }
1015 }
1016
1017 end:
1018
1019 return buf;
1020 }
1021
1022 static const char switch_b64_table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1023 #define B64BUFFLEN 1024
1024 SWITCH_DECLARE(switch_status_t) switch_b64_encode(unsigned char *in, switch_size_t ilen, unsigned char *out, switch_size_t olen)
1025 {
1026 int y = 0, bytes = 0;
1027 size_t x = 0;
1028 unsigned int b = 0, l = 0;
1029
1030 for (x = 0; x < ilen; x++) {
1031 b = (b << 8) + in[x];
1032 l += 8;
1033
1034 while (l >= 6) {
1035 out[bytes++] = switch_b64_table[(b >> (l -= 6)) % 64];
1036 if (bytes >= (int)olen - 1) {
1037 goto end;
1038 }
1039 if (++y != 72) {
1040 continue;
1041 }
1042 /* out[bytes++] = '\n'; */
1043 y = 0;
1044 }
1045 }
1046
1047 if (l > 0) {
1048 out[bytes++] = switch_b64_table[((b % 16) << (6 - l)) % 64];
1049 }
1050 if (l != 0) {
1051 while (l < 6 && bytes < (int)olen - 1) {
1052 out[bytes++] = '=', l += 2;
1053 }
1054 }
1055
1056 end:
1057
1058 out[bytes] = '\0';
1059
1060 return SWITCH_STATUS_SUCCESS;
1061 }
1062
1063 SWITCH_DECLARE(switch_size_t) switch_b64_decode(const char *in, char *out, switch_size_t olen)
1064 {
1065
1066 char l64[256];
1067 int b = 0, c, l = 0, i;
1068 const char *ip;
1069 char *op = out;
1070 size_t ol = 0;
1071
1072 for (i = 0; i < 256; i++) {
1073 l64[i] = -1;
1074 }
1075
1076 for (i = 0; i < 64; i++) {
1077 l64[(int) switch_b64_table[i]] = (char) i;
1078 }
1079
1080 for (ip = in; ip && *ip; ip++) {
1081 c = l64[(int) *ip];
1082 if (c == -1) {
1083 continue;
1084 }
1085
1086 b = (b << 6) + c;
1087 l += 6;
1088
1089 while (l >= 8) {
1090 op[ol++] = (char) ((b >> (l -= 8)) % 256);
1091 if (ol >= olen - 1) {
1092 goto end;
1093 }
1094 }
1095 }
1096
1097 end:
1098
1099 op[ol++] = '\0';
1100
1101 return ol;
1102 }
1103
1104 static int write_buf(int fd, const char *buf)
1105 {
1106
1107 int len = (int) strlen(buf);
1108 if (fd && write(fd, buf, len) != len) {
1109 close(fd);
1110 return 0;
1111 }
1112
1113 return 1;
1114 }
1115
1116 SWITCH_DECLARE(switch_bool_t) switch_simple_email(const char *to,
1117 const char *from,
1118 const char *headers,
1119 const char *body, const char *file, const char *convert_cmd, const char *convert_ext)
1120 {
1121 char *bound = "XXXX_boundary_XXXX";
1122 const char *mime_type = "audio/inline";
1123 char filename[80], buf[B64BUFFLEN];
1124 int fd = -1, ifd = -1;
1125 int x = 0, y = 0, bytes = 0, ilen = 0;
1126 unsigned int b = 0, l = 0;
1127 unsigned char in[B64BUFFLEN];
1128 unsigned char out[B64BUFFLEN + 512];
1129 char *dupfile = NULL, *ext = NULL;
1130 char *newfile = NULL;
1131 switch_bool_t rval = SWITCH_FALSE;
1132 const char *err = NULL;
1133
1134 filename[0] = '\0';
1135
1136 if (zstr(to)) {
1137 err = "No to address specified";
1138 goto end;
1139 }
1140
1141 if (!zstr(file) && !zstr(convert_cmd) && !zstr(convert_ext)) {
1142 if (strrchr(file, '.')) {
1143 dupfile = strdup(file);
1144 if ((ext = strrchr(dupfile, '.'))) {
1145 *ext++ = '\0';
1146 newfile = switch_mprintf("%s.%s", dupfile, convert_ext);
1147 }
1148 }
1149
1150 if (newfile) {
1151 char cmd[1024] = "";
1152 switch_snprintf(cmd, sizeof(cmd), "%s %s %s", convert_cmd, file, newfile);
1153 switch_system(cmd, SWITCH_TRUE);
1154 if (strcmp(file, newfile)) {
1155 file = newfile;
1156 } else {
1157 switch_safe_free(newfile);
1158 }
1159 }
1160
1161 switch_safe_free(dupfile);
1162 }
1163
1164 switch_snprintf(filename, 80, "%s%smail.%d%04x", SWITCH_GLOBAL_dirs.temp_dir, SWITCH_PATH_SEPARATOR, (int) switch_epoch_time_now(NULL), rand() & 0xffff);
1165
1166 if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644)) > -1) {
1167 if (file) {
1168 if ((ifd = open(file, O_RDONLY | O_BINARY)) < 0) {
1169 rval = SWITCH_FALSE;
1170 err = "Cannot open tmp file\n";
1171 goto end;
1172 }
1173 }
1174
1175 if (!file && (!body || !switch_stristr("content-type", body))) {
1176 bound = NULL;
1177 }
1178
1179 if (bound) {
1180 switch_snprintf(buf, B64BUFFLEN, "MIME-Version: 1.0\nContent-Type: multipart/mixed; boundary=\"%s\"\n", bound);
1181 if (!write_buf(fd, buf)) {
1182 rval = SWITCH_FALSE;
1183 err = "write error.";
1184 goto end;
1185 }
1186 }
1187
1188 if (headers && !write_buf(fd, headers)) {
1189 rval = SWITCH_FALSE;
1190 err = "write error.";
1191 goto end;
1192 }
1193
1194 if (!write_buf(fd, "\n\n")) {
1195 rval = SWITCH_FALSE;
1196 err = "write error.";
1197 goto end;
1198 }
1199
1200 if (bound) {
1201 if (body && switch_stristr("content-type", body)) {
1202 switch_snprintf(buf, B64BUFFLEN, "--%s\n", bound);
1203 } else {
1204 switch_snprintf(buf, B64BUFFLEN, "--%s\nContent-Type: text/plain\n\n", bound);
1205 }
1206 if (!write_buf(fd, buf)) {
1207 rval = SWITCH_FALSE;
1208 err = "write error.";
1209 goto end;
1210 }
1211 }
1212
1213 if (body) {
1214 if (!write_buf(fd, body)) {
1215 rval = SWITCH_FALSE;
1216 err = "write error.";
1217 goto end;
1218 }
1219 }
1220
1221 if (file && bound) {
1222 const char *stipped_file = switch_cut_path(file);
1223 const char *new_type;
1224 char *ext;
1225
1226 if ((ext = strrchr(stipped_file, '.'))) {
1227 ext++;
1228 if ((new_type = switch_core_mime_ext2type(ext))) {
1229 mime_type = new_type;
1230 }
1231 }
1232
1233 switch_snprintf(buf, B64BUFFLEN,
1234 "\n\n--%s\nContent-Type: %s; name=\"%s\"\n"
1235 "Content-ID: <ATTACHED@freeswitch.org>\n"
1236 "Content-Transfer-Encoding: base64\n"
1237 "Content-Description: Sound attachment.\n"
1238 "Content-Disposition: attachment; filename=\"%s\"\n\n", bound, mime_type, stipped_file, stipped_file);
1239 if (!write_buf(fd, buf)) {
1240 rval = SWITCH_FALSE;
1241 err = "write error.";
1242 goto end;
1243 }
1244
1245 while ((ilen = read(ifd, in, B64BUFFLEN))) {
1246 for (x = 0; x < ilen; x++) {
1247 b = (b << 8) + in[x];
1248 l += 8;
1249 while (l >= 6) {
1250 out[bytes++] = switch_b64_table[(b >> (l -= 6)) % 64];
1251 if (++y != 72)
1252 continue;
1253 out[bytes++] = '\n';
1254 y = 0;
1255 }
1256 }
1257 if (write(fd, &out, bytes) != bytes) {
1258 rval = -1;
1259 break;
1260 } else {
1261 bytes = 0;
1262 }
1263
1264 }
1265
1266 if (l > 0) {
1267 out[bytes++] = switch_b64_table[((b % 16) << (6 - l)) % 64];
1268 }
1269 if (l != 0)
1270 while (l < 6) {
1271 out[bytes++] = '=', l += 2;
1272 }
1273 if (write(fd, &out, bytes) != bytes) {
1274 rval = -1;
1275 }
1276
1277 }
1278
1279 if (bound) {
1280 switch_snprintf(buf, B64BUFFLEN, "\n\n--%s--\n.\n", bound);
1281
1282 if (!write_buf(fd, buf)) {
1283 rval = SWITCH_FALSE;
1284 err = "write error.";
1285 goto end;
1286 }
1287 }
1288 }
1289
1290 if (fd > -1) {
1291 close(fd);
1292 fd = -1;
1293 }
1294
1295 if (zstr(from)) {
1296 from = "freeswitch";
1297 }
1298
1299 {
1300 char *to_arg = switch_util_quote_shell_arg(to);
1301 char *from_arg = switch_util_quote_shell_arg(from);
1302 #ifdef WIN32
1303 switch_snprintf(buf, B64BUFFLEN, "\"\"%s\" -f %s %s %s < \"%s\"\"", runtime.mailer_app, from_arg, runtime.mailer_app_args, to_arg, filename);
1304 #else
1305 switch_snprintf(buf, B64BUFFLEN, "/bin/cat %s | %s -f %s %s %s", filename, runtime.mailer_app, from_arg, runtime.mailer_app_args, to_arg);
1306 #endif
1307 switch_safe_free(to_arg); switch_safe_free(from_arg);
1308 }
1309 if (switch_system(buf, SWITCH_TRUE) < 0) {
1310 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to execute command: %s\n", buf);
1311 err = "execute error";
1312 rval = SWITCH_FALSE;
1313 }
1314
1315 if (zstr(err)) {
1316 if (file) {
1317 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Emailed file [%s] to [%s]\n", filename, to);
1318 } else {
1319 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Emailed data to [%s]\n", to);
1320 }
1321
1322 rval = SWITCH_TRUE;
1323 }
1324
1325 end:
1326
1327 if (fd > -1) {
1328 close(fd);
1329 }
1330
1331 if (!zstr_buf(filename) && unlink(filename) != 0) {
1332 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to delete file [%s]\n", filename);
1333 }
1334
1335 if (ifd > -1) {
1336 close(ifd);
1337 }
1338
1339
1340 if (newfile) {
1341 unlink(newfile);
1342 free(newfile);
1343 }
1344
1345 if (rval != SWITCH_TRUE) {
1346 if (zstr(err)) err = "Unknown Error";
1347
1348 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "EMAIL NOT SENT, error [%s]\n", err);
1349 }
1350
1351 return rval;
1352 }
1353
1354 SWITCH_DECLARE(switch_bool_t) switch_is_lan_addr(const char *ip)
1355 {
1356 if (zstr(ip))
1357 return SWITCH_FALSE;
1358
1359 return (strncmp(ip, "10.", 3) && /* 10.0.0.0 - 10.255.255.255 (10/8 prefix) */
1360 strncmp(ip, "192.168.", 8) && /* 192.168.0.0 - 192.168.255.255 (192.168/16 prefix) */
1361 strncmp(ip, "127.", 4) && /* 127.0.0.0 - 127.255.255.255 (127/8 prefix) */
1362 strncmp(ip, "255.", 4) &&
1363 strncmp(ip, "0.", 2) &&
1364 strncmp(ip, "1.", 2) &&
1365 strncmp(ip, "2.", 2) &&
1366 strncmp(ip, "172.16.", 7) && /* 172.16.0.0 - 172.31.255.255 (172.16/12 prefix) */
1367 strncmp(ip, "172.17.", 7) &&
1368 strncmp(ip, "172.18.", 7) &&
1369 strncmp(ip, "172.19.", 7) &&
1370 strncmp(ip, "172.20.", 7) &&
1371 strncmp(ip, "172.21.", 7) &&
1372 strncmp(ip, "172.22.", 7) &&
1373 strncmp(ip, "172.23.", 7) &&
1374 strncmp(ip, "172.24.", 7) &&
1375 strncmp(ip, "172.25.", 7) &&
1376 strncmp(ip, "172.26.", 7) &&
1377 strncmp(ip, "172.27.", 7) &&
1378 strncmp(ip, "172.28.", 7) &&
1379 strncmp(ip, "172.29.", 7) &&
1380 strncmp(ip, "172.30.", 7) &&
1381 strncmp(ip, "172.31.", 7) &&
1382 strncmp(ip, "192.0.2.", 8) && /* 192.0.2.0 - 192.0.2.255 (192.0.2/24 prefix) */
1383 strncmp(ip, "169.254.", 8) /* 169.254.0.0 - 169.254.255.255 (169.254/16 prefix) */
1384 )? SWITCH_FALSE : SWITCH_TRUE;
1385 }
1386
1387 SWITCH_DECLARE(switch_bool_t) switch_ast2regex(const char *pat, char *rbuf, size_t len)
1388 {
1389 const char *p = pat;
1390
1391 if (!pat) {
1392 return SWITCH_FALSE;
1393 }
1394
1395 memset(rbuf, 0, len);
1396
1397 *(rbuf + strlen(rbuf)) = '^';
1398
1399 while (p && *p) {
1400 if (*p == 'N') {
1401 strncat(rbuf, "[2-9]", len - strlen(rbuf));
1402 } else if (*p == 'X') {
1403 strncat(rbuf, "[0-9]", len - strlen(rbuf));
1404 } else if (*p == 'Z') {
1405 strncat(rbuf, "[1-9]", len - strlen(rbuf));
1406 } else if (*p == '.') {
1407 strncat(rbuf, ".*", len - strlen(rbuf));
1408 } else if (strlen(rbuf) < len - 1) {
1409 *(rbuf + strlen(rbuf)) = *p;
1410 }
1411 p++;
1412 }
1413 *(rbuf + strlen(rbuf)) = '$';
1414
1415 return strcmp(pat, rbuf) ? SWITCH_TRUE : SWITCH_FALSE;
1416 }
1417
1418 SWITCH_DECLARE(char *) switch_replace_char(char *str, char from, char to, switch_bool_t dup)
1419 {
1420 char *p;
1421
1422 if (dup) {
1423 p = strdup(str);
1424 switch_assert(p);
1425 } else {
1426 p = str;
1427 }
1428
1429 for (; p && *p; p++) {
1430 if (*p == from) {
1431 *p = to;
1432 }
1433 }
1434
1435 return p;
1436 }
1437
1438 SWITCH_DECLARE(char *) switch_pool_strip_whitespace(switch_memory_pool_t *pool, const char *str)
1439 {
1440 const char *sp = str;
1441 char *p, *s = NULL;
1442 size_t len;
1443
1444 if (zstr(sp)) {
1445 return switch_core_strdup(pool, SWITCH_BLANK_STRING);
1446 }
1447
1448 while ((*sp == 13 ) || (*sp == 10 ) || (*sp == 9 ) || (*sp == 32) || (*sp == 11) ) {
1449 sp++;
1450 }
1451
1452 if (zstr(sp)) {
1453 return switch_core_strdup(pool, SWITCH_BLANK_STRING);
1454 }
1455
1456 s = switch_core_strdup(pool, sp);
1457 switch_assert(s);
1458
1459 if ((len = strlen(s)) > 0) {
1460 p = s + (len - 1);
1461
1462 while ((p >= s) && ((*p == 13 ) || (*p == 10 ) || (*p == 9 ) || (*p == 32) || (*p == 11))) {
1463 *p-- = '\0';
1464 }
1465 }
1466
1467 return s;
1468 }
1469
1470 SWITCH_DECLARE(char *) switch_strip_whitespace(const char *str)
1471 {
1472 const char *sp = str;
1473 char *p, *s = NULL;
1474 size_t len;
1475
1476 if (zstr(sp)) {
1477 return strdup(SWITCH_BLANK_STRING);
1478 }
1479
1480 while ((*sp == 13 ) || (*sp == 10 ) || (*sp == 9 ) || (*sp == 32) || (*sp == 11) ) {
1481 sp++;
1482 }
1483
1484 if (zstr(sp)) {
1485 return strdup(SWITCH_BLANK_STRING);
1486 }
1487
1488 s = strdup(sp);
1489 switch_assert(s);
1490
1491 if ((len = strlen(s)) > 0) {
1492 p = s + (len - 1);
1493
1494 while ((p >= s) && ((*p == 13 ) || (*p == 10 ) || (*p == 9 ) || (*p == 32) || (*p == 11))) {
1495 *p-- = '\0';
1496 }
1497 }
1498
1499 return s;
1500 }
1501
1502 SWITCH_DECLARE(char *) switch_strip_spaces(char *str, switch_bool_t dup)
1503 {
1504 char *sp = str;
1505 char *p, *s = NULL;
1506 size_t len;
1507
1508 if (zstr(sp)) {
1509 return dup ? strdup(SWITCH_BLANK_STRING) : sp;
1510 }
1511
1512 while (*sp == ' ') {
1513 sp++;
1514 }
1515
1516 if (dup) {
1517 s = strdup(sp);
1518 switch_assert(s);
1519 } else {
1520 s = sp;
1521 }
1522
1523 if (zstr(s)) {
1524 return s;
1525 }
1526
1527 if ((len = strlen(s)) > 0) {
1528 p = s + (len - 1);
1529
1530 while (p && *p && (p >= s) && *p == ' ') {
1531 *p-- = '\0';
1532 }
1533 }
1534
1535 return s;
1536 }
1537
1538 SWITCH_DECLARE(char *) switch_strip_commas(char *in, char *out, switch_size_t len)
1539 {
1540 char *p = in, *q = out;
1541 char *ret = out;
1542 switch_size_t x = 0;
1543
1544 for (; p && *p; p++) {
1545 if ((*p > 47 && *p < 58)) {
1546 *q++ = *p;
1547
1548 if (++x > len) {
1549 ret = NULL;
1550 break;
1551 }
1552 } else if (*p != ',') {
1553 ret = NULL;
1554 break;
1555 }
1556 }
1557
1558 return ret;
1559 }
1560
1561 SWITCH_DECLARE(char *) switch_strip_nonnumerics(char *in, char *out, switch_size_t len)
1562 {
1563 char *p = in, *q = out;
1564 char *ret = out;
1565 switch_size_t x = 0;
1566 /* valid are 0 - 9, period (.), minus (-), and plus (+) - remove all others */
1567 for (; p && *p; p++) {
1568 if ((*p > 47 && *p < 58) || *p == '.' || *p == '-' || *p == '+') {
1569 *q++ = *p;
1570
1571 if (++x > len) {
1572 ret = NULL;
1573 break;
1574 }
1575 }
1576 }
1577
1578 return ret;
1579 }
1580
1581 SWITCH_DECLARE(char *) switch_separate_paren_args(char *str)
1582 {
1583 char *e, *args;
1584 switch_size_t br;
1585
1586 if ((args = strchr(str, '('))) {
1587 e = args - 1;
1588 *args++ = '\0';
1589 while (*e == ' ') {
1590 *e-- = '\0';
1591 }
1592 e = args;
1593 br = 1;
1594 while (e && *e) {
1595 if (*e == '(') {
1596 br++;
1597 } else if (br > 1 && *e == ')') {
1598 br--;
1599 } else if (br == 1 && *e == ')') {
1600 *e = '\0';
1601 break;
1602 }
1603 e++;
1604 }
1605 }
1606
1607 return args;
1608 }
1609
1610 SWITCH_DECLARE(switch_bool_t) switch_is_number(const char *str)
1611 {
1612 const char *p;
1613 switch_bool_t r = SWITCH_TRUE;
1614
1615 if (*str == '-' || *str == '+') {
1616 str++;
1617 }
1618
1619 for (p = str; p && *p; p++) {
1620 if (!(*p == '.' || (*p > 47 && *p < 58))) {
1621 r = SWITCH_FALSE;
1622 break;
1623 }
1624 }
1625
1626 return r;
1627 }
1628
1629 SWITCH_DECLARE(switch_bool_t) switch_is_leading_number(const char *str)
1630 {
1631 const char *p;
1632 switch_bool_t r = SWITCH_FALSE;
1633
1634 if (*str == '-' || *str == '+') {
1635 str++;
1636 }
1637
1638 for (p = str; p && *p; p++) {
1639 if ((*p == '.' || (*p > 47 && *p < 58))) {
1640 r = SWITCH_TRUE;
1641 break;
1642 }
1643 }
1644
1645 return r;
1646 }
1647
1648 SWITCH_DECLARE(const char *) switch_stristr(const char *instr, const char *str)
1649 {
1650 /*
1651 ** Rev History: 16/07/97 Greg Thayer Optimized
1652 ** 07/04/95 Bob Stout ANSI-fy
1653 ** 02/03/94 Fred Cole Original
1654 ** 09/01/03 Bob Stout Bug fix (lines 40-41) per Fred Bulback
1655 **
1656 ** Hereby donated to public domain.
1657 */
1658 const char *pptr, *sptr, *start;
1659
1660 if (!str || !instr)
1661 return NULL;
1662
1663 for (start = str; *start; start++) {
1664 /* find start of pattern in string */
1665 for (; ((*start) && (switch_toupper(*start) != switch_toupper(*instr))); start++);
1666
1667 if (!*start)
1668 return NULL;
1669
1670 pptr = instr;
1671 sptr = start;
1672
1673 while (switch_toupper(*sptr) == switch_toupper(*pptr)) {
1674 sptr++;
1675 pptr++;
1676
1677 /* if end of pattern then pattern was found */
1678 if (!*pptr)
1679 return (start);
1680
1681 if (!*sptr)
1682 return NULL;
1683 }
1684 }
1685 return NULL;
1686 }
1687
1688 #ifdef HAVE_GETIFADDRS
1689 #include <ifaddrs.h>
1690 static int get_netmask(struct sockaddr_in *me, int *mask)
1691 {
1692 struct ifaddrs *ifaddrs, *i = NULL;
1693
1694 if (!me || getifaddrs(&ifaddrs) < 0) {
1695 return -1;
1696 }
1697
1698 for (i = ifaddrs; i; i = i->ifa_next) {
1699 struct sockaddr_in *s = (struct sockaddr_in *) i->ifa_addr;
1700 struct sockaddr_in *m = (struct sockaddr_in *) i->ifa_netmask;
1701
1702 if (s && m && s->sin_family == AF_INET && s->sin_addr.s_addr == me->sin_addr.s_addr) {
1703 *mask = m->sin_addr.s_addr;
1704 freeifaddrs(ifaddrs);
1705 return 0;
1706 }
1707 }
1708
1709 freeifaddrs(ifaddrs);
1710
1711 return -2;
1712 }
1713 #elif defined(__linux__)
1714
1715 #include <sys/ioctl.h>
1716 #include <net/if.h>
1717 static int get_netmask(struct sockaddr_in *me, int *mask)
1718 {
1719
1720 static struct ifreq ifreqs[20] = { {{{0}}} };
1721 struct ifconf ifconf;
1722 int nifaces, i;
1723 int sock;
1724 int r = -1;
1725
1726 memset(&ifconf, 0, sizeof(ifconf));
1727 ifconf.ifc_buf = (char *) (ifreqs);
1728 ifconf.ifc_len = sizeof(ifreqs);
1729
1730
1731 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
1732 goto end;
1733 }
1734
1735 if (ioctl(sock, SIOCGIFCONF, (char *) &ifconf) < 0) {
1736 goto end;
1737 }
1738
1739 nifaces = ifconf.ifc_len / sizeof(struct ifreq);
1740
1741 for (i = 0; i < nifaces; i++) {
1742 struct sockaddr_in *sin = NULL;
1743 struct in_addr ip;
1744
1745 ioctl(sock, SIOCGIFADDR, &ifreqs[i]);
1746 sin = (struct sockaddr_in *) &ifreqs[i].ifr_addr;
1747 ip = sin->sin_addr;
1748
1749 if (ip.s_addr == me->sin_addr.s_addr) {
1750 ioctl(sock, SIOCGIFNETMASK, &ifreqs[i]);
1751 sin = (struct sockaddr_in *) &ifreqs[i].ifr_addr;
1752 /* mask = sin->sin_addr; */
1753 *mask = sin->sin_addr.s_addr;
1754 r = 0;
1755 break;
1756 }
1757
1758 }
1759
1760 end:
1761
1762 close(sock);
1763 return r;
1764
1765 }
1766
1767 #elif defined(WIN32)
1768
1769 static int get_netmask(struct sockaddr_in *me, int *mask)
1770 {
1771 SOCKET sock = WSASocket(AF_INET, SOCK_DGRAM, 0, 0, 0, 0);
1772 INTERFACE_INFO interfaces[20];
1773 unsigned long bytes;
1774 int interface_count, x;
1775 int r = -1;
1776
1777 *mask = 0;
1778
1779 if (sock == SOCKET_ERROR) {
1780 return -1;
1781 }
1782
1783 if (WSAIoctl(sock, SIO_GET_INTERFACE_LIST, 0, 0, &interfaces, sizeof(interfaces), &bytes, 0, 0) == SOCKET_ERROR) {
1784 r = -1;
1785 goto end;
1786 }
1787
1788 interface_count = bytes / sizeof(INTERFACE_INFO);
1789
1790 for (x = 0; x < interface_count; ++x) {
1791 struct sockaddr_in *addr = (struct sockaddr_in *) &(interfaces[x].iiAddress);
1792
1793 if (addr->sin_addr.s_addr == me->sin_addr.s_addr) {
1794 struct sockaddr_in *netmask = (struct sockaddr_in *) &(interfaces[x].iiNetmask);
1795 *mask = netmask->sin_addr.s_addr;
1796 r = 0;
1797 break;
1798 }
1799 }
1800
1801 end:
1802 closesocket(sock);
1803 return r;
1804 }
1805
1806 #else
1807
1808 static int get_netmask(struct sockaddr_in *me, int *mask)
1809 {
1810 return -1;
1811 }
1812
1813 #endif
1814
1815
1816 SWITCH_DECLARE(switch_status_t) switch_resolve_host(const char *host, char *buf, size_t buflen)
1817 {
1818
1819 struct addrinfo *ai;
1820
1821 if (getaddrinfo(host, 0, 0, &ai)) {
1822 return SWITCH_STATUS_FALSE;
1823 }
1824
1825 get_addr(buf, buflen, ai->ai_addr, sizeof(struct sockaddr_storage));
1826
1827 freeaddrinfo(ai);
1828
1829 return SWITCH_STATUS_SUCCESS;
1830 }
1831
1832
1833 SWITCH_DECLARE(switch_status_t) switch_find_local_ip(char *buf, int len, int *mask, int family)
1834 {
1835 switch_status_t status = SWITCH_STATUS_FALSE;
1836 char *base;
1837 char *force_local_ip_v4 = switch_core_get_variable_dup("force_local_ip_v4");
1838 char *force_local_ip_v6 = switch_core_get_variable_dup("force_local_ip_v6");
1839
1840 #ifdef WIN32
1841 SOCKET tmp_socket;
1842 SOCKADDR_STORAGE l_address;
1843 int l_address_len;
1844 struct addrinfo *address_info;
1845 #else
1846 #ifdef __Darwin__
1847 int ilen;
1848 #else
1849 unsigned int ilen;
1850 #endif
1851 int tmp_socket = -1, on = 1;
1852 char abuf[25] = "";
1853 #endif
1854
1855 switch (family) {
1856 case AF_INET:
1857 if (force_local_ip_v4) {
1858 switch_copy_string(buf, force_local_ip_v4, len);
1859 switch_safe_free(force_local_ip_v4);
1860 switch_safe_free(force_local_ip_v6);
1861 return SWITCH_STATUS_SUCCESS;
1862 }
1863 case AF_INET6:
1864 if (force_local_ip_v6) {
1865 switch_copy_string(buf, force_local_ip_v6, len);
1866 switch_safe_free(force_local_ip_v4);
1867 switch_safe_free(force_local_ip_v6);
1868 return SWITCH_STATUS_SUCCESS;
1869 }
1870 default:
1871 switch_safe_free(force_local_ip_v4);
1872 switch_safe_free(force_local_ip_v6);
1873 break;
1874 }
1875
1876
1877 if (len < 16) {
1878 return status;
1879 }
1880
1881 switch (family) {
1882 case AF_INET:
1883 switch_copy_string(buf, "127.0.0.1", len);
1884 base = "82.45.148.209";
1885 break;
1886 case AF_INET6:
1887 switch_copy_string(buf, "::1", len);
1888 base = "2001:503:BA3E::2:30"; /* DNS Root server A */
1889 break;
1890 default:
1891 base = "127.0.0.1";
1892 break;
1893 }
1894
1895 #ifdef WIN32
1896 tmp_socket = socket(family, SOCK_DGRAM, 0);
1897
1898 getaddrinfo(base, NULL, NULL, &address_info);
1899
1900 if (!address_info || WSAIoctl(tmp_socket,
1901 SIO_ROUTING_INTERFACE_QUERY,
1902 address_info->ai_addr, (DWORD) address_info->ai_addrlen, &l_address, sizeof(l_address), (LPDWORD) & l_address_len, NULL,
1903 NULL)) {
1904
1905 closesocket(tmp_socket);
1906 if (address_info)
1907 freeaddrinfo(address_info);
1908 return status;
1909 }
1910
1911
1912 closesocket(tmp_socket);
1913 freeaddrinfo(address_info);
1914
1915 if (!getnameinfo((const struct sockaddr *) &l_address, l_address_len, buf, len, NULL, 0, NI_NUMERICHOST)) {
1916 status = SWITCH_STATUS_SUCCESS;
1917 if (mask) {
1918 get_netmask((struct sockaddr_in *) &l_address, mask);
1919 }
1920 }
1921 #else
1922
1923 switch (family) {
1924 case AF_INET:
1925 {
1926 struct sockaddr_in iface_out;
1927 struct sockaddr_in remote;
1928 memset(&remote, 0, sizeof(struct sockaddr_in));
1929
1930 remote.sin_family = AF_INET;
1931 remote.sin_addr.s_addr = inet_addr(base);
1932 remote.sin_port = htons(4242);
1933
1934 memset(&iface_out, 0, sizeof(iface_out));
1935 if ( (tmp_socket = socket(AF_INET, SOCK_DGRAM, 0)) == -1 ) {
1936 goto doh;
1937 }
1938
1939 if (setsockopt(tmp_socket, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) == -1) {
1940 goto doh;
1941 }
1942
1943 if (connect(tmp_socket, (struct sockaddr *) &remote, sizeof(struct sockaddr_in)) == -1) {
1944 goto doh;
1945 }
1946
1947 ilen = sizeof(iface_out);
1948 if (getsockname(tmp_socket, (struct sockaddr *) &iface_out, &ilen) == -1) {
1949 goto doh;
1950 }
1951
1952 if (iface_out.sin_addr.s_addr == 0) {
1953 goto doh;
1954 }
1955
1956 switch_copy_string(buf, get_addr(abuf, sizeof(abuf), (struct sockaddr *) &iface_out, sizeof(struct sockaddr_storage)), len);
1957 if (mask) {
1958 get_netmask((struct sockaddr_in *) &iface_out, mask);
1959 }
1960
1961 status = SWITCH_STATUS_SUCCESS;
1962 }
1963 break;
1964 case AF_INET6:
1965 {
1966 struct sockaddr_in6 iface_out;
1967 struct sockaddr_in6 remote;
1968 memset(&remote, 0, sizeof(struct sockaddr_in6));
1969
1970 remote.sin6_family = AF_INET6;
1971 switch_inet_pton(AF_INET6, base, &remote.sin6_addr);
1972 remote.sin6_port = htons(4242);
1973
1974 memset(&iface_out, 0, sizeof(iface_out));
1975 if ( (tmp_socket = socket(AF_INET6, SOCK_DGRAM, 0)) == -1 ) {
1976 goto doh;
1977 }
1978
1979 if (connect(tmp_socket, (struct sockaddr *) &remote, sizeof(remote)) == -1) {
1980 goto doh;
1981 }
1982
1983 ilen = sizeof(iface_out);
1984 if (getsockname(tmp_socket, (struct sockaddr *) &iface_out, &ilen) == -1) {
1985 goto doh;
1986 }
1987
1988 inet_ntop(AF_INET6, (const void *) &iface_out.sin6_addr, buf, len - 1);
1989 status = SWITCH_STATUS_SUCCESS;
1990 }
1991 break;
1992 }
1993
1994 doh:
1995 if (tmp_socket > 0) {
1996 close(tmp_socket);
1997 }
1998 #endif
1999
2000 return status;
2001 }
2002
2003 #ifdef HAVE_GETIFADDRS
2004 # include <ifaddrs.h>
2005 # include <net/if.h>
2006 #endif
2007 SWITCH_DECLARE(switch_status_t) switch_find_interface_ip(char *buf, int len, int *mask, const char *ifname, int family)
2008 {
2009 switch_status_t status = SWITCH_STATUS_FALSE;
2010
2011 #ifdef HAVE_GETIFADDRS
2012
2013 struct ifaddrs *addrs, *addr;
2014
2015 getifaddrs(&addrs);
2016 for(addr = addrs; addr; addr = addr->ifa_next)
2017 {
2018 if (!(addr->ifa_flags & IFF_UP)) continue; // Address is not UP
2019 if (!addr->ifa_addr) continue; // No address set
2020 if (!addr->ifa_netmask) continue; // No netmask set
2021 if (family != AF_UNSPEC && addr->ifa_addr->sa_family != family) continue; // Not the address family we're looking for
2022 if (strcmp(addr->ifa_name, ifname)) continue; // Not the interface we're looking for
2023
2024 switch(addr->ifa_addr->sa_family) {
2025 case AF_INET:
2026 inet_ntop(AF_INET, &( ((struct sockaddr_in*)(addr->ifa_addr))->sin_addr ), buf, len - 1);
2027 break;
2028 case AF_INET6:
2029 inet_ntop(AF_INET6, &( ((struct sockaddr_in6*)(addr->ifa_addr))->sin6_addr ), buf, len - 1);
2030 break;
2031 default:
2032 continue;
2033 }
2034
2035 if (mask && addr->ifa_netmask->sa_family == AF_INET) {
2036 *mask = ((struct sockaddr_in*)(addr->ifa_addr))->sin_addr.s_addr;
2037 }
2038
2039 status = SWITCH_STATUS_SUCCESS;
2040 break;
2041 }
2042 freeifaddrs(addrs);
2043
2044 #elif defined(__linux__)
2045
2046 // TODO Not implemented, contributions welcome.
2047
2048 #elif defined(WIN32)
2049
2050 // TODO Not implemented, contributions welcome.
2051
2052 #endif
2053
2054 return status;
2055 }
2056
2057
2058 SWITCH_DECLARE(switch_time_t) switch_str_time(const char *in)
2059 {
2060 switch_time_exp_t tm = { 0 }, local_tm = { 0 };
2061 int proceed = 0, ovector[30], time_only = 0;
2062 switch_regex_t *re = NULL;
2063 char replace[1024] = "";
2064 switch_time_t ret = 0, local_time = 0;
2065 char *pattern = "^(\\d+)-(\\d+)-(\\d+)\\s*(\\d*):{0,1}(\\d*):{0,1}(\\d*)";
2066 char *pattern2 = "^(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})";
2067 char *pattern3 = "^(\\d*):{0,1}(\\d*):{0,1}(\\d*)$";
2068
2069 switch_time_exp_lt(&tm, switch_micro_time_now());
2070
2071
2072 if ((time_only = switch_regex_perform(in, pattern3, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
2073 tm.tm_hour = 0;
2074 tm.tm_min = 0;
2075 tm.tm_sec = 0;
2076 } else {
2077 tm.tm_year = tm.tm_mon = tm.tm_mday = tm.tm_hour = tm.tm_min = tm.tm_sec = tm.tm_usec = 0;
2078
2079 if (!(proceed = switch_regex_perform(in, pattern, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
2080 switch_regex_safe_free(re);
2081 proceed = switch_regex_perform(in, pattern2, &re, ovector, sizeof(ovector) / sizeof(ovector[0]));
2082 }
2083 }
2084
2085 if (proceed || time_only) {
2086
2087 if (time_only > 1) {
2088 switch_regex_copy_substring(in, ovector, time_only, 1, replace, sizeof(replace));
2089 tm.tm_hour = atoi(replace);
2090 }
2091
2092 if (time_only > 2) {
2093 switch_regex_copy_substring(in, ovector, time_only, 2, replace, sizeof(replace));
2094 tm.tm_min = atoi(replace);
2095 }
2096
2097 if (time_only > 3) {
2098 switch_regex_copy_substring(in, ovector, time_only, 3, replace, sizeof(replace));
2099 tm.tm_sec = atoi(replace);
2100 }
2101
2102 if (proceed > 1) {
2103 switch_regex_copy_substring(in, ovector, proceed, 1, replace, sizeof(replace));
2104 tm.tm_year = atoi(replace) - 1900;
2105 }
2106
2107 if (proceed > 2) {
2108 switch_regex_copy_substring(in, ovector, proceed, 2, replace, sizeof(replace));
2109 tm.tm_mon = atoi(replace) - 1;
2110 }
2111
2112 if (proceed > 3) {
2113 switch_regex_copy_substring(in, ovector, proceed, 3, replace, sizeof(replace));
2114 tm.tm_mday = atoi(replace);
2115 }
2116
2117 if (proceed > 4) {
2118 switch_regex_copy_substring(in, ovector, proceed, 4, replace, sizeof(replace));
2119 tm.tm_hour = atoi(replace);
2120 }
2121
2122 if (proceed > 5) {
2123 switch_regex_copy_substring(in, ovector, proceed, 5, replace, sizeof(replace));
2124 tm.tm_min = atoi(replace);
2125 }
2126
2127 if (proceed > 6) {
2128 switch_regex_copy_substring(in, ovector, proceed, 6, replace, sizeof(replace));
2129 tm.tm_sec = atoi(replace);
2130 }
2131
2132 switch_regex_safe_free(re);
2133
2134 switch_time_exp_get(&local_time, &tm);
2135 switch_time_exp_lt(&local_tm, local_time);
2136 tm.tm_isdst = local_tm.tm_isdst;
2137 tm.tm_gmtoff = local_tm.tm_gmtoff;
2138
2139 switch_time_exp_gmt_get(&ret, &tm);
2140 return ret;
2141 }
2142
2143 switch_regex_safe_free(re);
2144
2145 return ret;
2146 }
2147
2148 SWITCH_DECLARE(const char *) switch_priority_name(switch_priority_t priority)
2149 {
2150 switch (priority) { /*lol */
2151 case SWITCH_PRIORITY_NORMAL:
2152 return "NORMAL";
2153 case SWITCH_PRIORITY_LOW:
2154 return "LOW";
2155 case SWITCH_PRIORITY_HIGH:
2156 return "HIGH";
2157 default:
2158 return "INVALID";
2159 }
2160 }
2161
2162 static char RFC2833_CHARS[] = "0123456789*#ABCDF";
2163
2164 #ifdef _MSC_VER
2165 /* Copyright (c) 1996 by Internet Software Consortium.
2166 *
2167 * Permission to use, copy, modify, and distribute this software for any
2168 * purpose with or without fee is hereby granted, provided that the above
2169 * copyright notice and this permission notice appear in all copies.
2170 *
2171 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
2172 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
2173 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
2174 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
2175 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
2176 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
2177 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2178 * SOFTWARE.
2179 */
2180
2181 #include <ctype.h>
2182 #include <errno.h>
2183 #include <stdio.h>
2184 #include <string.h>
2185 #include <stdlib.h>
2186
2187 #include <sys/types.h>
2188
2189 /*
2190 * WARNING: Don't even consider trying to compile this on a system where
2191 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
2192 */
2193
2194 static const char *switch_inet_ntop4(const unsigned char *src, char *dst, size_t size);
2195 #if HAVE_SIN6
2196 static const char *switch_inet_ntop6(const unsigned char *src, char *dst, size_t size);
2197 #endif
2198
2199 /* char *
2200 * inet_ntop(af, src, dst, size)
2201 * convert a network format address to presentation format.
2202 * return:
2203 * pointer to presentation format address (`dst'), or NULL (see errno).
2204 * author:
2205 * Paul Vixie, 1996.
2206 */
2207 SWITCH_DECLARE(const char *) switch_inet_ntop(int af, void const *src, char *dst, size_t size)
2208 {
2209
2210 switch (af) {
2211 case AF_INET:
2212 return switch_inet_ntop4(src, dst, size);
2213 #if HAVE_SIN6
2214 case AF_INET6:
2215 return switch_inet_ntop6(src, dst, size);
2216 #endif
2217 default:
2218 return NULL;
2219 }
2220 /* NOTREACHED */
2221 }
2222
2223 /* const char *
2224 * inet_ntop4(src, dst, size)
2225 * format an IPv4 address, more or less like inet_ntoa()
2226 * return:
2227 * `dst' (as a const)
2228 * notes:
2229 * (1) uses no statics
2230 * (2) takes a unsigned char* not an in_addr as input
2231 * author:
2232 * Paul Vixie, 1996.
2233 */
2234 static const char *switch_inet_ntop4(const unsigned char *src, char *dst, size_t size)
2235 {
2236 static const char fmt[] = "%u.%u.%u.%u";
2237 char tmp[sizeof "255.255.255.255"];
2238
2239 if (switch_snprintf(tmp, sizeof tmp, fmt, src[0], src[1], src[2], src[3]) >= (int) size) {
2240 return NULL;
2241 }
2242
2243 return strcpy(dst, tmp);
2244 }
2245
2246 #if HAVE_SIN6 || defined(NTDDI_VERSION)
2247 /* const char *
2248 * inet_ntop6(src, dst, size)
2249 * convert IPv6 binary address into presentation (printable) format
2250 * author:
2251 * Paul Vixie, 1996.
2252 */
2253 static const char *switch_inet_ntop6(unsigned char const *src, char *dst, size_t size)
2254 {
2255 /*
2256 * Note that int32_t and int16_t need only be "at least" large enough
2257 * to contain a value of the specified size. On some systems, like
2258 * Crays, there is no such thing as an integer variable with 16 bits.
2259 * Keep this in mind if you think this function should have been coded
2260 * to use pointer overlays. All the world's not a VAX.
2261 */
2262 char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
2263 struct {
2264 int base, len;
2265 } best = {
2266 -1, 0}, cur = {
2267 -1, 0};
2268 unsigned int words[8];
2269 int i;
2270
2271 /*
2272 * Preprocess:
2273 * Copy the input (bytewise) array into a wordwise array.
2274 * Find the longest run of 0x00's in src[] for :: shorthanding.
2275 */
2276 for (i = 0; i < 16; i += 2)
2277 words[i / 2] = (src[i] << 8) | (src[i + 1]);
2278 best.base = -1;
2279 cur.base = -1;
2280 for (i = 0; i < 8; i++) {
2281 if (words[i] == 0) {
2282 if (cur.base == -1)
2283 cur.base = i, cur.len = 1;
2284 else
2285 cur.len++;
2286 } else {
2287 if (cur.base != -1) {
2288 if (best.base == -1 || cur.len > best.len)
2289 best = cur;
2290 cur.base = -1;
2291 }
2292 }
2293 }
2294 if (cur.base != -1) {
2295 if (best.base == -1 || cur.len > best.len)
2296 best = cur;
2297 }
2298 if (best.base != -1 && best.len < 2)
2299 best.base = -1;
2300
2301 /*
2302 * Format the result.
2303 */
2304 tp = tmp;
2305 for (i = 0; i < 8; i++) {
2306 /* Are we inside the best run of 0x00's? */
2307 if (best.base != -1 && i >= best.base && i < (best.base + best.len)) {
2308 if (i == best.base)
2309 *tp++ = ':';
2310 continue;
2311 }
2312 /* Are we following an initial run of 0x00s or any real hex? */
2313 if (i != 0)
2314 *tp++ = ':';
2315 /* Is this address an encapsulated IPv4? */
2316 if (i == 6 && best.base == 0 && (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
2317 if (!switch_inet_ntop4(src + 12, tp, sizeof tmp - (tp - tmp)))
2318 return (NULL);
2319 tp += strlen(tp);
2320 break;
2321 }
2322 tp += sprintf(tp, "%x", words[i]);
2323 }
2324 /* Was it a trailing run of 0x00's? */
2325 if (best.base != -1 && (best.base + best.len) == 8)
2326 *tp++ = ':';
2327 *tp++ = '\0';
2328
2329 /*
2330 * Check for overflow, copy, and we're done.
2331 */
2332 if ((size_t) (tp - tmp) >= size) {
2333 return NULL;
2334 }
2335
2336 return strcpy(dst, tmp);
2337 }
2338 #endif
2339
2340 #endif
2341
2342 SWITCH_DECLARE(int) get_addr_int(switch_sockaddr_t *sa)
2343 {
2344 struct sockaddr_in *s = (struct sockaddr_in *) &sa->sa;
2345
2346 return ntohs((unsigned short) s->sin_addr.s_addr);
2347 }
2348
2349 SWITCH_DECLARE(int) switch_cmp_addr(switch_sockaddr_t *sa1, switch_sockaddr_t *sa2, switch_bool_t ip_only)
2350 {
2351 struct sockaddr_in *s1;
2352 struct sockaddr_in *s2;
2353
2354 struct sockaddr_in6 *s16;
2355 struct sockaddr_in6 *s26;
2356
2357 struct sockaddr *ss1;
2358 struct sockaddr *ss2;
2359
2360 if (!(sa1 && sa2))
2361 return 0;
2362
2363 s1 = (struct sockaddr_in *) &sa1->sa;
2364 s2 = (struct sockaddr_in *) &sa2->sa;
2365
2366 s16 = (struct sockaddr_in6 *) &sa1->sa;
2367 s26 = (struct sockaddr_in6 *) &sa2->sa;
2368
2369 ss1 = (struct sockaddr *) &sa1->sa;
2370 ss2 = (struct sockaddr *) &sa2->sa;
2371
2372 if (ss1->sa_family != ss2->sa_family)
2373 return 0;
2374
2375 switch (ss1->sa_family) {
2376 case AF_INET:
2377 if (ip_only) {
2378 return (s1->sin_addr.s_addr == s2->sin_addr.s_addr);
2379 } else {
2380 return (s1->sin_addr.s_addr == s2->sin_addr.s_addr && s1->sin_port == s2->sin_port);
2381 }
2382 case AF_INET6:
2383 if (s16->sin6_addr.s6_addr && s26->sin6_addr.s6_addr) {
2384 int i;
2385
2386 if (!ip_only) {
2387 if (s16->sin6_port != s26->sin6_port) return 0;
2388 }
2389
2390 for (i = 0; i < 4; i++) {
2391 if (*((int32_t *) s16->sin6_addr.s6_addr + i) != *((int32_t *) s26->sin6_addr.s6_addr + i)) return 0;
2392 }
2393
2394 return 1;
2395 }
2396 }
2397
2398 return 0;
2399 }
2400
2401
2402 SWITCH_DECLARE(int) switch_cp_addr(switch_sockaddr_t *sa1, switch_sockaddr_t *sa2)
2403 {
2404 struct sockaddr_in *s1;
2405 struct sockaddr_in *s2;
2406
2407 struct sockaddr_in6 *s16;
2408 struct sockaddr_in6 *s26;
2409
2410 struct sockaddr *ss1;
2411 //struct sockaddr *ss2;
2412
2413 if (!(sa1 && sa2))
2414 return 0;
2415
2416 s1 = (struct sockaddr_in *) &sa1->sa;
2417 s2 = (struct sockaddr_in *) &sa2->sa;
2418
2419 s16 = (struct sockaddr_in6 *) &sa1->sa;
2420 s26 = (struct sockaddr_in6 *) &sa2->sa;
2421
2422 ss1 = (struct sockaddr *) &sa1->sa;
2423 //ss2 = (struct sockaddr *) &sa2->sa;
2424
2425 sa1->port = sa2->port;
2426 sa1->family = sa2->family;
2427
2428 sa1->sa.sin.sin_family = sa2->family;
2429
2430 switch (ss1->sa_family) {
2431 case AF_INET:
2432 s1->sin_addr.s_addr = s2->sin_addr.s_addr;
2433 s1->sin_port = s2->sin_port;
2434
2435 return 1;
2436 case AF_INET6:
2437 if (s16->sin6_addr.s6_addr && s26->sin6_addr.s6_addr) {
2438 int i;
2439
2440 s16->sin6_port = s26->sin6_port;
2441
2442 for (i = 0; i < 4; i++) {
2443 *((int32_t *) s16->sin6_addr.s6_addr + i) = *((int32_t *) s26->sin6_addr.s6_addr + i);
2444 }
2445
2446 return 1;
2447 }
2448 }
2449
2450 return 0;
2451 }
2452
2453 SWITCH_DECLARE(char *) get_addr6(char *buf, switch_size_t len, struct sockaddr_in6 *sa, socklen_t salen)
2454 {
2455 switch_assert(buf);
2456 *buf = '\0';
2457
2458 if (sa) {
2459 #if defined(NTDDI_VERSION)
2460 switch_inet_ntop6((unsigned char*)&(sa->sin6_addr), buf, len);
2461 #else
2462 inet_ntop(AF_INET6, &(sa->sin6_addr), buf, len);
2463 #endif
2464 }
2465
2466 return buf;
2467 }
2468
2469 SWITCH_DECLARE(char *) get_addr(char *buf, switch_size_t len, struct sockaddr *sa, socklen_t salen)
2470 {
2471 switch_assert(buf);
2472 *buf = '\0';
2473
2474 if (sa) {
2475 getnameinfo(sa, salen, buf, (socklen_t) len, NULL, 0, NI_NUMERICHOST);
2476 }
2477 return buf;
2478 }
2479
2480 SWITCH_DECLARE(unsigned short) get_port(struct sockaddr *sa)
2481 {
2482 unsigned short port = 0;
2483 if (sa) {
2484 switch (sa->sa_family) {
2485 case AF_INET:
2486 port = ntohs(((struct sockaddr_in *) sa)->sin_port);
2487 break;
2488 case AF_INET6:
2489 port = ntohs(((struct sockaddr_in6 *) sa)->sin6_port);
2490 break;
2491 }
2492 }
2493 return port;
2494 }
2495
2496 SWITCH_DECLARE(int) switch_build_uri(char *uri, switch_size_t size, const char *scheme, const char *user, const switch_sockaddr_t *sa, int flags)
2497 {
2498 char host[NI_MAXHOST], serv[NI_MAXSERV];
2499 struct sockaddr_in6 si6;
2500 const struct sockaddr *addr;
2501 const char *colon;
2502
2503 if (flags & SWITCH_URI_NO_SCOPE && sa->family == AF_INET6) {
2504 memcpy(&si6, &sa->sa, sa->salen);
2505 si6.sin6_scope_id = 0;
2506
2507 addr = (const struct sockaddr *) &si6;
2508 } else {
2509 addr = (const struct sockaddr *) (intptr_t) & sa->sa;
2510 }
2511
2512 if (getnameinfo(addr, sa->salen, host, sizeof(host), serv, sizeof(serv),
2513 ((flags & SWITCH_URI_NUMERIC_HOST) ? NI_NUMERICHOST : 0) | ((flags & SWITCH_URI_NUMERIC_PORT) ? NI_NUMERICSERV : 0)) != 0) {
2514 return 0;
2515 }
2516
2517 colon = strchr(host, ':');
2518
2519 return switch_snprintf(uri, size, "%s:%s%s%s%s%s%s%s", scheme,
2520 user ? user : "", user ? "@" : "", colon ? "[" : "", host, colon ? "]" : "", serv[0] ? ":" : "", serv[0] ? serv : "");
2521 }
2522
2523 SWITCH_DECLARE(char) switch_rfc2833_to_char(int event)
2524 {
2525 if (event > -1 && event < (int32_t) sizeof(RFC2833_CHARS)) {
2526 return RFC2833_CHARS[event];
2527 }
2528 return '\0';
2529 }
2530
2531 SWITCH_DECLARE(unsigned char) switch_char_to_rfc2833(char key)
2532 {
2533 char *c;
2534 unsigned char counter = 0;
2535
2536 key = (char) switch_toupper(key);
2537 for (c = RFC2833_CHARS; *c; c++) {
2538 if (*c == key) {
2539 return counter;
2540 }
2541 counter++;
2542 }
2543 return '\0';
2544 }
2545
2546 SWITCH_DECLARE(char *) switch_escape_char(switch_memory_pool_t *pool, char *in, const char *delim, char esc)
2547 {
2548 char *data;
2549 const char *p, *d;
2550 int count = 1, i = 0;
2551
2552 p = in;
2553 while (*p) {
2554 d = delim;
2555 while (*d) {
2556 if (*p == *d) {
2557 count++;
2558 }
2559 d++;
2560 }
2561 p++;
2562 }
2563
2564 if (count == 1) {
2565 return in;
2566 }
2567
2568 data = switch_core_alloc(pool, strlen(in) + count);
2569
2570 p = in;
2571 while (*p) {
2572 d = delim;
2573 while (*d) {
2574 if (*p == *d) {
2575 data[i++] = esc;
2576 }
2577 d++;
2578 }
2579 data[i++] = *p;
2580 p++;
2581 }
2582 return data;
2583 }
2584
2585 /* Helper function used when separating strings to unescape a character. The
2586 supported characters are:
2587
2588 \n linefeed
2589 \r carriage return
2590 \t tab
2591 \s space
2592
2593 Any other character is returned as it was received. */
2594 static char unescape_char(char escaped)
2595 {
2596 char unescaped;
2597
2598 switch (escaped) {
2599 case 'n':
2600 unescaped = '\n';
2601 break;
2602 case 'r':
2603 unescaped = '\r';
2604 break;
2605 case 't':
2606 unescaped = '\t';
2607 break;
2608 case 's':
2609 unescaped = ' ';
2610 break;
2611 default:
2612 unescaped = escaped;
2613 }
2614 return unescaped;
2615 }
2616
2617 SWITCH_DECLARE(char *) switch_escape_string(const char *in, char *out, switch_size_t outlen)
2618 {
2619 const char *p;
2620 char *o = out;
2621
2622 for (p = in; *p; p++) {
2623 switch (*p) {
2624 case '\n':
2625 *o++ = '\\';
2626 *o++ = 'n';
2627 break;
2628 case '\r':
2629 *o++ = '\\';
2630 *o++ = 'r';
2631 break;
2632 case '\t':
2633 *o++ = '\\';
2634 *o++ = 't';
2635 break;
2636 case ' ':
2637 *o++ = '\\';
2638 *o++ = 's';
2639 break;
2640 case '$':
2641 *o++ = '\\';
2642 *o++ = '$';
2643 break;
2644 default:
2645 *o++ = *p;
2646 break;
2647 }
2648 }
2649
2650 *o++ = '\0';
2651
2652 return out;
2653 }
2654
2655 SWITCH_DECLARE(char *) switch_escape_string_pool(const char *in, switch_memory_pool_t *pool)
2656 {
2657 size_t len = strlen(in) * 2 + 1;
2658 char *buf = switch_core_alloc(pool, len);
2659 return switch_escape_string(in, buf, len);
2660 }
2661
2662 /* Helper function used when separating strings to remove quotes, leading /
2663 trailing spaces, and to convert escaped characters. */
2664 static char *cleanup_separated_string(char *str, char delim)
2665 {
2666 char *ptr;
2667 char *dest;
2668 char *start;
2669 char *end = NULL;
2670 int inside_quotes = 0;
2671
2672 /* Skip initial whitespace */
2673 for (ptr = str; *ptr == ' '; ++ptr) {
2674 }
2675
2676 for (start = dest = ptr; *ptr; ++ptr) {
2677 char e;
2678 int esc = 0;
2679
2680 if (*ptr == ESCAPE_META) {
2681 e = *(ptr + 1);
2682 if (e == '\'' || e == '"' || (delim && e == delim) || e == ESCAPE_META || (e = unescape_char(*(ptr + 1))) != *(ptr + 1)) {
2683 ++ptr;
2684 *dest++ = e;
2685 end = dest;
2686 esc++;
2687 }
2688 }
2689 if (!esc) {
2690 if (*ptr == '\'' && (inside_quotes || strchr(ptr+1, '\''))) {
2691 if ((inside_quotes = (1 - inside_quotes))) {
2692 end = dest;
2693 }
2694 } else {
2695 *dest++ = *ptr;
2696 if (*ptr != ' ' || inside_quotes) {
2697 end = dest;
2698 }
2699 }
2700 }
2701 }
2702 if (end) {
2703 *end = '\0';
2704 }
2705
2706 return start;
2707 }
2708
2709 SWITCH_DECLARE(unsigned int) switch_separate_string_string(char *buf, char *delim, char **array, unsigned int arraylen)
2710 {
2711 unsigned int count = 0;
2712 char *d;
2713 size_t dlen = strlen(delim);
2714
2715 array[count++] = buf;
2716
2717 while (count < arraylen && array[count - 1]) {
2718 if ((d = strstr(array[count - 1], delim))) {
2719 *d = '\0';
2720 d += dlen;
2721 array[count++] = d;
2722 } else
2723 break;
2724 }
2725
2726 return count;
2727 }
2728
2729 /* Separate a string using a delimiter that is not a space */
2730 static unsigned int separate_string_char_delim(char *buf, char delim, char **array, unsigned int arraylen)
2731 {
2732 enum tokenizer_state {
2733 START,
2734 FIND_DELIM
2735 } state = START;
2736
2737 unsigned int count = 0;
2738 char *ptr = buf;
2739 int inside_quotes = 0;
2740 unsigned int i;
2741
2742 while (*ptr && count < arraylen) {
2743 switch (state) {
2744 case START:
2745 array[count++] = ptr;
2746 state = FIND_DELIM;
2747 break;
2748
2749 case FIND_DELIM:
2750 /* escaped characters are copied verbatim to the destination string */
2751 if (*ptr == ESCAPE_META) {
2752 ++ptr;
2753 } else if (*ptr == '\'' && (inside_quotes || strchr(ptr+1, '\''))) {
2754 inside_quotes = (1 - inside_quotes);
2755 } else if (*ptr == delim && !inside_quotes) {
2756 *ptr = '\0';
2757 state = START;
2758 }
2759 ++ptr;
2760 break;
2761 }
2762 }
2763 /* strip quotes, escaped chars and leading / trailing spaces */
2764
2765 for (i = 0; i < count; ++i) {
2766 array[i] = cleanup_separated_string(array[i], delim);
2767 }
2768
2769 return count;
2770 }
2771
2772 /* Separate a string using a delimiter that is a space */
2773 static unsigned int separate_string_blank_delim(char *buf, char **array, unsigned int arraylen)
2774 {
2775 enum tokenizer_state {
2776 START,
2777 SKIP_INITIAL_SPACE,
2778 FIND_DELIM,
2779 SKIP_ENDING_SPACE
2780 } state = START;
2781
2782 unsigned int count = 0;
2783 char *ptr = buf;
2784 int inside_quotes = 0;
2785 unsigned int i;
2786
2787 while (*ptr && count < arraylen) {
2788 switch (state) {
2789 case START:
2790 array[count++] = ptr;
2791 state = SKIP_INITIAL_SPACE;
2792 break;
2793
2794 case SKIP_INITIAL_SPACE:
2795 if (*ptr == ' ') {
2796 ++ptr;
2797 } else {
2798 state = FIND_DELIM;
2799 }
2800 break;
2801
2802 case FIND_DELIM:
2803 if (*ptr == ESCAPE_META) {
2804 ++ptr;
2805 } else if (*ptr == '\'') {
2806 inside_quotes = (1 - inside_quotes);
2807 } else if (*ptr == ' ' && !inside_quotes) {
2808 *ptr = '\0';
2809 state = SKIP_ENDING_SPACE;
2810 }
2811 ++ptr;
2812 break;
2813
2814 case SKIP_ENDING_SPACE:
2815 if (*ptr == ' ') {
2816 ++ptr;
2817 } else {
2818 state = START;
2819 }
2820 break;
2821 }
2822 }
2823 /* strip quotes, escaped chars and leading / trailing spaces */
2824
2825 for (i = 0; i < count; ++i) {
2826 array[i] = cleanup_separated_string(array[i], 0);
2827 }
2828
2829 return count;
2830 }
2831
2832 SWITCH_DECLARE(unsigned int) switch_separate_string(char *buf, char delim, char **array, unsigned int arraylen)
2833 {
2834 if (!buf || !array || !arraylen) {
2835 return 0;
2836 }
2837
2838
2839 if (*buf == '^' && *(buf+1) == '^') {
2840 char *p = buf + 2;
2841
2842 if (*p && *(p+1)) {
2843 buf = p;
2844 delim = *buf++;
2845 }
2846 }
2847
2848
2849 memset(array, 0, arraylen * sizeof(*array));
2850
2851 return (delim == ' ' ? separate_string_blank_delim(buf, array, arraylen) : separate_string_char_delim(buf, delim, array, arraylen));
2852 }
2853
2854 SWITCH_DECLARE(const char *) switch_cut_path(const char *in)
2855 {
2856 const char *p, *ret = in;
2857 const char delims[] = "/\\";
2858 const char *i;
2859
2860 if (in) {
2861 for (i = delims; *i; i++) {
2862 p = in;
2863 while ((p = strchr(p, *i)) != 0) {
2864 ret = ++p;
2865 }
2866 }
2867 return ret;
2868 } else {
2869 return NULL;
2870 }
2871 }
2872
2873 SWITCH_DECLARE(switch_status_t) switch_string_match(const char *string, size_t string_len, const char *search, size_t search_len)
2874 {
2875 size_t i;
2876
2877 for (i = 0; (i < search_len) && (i < string_len); i++) {
2878 if (string[i] != search[i]) {
2879 return SWITCH_STATUS_FALSE;
2880 }
2881 }
2882
2883 if (i == search_len) {
2884 return SWITCH_STATUS_SUCCESS;
2885 }
2886
2887 return SWITCH_STATUS_FALSE;
2888 }
2889
2890 SWITCH_DECLARE(char *) switch_string_replace(const char *string, const char *search, const char *replace)
2891 {
2892 size_t string_len = strlen(string);
2893 size_t search_len = strlen(search);
2894 size_t replace_len = strlen(replace);
2895 size_t i, n;
2896 size_t dest_len = 0;
2897 char *dest, *tmp;
2898
2899 dest = (char *) malloc(sizeof(char));
2900 switch_assert(dest);
2901
2902 for (i = 0; i < string_len; i++) {
2903 if (switch_string_match(string + i, string_len - i, search, search_len) == SWITCH_STATUS_SUCCESS) {
2904 for (n = 0; n < replace_len; n++) {
2905 dest[dest_len] = replace[n];
2906 dest_len++;
2907 tmp = (char *) realloc(dest, sizeof(char) * (dest_len + 1));
2908 switch_assert(tmp);
2909 dest = tmp;
2910 }
2911 i += search_len - 1;
2912 } else {
2913 dest[dest_len] = string[i];
2914 dest_len++;
2915 tmp = (char *) realloc(dest, sizeof(char) * (dest_len + 1));
2916 switch_assert(tmp);
2917 dest = tmp;
2918 }
2919 }
2920
2921 dest[dest_len] = 0;
2922 return dest;
2923 }
2924
2925 SWITCH_DECLARE(char *) switch_util_quote_shell_arg(const char *string)
2926 {
2927 return switch_util_quote_shell_arg_pool(string, NULL);
2928 }
2929
2930 SWITCH_DECLARE(char *) switch_util_quote_shell_arg_pool(const char *string, switch_memory_pool_t *pool)
2931 {
2932 size_t string_len = strlen(string);
2933 size_t i;
2934 size_t n = 0;
2935 size_t dest_len = 0;
2936 char *dest;
2937
2938 /* first pass through, figure out how large to make the allocation */
2939 dest_len = strlen(string) + 1; /* string + null */
2940 dest_len += 1; /* opening quote */
2941 for (i = 0; i < string_len; i++) {
2942 switch (string[i]) {
2943 #ifndef WIN32
2944 case '\'':
2945 /* We replace ' by sq backslace sq sq, so need 3 additional bytes */
2946 dest_len += 3;
2947 break;
2948 #endif
2949 }
2950 }
2951 dest_len += 1; /* closing quote */
2952
2953 /* if we're given a pool, allocate from it, otherwise use malloc */
2954 if (pool) {
2955 dest = switch_core_alloc(pool, sizeof(char) * dest_len);
2956 } else {
2957 dest = (char *) malloc(sizeof(char) * dest_len);
2958 }
2959 switch_assert(dest);
2960
2961 #ifdef WIN32
2962 dest[n++] = '"';
2963 #else
2964 dest[n++] = '\'';
2965 #endif
2966
2967 for (i = 0; i < string_len; i++) {
2968 switch (string[i]) {
2969 #ifdef WIN32
2970 case '"':
2971 case '%':
2972 dest[n++] = ' ';
2973 break;
2974 #else
2975 case '\'':
2976 /* We replace ' by sq backslash sq sq */
2977 dest[n++] = '\'';
2978 dest[n++] = '\\';
2979 dest[n++] = '\'';
2980 dest[n++] = '\'';
2981 break;
2982 #endif
2983 default:
2984 dest[n++] = string[i];
2985 }
2986 }
2987
2988 #ifdef WIN32
2989 dest[n++] = '"';
2990 #else
2991 dest[n++] = '\'';
2992 #endif
2993 dest[n++] = 0;
2994 switch_assert(n == dest_len);
2995 return dest;
2996 }
2997
2998
2999
3000 #ifdef HAVE_POLL
3001 #include <poll.h>
3002 SWITCH_DECLARE(int) switch_wait_sock(switch_os_socket_t sock, uint32_t ms, switch_poll_t flags)
3003 {
3004 struct pollfd pfds[2] = { { 0 } };
3005 int s = 0, r = 0;
3006
3007 if (sock == SWITCH_SOCK_INVALID) {
3008 return SWITCH_SOCK_INVALID;
3009 }
3010
3011 pfds[0].fd = sock;
3012
3013
3014 if ((flags & SWITCH_POLL_READ)) {
3015 pfds[0].events |= POLLIN;
3016 }
3017
3018 if ((flags & SWITCH_POLL_WRITE)) {
3019 pfds[0].events |= POLLOUT;
3020 }
3021
3022 if ((flags & SWITCH_POLL_ERROR)) {
3023 pfds[0].events |= POLLERR;
3024 }
3025
3026 if ((flags & SWITCH_POLL_HUP)) {
3027 pfds[0].events |= POLLHUP;
3028 }
3029
3030 if ((flags & SWITCH_POLL_RDNORM)) {
3031 pfds[0].events |= POLLRDNORM;
3032 }
3033
3034 if ((flags & SWITCH_POLL_RDBAND)) {
3035 pfds[0].events |= POLLRDBAND;
3036 }
3037
3038 if ((flags & SWITCH_POLL_PRI)) {
3039 pfds[0].events |= POLLPRI;
3040 }
3041
3042 s = poll(pfds, 1, ms);
3043
3044 if (s < 0) {
3045 if (switch_errno_is_break(switch_errno())) {
3046 s = 0;
3047 }
3048 }
3049
3050 if (s < 0) {
3051 r = s;
3052 } else if (s > 0) {
3053 if ((pfds[0].revents & POLLIN)) {
3054 r |= SWITCH_POLL_READ;
3055 }
3056 if ((pfds[0].revents & POLLOUT)) {
3057 r |= SWITCH_POLL_WRITE;
3058 }
3059 if ((pfds[0].revents & POLLERR)) {
3060 r |= SWITCH_POLL_ERROR;
3061 }
3062 if ((pfds[0].revents & POLLHUP)) {
3063 r |= SWITCH_POLL_HUP;
3064 }
3065 if ((pfds[0].revents & POLLRDNORM)) {
3066 r |= SWITCH_POLL_RDNORM;
3067 }
3068 if ((pfds[0].revents & POLLRDBAND)) {
3069 r |= SWITCH_POLL_RDBAND;
3070 }
3071 if ((pfds[0].revents & POLLPRI)) {
3072 r |= SWITCH_POLL_PRI;
3073 }
3074 if ((pfds[0].revents & POLLNVAL)) {
3075 r |= SWITCH_POLL_INVALID;
3076 }
3077 }
3078
3079 return r;
3080
3081 }
3082
3083 SWITCH_DECLARE(int) switch_wait_socklist(switch_waitlist_t *waitlist, uint32_t len, uint32_t ms)
3084 {
3085 struct pollfd *pfds;
3086 int s = 0, r = 0, i;
3087
3088 pfds = calloc(len, sizeof(struct pollfd));
3089 switch_assert(pfds);
3090
3091 for (i = 0; i < len; i++) {
3092 if (waitlist[i].sock == SWITCH_SOCK_INVALID) {
3093 break;
3094 }
3095
3096 pfds[i].fd = waitlist[i].sock;
3097
3098 if ((waitlist[i].events & SWITCH_POLL_READ)) {
3099 pfds[i].events |= POLLIN;
3100 }
3101
3102 if ((waitlist[i].events & SWITCH_POLL_WRITE)) {
3103 pfds[i].events |= POLLOUT;
3104 }
3105
3106 if ((waitlist[i].events & SWITCH_POLL_ERROR)) {
3107 pfds[i].events |= POLLERR;
3108 }
3109
3110 if ((waitlist[i].events & SWITCH_POLL_HUP)) {
3111 pfds[i].events |= POLLHUP;
3112 }
3113
3114 if ((waitlist[i].events & SWITCH_POLL_RDNORM)) {
3115 pfds[i].events |= POLLRDNORM;
3116 }
3117
3118 if ((waitlist[i].events & SWITCH_POLL_RDBAND)) {
3119 pfds[i].events |= POLLRDBAND;
3120 }
3121
3122 if ((waitlist[i].events & SWITCH_POLL_PRI)) {
3123 pfds[i].events |= POLLPRI;
3124 }
3125 }
3126
3127 s = poll(pfds, len, ms);
3128
3129 if (s < 0) {
3130 if (switch_errno_is_break(switch_errno())) {
3131 s = 0;
3132 }
3133 }
3134
3135 if (s < 0) {
3136 r = s;
3137 } else if (s > 0) {
3138 for (i = 0; i < len; i++) {
3139 if ((pfds[i].revents & POLLIN)) {
3140 r |= SWITCH_POLL_READ;
3141 waitlist[i].revents |= SWITCH_POLL_READ;
3142 }
3143 if ((pfds[i].revents & POLLOUT)) {
3144 r |= SWITCH_POLL_WRITE;
3145 waitlist[i].revents |= SWITCH_POLL_WRITE;
3146 }
3147 if ((pfds[i].revents & POLLERR)) {
3148 r |= SWITCH_POLL_ERROR;
3149 waitlist[i].revents |= SWITCH_POLL_ERROR;
3150 }
3151 if ((pfds[i].revents & POLLHUP)) {
3152 r |= SWITCH_POLL_HUP;
3153 waitlist[i].revents |= SWITCH_POLL_HUP;
3154 }
3155 if ((pfds[i].revents & POLLRDNORM)) {
3156 r |= SWITCH_POLL_RDNORM;
3157 waitlist[i].revents |= SWITCH_POLL_RDNORM;
3158 }
3159 if ((pfds[i].revents & POLLRDBAND)) {
3160 r |= SWITCH_POLL_RDBAND;
3161 waitlist[i].revents |= SWITCH_POLL_RDBAND;
3162 }
3163 if ((pfds[i].revents & POLLPRI)) {
3164 r |= SWITCH_POLL_PRI;
3165 waitlist[i].revents |= SWITCH_POLL_PRI;
3166 }
3167 if ((pfds[i].revents & POLLNVAL)) {
3168 r |= SWITCH_POLL_INVALID;
3169 waitlist[i].revents |= SWITCH_POLL_INVALID;
3170 }
3171 }
3172 }
3173
3174 free(pfds);
3175
3176 return r;
3177
3178 }
3179
3180 #else
3181 /* use select instead of poll */
3182 SWITCH_DECLARE(int) switch_wait_sock(switch_os_socket_t sock, uint32_t ms, switch_poll_t flags)
3183 {
3184 int s = 0, r = 0;
3185 fd_set *rfds;
3186 fd_set *wfds;
3187 fd_set *efds;
3188 struct timeval tv;
3189
3190 if (sock == SWITCH_SOCK_INVALID) {
3191 return SWITCH_SOCK_INVALID;
3192 }
3193
3194 rfds = malloc(sizeof(fd_set));
3195 wfds = malloc(sizeof(fd_set));
3196 efds = malloc(sizeof(fd_set));
3197
3198 FD_ZERO(rfds);
3199 FD_ZERO(wfds);
3200 FD_ZERO(efds);
3201
3202 #ifndef WIN32
3203 /* Wouldn't you rather know?? */
3204 assert(sock <= FD_SETSIZE);
3205 #endif
3206
3207 if ((flags & SWITCH_POLL_READ)) {
3208
3209 #ifdef WIN32
3210 #pragma warning( push )
3211 #pragma warning( disable : 4127 )
3212 FD_SET(sock, rfds);
3213 #pragma warning( pop )
3214 #else
3215 FD_SET(sock, rfds);
3216 #endif
3217 }
3218
3219 if ((flags & SWITCH_POLL_WRITE)) {
3220
3221 #ifdef WIN32
3222 #pragma warning( push )
3223 #pragma warning( disable : 4127 )
3224 FD_SET(sock, wfds);
3225 #pragma warning( pop )
3226 #else
3227 FD_SET(sock, wfds);
3228 #endif
3229 }
3230
3231 if ((flags & SWITCH_POLL_ERROR)) {
3232
3233 #ifdef WIN32
3234 #pragma warning( push )
3235 #pragma warning( disable : 4127 )
3236 FD_SET(sock, efds);
3237 #pragma warning( pop )
3238 #else
3239 FD_SET(sock, efds);
3240 #endif
3241 }
3242
3243 tv.tv_sec = ms / 1000;
3244 tv.tv_usec = (ms % 1000) * 1000;
3245
3246 s = select(sock + 1, (flags & SWITCH_POLL_READ) ? rfds : NULL, (flags & SWITCH_POLL_WRITE) ? wfds : NULL, (flags & SWITCH_POLL_ERROR) ? efds : NULL, &tv);
3247
3248 if (s < 0) {
3249 if (switch_errno_is_break(switch_errno())) {
3250 s = 0;
3251 }
3252 }
3253
3254 if (s < 0) {
3255 r = s;
3256 } else if (s > 0) {
3257 if ((flags & SWITCH_POLL_READ) && FD_ISSET(sock, rfds)) {
3258 r |= SWITCH_POLL_READ;
3259 }
3260
3261 if ((flags & SWITCH_POLL_WRITE) && FD_ISSET(sock, wfds)) {
3262 r |= SWITCH_POLL_WRITE;
3263 }
3264
3265 if ((flags & SWITCH_POLL_ERROR) && FD_ISSET(sock, efds)) {
3266 r |= SWITCH_POLL_ERROR;
3267 }
3268 }
3269
3270 free(rfds);
3271 free(wfds);
3272 free(efds);
3273
3274 return r;
3275
3276 }
3277
3278 SWITCH_DECLARE(int) switch_wait_socklist(switch_waitlist_t *waitlist, uint32_t len, uint32_t ms)
3279 {
3280 int s = 0, r = 0;
3281 fd_set *rfds;
3282 fd_set *wfds;
3283 fd_set *efds;
3284 struct timeval tv;
3285 unsigned int i;
3286 switch_os_socket_t max_fd = 0;
3287 int flags = 0;
3288
3289 rfds = malloc(sizeof(fd_set));
3290 wfds = malloc(sizeof(fd_set));
3291 efds = malloc(sizeof(fd_set));
3292
3293 FD_ZERO(rfds);
3294 FD_ZERO(wfds);
3295 FD_ZERO(efds);
3296
3297 for (i = 0; i < len; i++) {
3298 if (waitlist[i].sock == SWITCH_SOCK_INVALID) {
3299 break;
3300 }
3301
3302 if (waitlist[i].sock > max_fd) {
3303 max_fd = waitlist[i].sock;
3304 }
3305
3306 #ifndef WIN32
3307 /* Wouldn't you rather know?? */
3308 assert(waitlist[i].sock <= FD_SETSIZE);
3309 #endif
3310 flags |= waitlist[i].events;
3311
3312 if ((waitlist[i].events & SWITCH_POLL_READ)) {
3313
3314 #ifdef WIN32
3315 #pragma warning( push )
3316 #pragma warning( disable : 4127 )
3317 FD_SET(waitlist[i].sock, rfds);
3318 #pragma warning( pop )
3319 #else
3320 FD_SET(waitlist[i].sock, rfds);
3321 #endif
3322 }
3323
3324 if ((waitlist[i].events & SWITCH_POLL_WRITE)) {
3325
3326 #ifdef WIN32
3327 #pragma warning( push )
3328 #pragma warning( disable : 4127 )
3329 FD_SET(waitlist[i].sock, wfds);
3330 #pragma warning( pop )
3331 #else
3332 FD_SET(waitlist[i].sock, wfds);
3333 #endif
3334 }
3335
3336 if ((waitlist[i].events & SWITCH_POLL_ERROR)) {
3337
3338 #ifdef WIN32
3339 #pragma warning( push )
3340 #pragma warning( disable : 4127 )
3341 FD_SET(waitlist[i].sock, efds);
3342 #pragma warning( pop )
3343 #else
3344 FD_SET(waitlist[i].sock, efds);
3345 #endif
3346 }
3347 }
3348
3349 tv.tv_sec = ms / 1000;
3350 tv.tv_usec = (ms % 1000) * 1000;
3351
3352 s = select(max_fd + 1, (flags & SWITCH_POLL_READ) ? rfds : NULL, (flags & SWITCH_POLL_WRITE) ? wfds : NULL, (flags & SWITCH_POLL_ERROR) ? efds : NULL, &tv);
3353
3354 if (s < 0) {
3355 if (switch_errno_is_break(switch_errno())) {
3356 s = 0;
3357 }
3358 }
3359
3360 if (s < 0) {
3361 r = s;
3362 } else if (s > 0) {
3363 for (i = 0; i < len; i++) {
3364 if ((waitlist[i].events & SWITCH_POLL_READ) && FD_ISSET(waitlist[i].sock, rfds)) {
3365 r |= SWITCH_POLL_READ;
3366 waitlist[i].revents |= SWITCH_POLL_READ;
3367 }
3368
3369 if ((waitlist[i].events & SWITCH_POLL_WRITE) && FD_ISSET(waitlist[i].sock, wfds)) {
3370 r |= SWITCH_POLL_WRITE;
3371 waitlist[i].revents |= SWITCH_POLL_WRITE;
3372 }
3373
3374 if ((waitlist[i].events & SWITCH_POLL_ERROR) && FD_ISSET(waitlist[i].sock, efds)) {
3375 r |= SWITCH_POLL_ERROR;
3376 waitlist[i].revents |= SWITCH_POLL_ERROR;
3377 }
3378 }
3379 }
3380
3381 free(rfds);
3382 free(wfds);
3383 free(efds);
3384
3385 return r;
3386
3387 }
3388 #endif
3389
3390 SWITCH_DECLARE(int) switch_socket_waitfor(switch_pollfd_t *poll, int ms)
3391 {
3392 int nsds = 0;
3393
3394 switch_poll(poll, 1, &nsds, ms);
3395
3396 return nsds;
3397 }
3398
3399 SWITCH_DECLARE(char *) switch_core_session_url_encode(switch_core_session_t *session, const char *url)
3400 {
3401 return switch_core_url_encode_opt(switch_core_session_get_pool(session), url, SWITCH_FALSE);
3402 }
3403
3404 SWITCH_DECLARE(char *) switch_core_session_url_encode_opt(switch_core_session_t *session, const char *url, switch_bool_t double_encode)
3405 {
3406 return switch_core_url_encode_opt(switch_core_session_get_pool(session), url, double_encode);
3407 }
3408
3409 SWITCH_DECLARE(char *) switch_core_url_encode(switch_memory_pool_t *pool, const char *url)
3410 {
3411 return switch_core_url_encode_opt(pool, url, SWITCH_FALSE);
3412 }
3413
3414 SWITCH_DECLARE(char *) switch_core_url_encode_opt(switch_memory_pool_t *pool, const char *url, switch_bool_t double_encode)
3415 {
3416 const char hex[] = "0123456789ABCDEF";
3417 switch_size_t len = 0;
3418 switch_size_t slen = 0;
3419 const char *p, *e;
3420
3421 if (!url) return NULL;
3422 if (!pool) return NULL;
3423
3424 e = end_of_p(url);
3425
3426 for (p = url; *p; p++) {
3427 int ok = 0;
3428
3429 len++;
3430 slen++;
3431
3432 if (!double_encode && *p == '%' && e-p > 1) {
3433 if (strchr(hex, *(p+1)) && strchr(hex, *(p+2))) {
3434 ok = 1;
3435 }
3436 }
3437
3438 if (!ok && (*p < ' ' || *p > '~' || strchr(SWITCH_URL_UNSAFE, *p))) {
3439 len += 2;
3440 }
3441 }
3442
3443 slen++;
3444 len++; /* NULL Terminatior */
3445
3446 if (slen == len) {
3447 return switch_core_strdup(pool, url);
3448 } else {
3449 return switch_url_encode_opt(url, switch_core_alloc(pool, sizeof(char) * len), len, double_encode);
3450 }
3451 }
3452
3453 SWITCH_DECLARE(char *) switch_url_encode_opt(const char *url, char *buf, size_t len, switch_bool_t double_encode)
3454 {
3455 const char *p, *e = end_of_p(url);
3456 size_t x = 0;
3457 const char hex[] = "0123456789ABCDEF";
3458
3459 if (!buf) {
3460 return 0;
3461 }
3462
3463 if (!url) {
3464 return 0;
3465 }
3466
3467 len--;
3468
3469 for (p = url; *p; p++) {
3470 int ok = 0;
3471
3472 if (x >= len) {
3473 break;
3474 }
3475
3476 if (!double_encode && *p == '%' && e-p > 1) {
3477 if (strchr(hex, *(p+1)) && strchr(hex, *(p+2))) {
3478 ok = 1;
3479 }
3480 }
3481
3482 if (!ok && (*p < ' ' || *p > '~' || strchr(SWITCH_URL_UNSAFE, *p))) {
3483 if ((x + 3) > len) {
3484 break;
3485 }
3486 buf[x++] = '%';
3487 buf[x++] = hex[(*p >> 4) & 0x0f];
3488 buf[x++] = hex[*p & 0x0f];
3489 } else {
3490 buf[x++] = *p;
3491 }
3492 }
3493 buf[x] = '\0';
3494
3495 return buf;
3496 }
3497
3498 SWITCH_DECLARE(char *) switch_url_encode(const char *url, char *buf, size_t len)
3499 {
3500 return switch_url_encode_opt(url, buf, len, SWITCH_FALSE);
3501 }
3502
3503 SWITCH_DECLARE(char *) switch_url_decode(char *s)
3504 {
3505 char *o;
3506 unsigned int tmp;
3507
3508 if (zstr(s) || !strchr(s, '%')) {
3509 return s;
3510 }
3511
3512 for (o = s; *s; s++, o++) {
3513 if (*s == '%' && strlen(s) > 2 && sscanf(s + 1, "%2x", &tmp) == 1) {
3514 *o = (char) tmp;
3515 s += 2;
3516 } else {
3517 *o = *s;
3518 }
3519 }
3520 *o = '\0';
3521 return s;
3522 }
3523
3524 SWITCH_DECLARE(void) switch_split_time(const char *exp, int *hour, int *min, int *sec)
3525 {
3526 char *dup = strdup(exp);
3527 char *shour = NULL;
3528 char *smin = NULL;
3529 char *ssec = NULL;
3530
3531 switch_assert(dup);
3532
3533 shour = dup;
3534 if ((smin=strchr(dup, ':'))) {
3535 *smin++ = '\0';
3536 if ((ssec=strchr(smin, ':'))) {
3537 *ssec++ = '\0';
3538 } else {
3539 ssec = "00";
3540 }
3541 if (hour) {
3542 *hour = atol(shour);
3543 }
3544 if (min) {
3545 *min = atol(smin);
3546 }
3547 if (sec) {
3548 *sec = atol(ssec);
3549 }
3550
3551 }
3552 switch_safe_free(dup);
3553 return;
3554
3555 }
3556
3557 SWITCH_DECLARE(void) switch_split_date(const char *exp, int *year, int *month, int *day)
3558 {
3559 char *dup = strdup(exp);
3560 char *syear = NULL;
3561 char *smonth = NULL;
3562 char *sday = NULL;
3563
3564 switch_assert(dup);
3565
3566 syear = dup;
3567 if ((smonth=strchr(dup, '-'))) {
3568 *smonth++ = '\0';
3569 if ((sday=strchr(smonth, '-'))) {
3570 *sday++ = '\0';
3571 if (year) {
3572 *year = atol(syear);
3573 }
3574 if (month) {
3575 *month = atol(smonth);
3576 }
3577 if (day) {
3578 *day = atol(sday);
3579 }
3580 }
3581 }
3582 switch_safe_free(dup);
3583 return;
3584
3585 }
3586
3587 /* Ex exp value "2009-10-10 14:33:22~2009-11-10 17:32:31" */
3588 SWITCH_DECLARE(int) switch_fulldate_cmp(const char *exp, switch_time_t *ts)
3589 {
3590 char *dup = strdup(exp);
3591 char *sStart;
3592 char *sEnd;
3593 char *cur;
3594 char *p;
3595 switch_time_t tsStart = 0;
3596 switch_time_t tsEnd = 0;
3597 int ret = 0;
3598
3599 switch_assert(dup);
3600
3601 cur = dup;
3602 if ((p = strchr(cur, ','))) {
3603 *p++ = '\0';
3604 }
3605
3606 while (cur) {
3607 sStart = cur;
3608 if ((sEnd = strchr(cur, '~'))) {
3609 *sEnd++ = '\0';
3610
3611 tsStart = switch_str_time(sStart);
3612 tsEnd = switch_str_time(sEnd);
3613
3614
3615 if (tsStart == 0 || tsEnd == 0) {
3616 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse error for date time range (%s~%s)\n", sStart, sEnd);
3617 break;
3618 }
3619
3620 if (tsStart <= *ts && tsEnd > *ts) {
3621 ret = 1;
3622 break;
3623 }
3624 }
3625
3626 if ((cur = p)) {
3627 if ((p = strchr(p, ','))) {
3628 *p++ = '\0';
3629 }
3630 }
3631 }
3632
3633 switch_safe_free(dup);
3634 return ret;
3635 }
3636
3637
3638 /* Written by Marc Espie, public domain */
3639 #define SWITCH_CTYPE_NUM_CHARS 256
3640
3641 const short _switch_C_toupper_[1 + SWITCH_CTYPE_NUM_CHARS] = {
3642 EOF,
3643 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
3644 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
3645 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
3646 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
3647 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
3648 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
3649 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
3650 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
3651 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
3652 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
3653 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
3654 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
3655 0x60, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
3656 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
3657 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
3658 'X', 'Y', 'Z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
3659 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
3660 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
3661 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
3662 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
3663 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
3664 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
3665 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
3666 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
3667 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
3668 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
3669 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
3670 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
3671 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
3672 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
3673 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
3674 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
3675 };
3676
3677 const short *_switch_toupper_tab_ = _switch_C_toupper_;
3678
3679 SWITCH_DECLARE(int) old_switch_toupper(int c)
3680 {
3681 if ((unsigned int) c > 255)
3682 return (c);
3683 if (c < -1)
3684 return EOF;
3685 return ((_switch_toupper_tab_ + 1)[c]);
3686 }
3687
3688 const short _switch_C_tolower_[1 + SWITCH_CTYPE_NUM_CHARS] = {
3689 EOF,
3690 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
3691 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
3692 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
3693 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
3694 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
3695 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
3696 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
3697 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
3698 0x40, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
3699 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
3700 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
3701 'x', 'y', 'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
3702 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
3703 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
3704 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
3705 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
3706 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
3707 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
3708 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
3709 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
3710 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
3711 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
3712 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
3713 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
3714 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
3715 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
3716 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
3717 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
3718 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
3719 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
3720 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
3721 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
3722 };
3723
3724 const short *_switch_tolower_tab_ = _switch_C_tolower_;
3725
3726 SWITCH_DECLARE(int) old_switch_tolower(int c)
3727 {
3728 if ((unsigned int) c > 255)
3729 return (c);
3730 if (c < -1)
3731 return EOF;
3732 return ((_switch_tolower_tab_ + 1)[c]);
3733 }
3734
3735 /*
3736 * Copyright (c) 1989 The Regents of the University of California.
3737 * All rights reserved.
3738 * (c) UNIX System Laboratories, Inc.
3739 * All or some portions of this file are derived from material licensed
3740 * to the University of California by American Telephone and Telegraph
3741 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
3742 * the permission of UNIX System Laboratories, Inc.
3743 *
3744 * Redistribution and use in source and binary forms, with or without
3745 * modification, are permitted provided that the following conditions
3746 * are met:
3747 * 1. Redistributions of source code must retain the above copyright
3748 * notice, this list of conditions and the following disclaimer.
3749 * 2. Redistributions in binary form must reproduce the above copyright
3750 * notice, this list of conditions and the following disclaimer in the
3751 * documentation and/or other materials provided with the distribution.
3752 * 3. Neither the name of the University nor the names of its contributors
3753 * may be used to endorse or promote products derived from this software
3754 * without specific prior written permission.
3755 *
3756 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
3757 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3758 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3759 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3760 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3761 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3762 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3763 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3764 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3765 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3766 * SUCH DAMAGE.
3767 */
3768
3769 #undef _U
3770 #undef _L
3771 #undef _N
3772 #undef _S
3773 #undef _P
3774 #undef _C
3775 #undef _X
3776 #undef _B
3777
3778 #define _U 0x01
3779 #define _L 0x02
3780 #define _N 0x04
3781 #define _S 0x08
3782 #define _P 0x10
3783 #define _C 0x20
3784 #define _X 0x40
3785 #define _B 0x80
3786
3787 const int _switch_C_ctype_[1 + SWITCH_CTYPE_NUM_CHARS] = {
3788 0,
3789 _C, _C, _C, _C, _C, _C, _C, _C,
3790 _C, _C | _S, _C | _S, _C | _S, _C | _S, _C | _S, _C, _C,
3791 _C, _C, _C, _C, _C, _C, _C, _C,
3792 _C, _C, _C, _C, _C, _C, _C, _C,
3793 _S | _B, _P, _P, _P, _P, _P, _P, _P,
3794 _P, _P, _P, _P, _P, _P, _P, _P,
3795 _N, _N, _N, _N, _N, _N, _N, _N,
3796 _N, _N, _P, _P, _P, _P, _P, _P,
3797 _P, _U | _X, _U | _X, _U | _X, _U | _X, _U | _X, _U | _X, _U,
3798 _U, _U, _U, _U, _U, _U, _U, _U,
3799 _U, _U, _U, _U, _U, _U, _U, _U,
3800 _U, _U, _U, _P, _P, _P, _P, _P,
3801 _P, _L | _X, _L | _X, _L | _X, _L | _X, _L | _X, _L | _X, _L,
3802 _L, _L, _L, _L, _L, _L, _L, _L,
3803 _L, _L, _L, _L, _L, _L, _L, _L,
3804 /* determine printability based on the IS0 8859 8-bit standard */
3805 _L, _L, _L, _P, _P, _P, _P, _C,
3806
3807 _C, _C, _C, _C, _C, _C, _C, _C, /* 80 */
3808 _C, _C, _C, _C, _C, _C, _C, _C, /* 88 */
3809 _C, _C, _C, _C, _C, _C, _C, _C, /* 90 */
3810 _C, _C, _C, _C, _C, _C, _C, _C, /* 98 */
3811 _P, _P, _P, _P, _P, _P, _P, _P, /* A0 */
3812 _P, _P, _P, _P, _P, _P, _P, _P, /* A8 */
3813 _P, _P, _P, _P, _P, _P, _P, _P, /* B0 */
3814 _P, _P, _P, _P, _P, _P, _P, _P, /* B8 */
3815 _P, _P, _P, _P, _P, _P, _P, _P, /* C0 */
3816 _P, _P, _P, _P, _P, _P, _P, _P, /* C8 */
3817 _P, _P, _P, _P, _P, _P, _P, _P, /* D0 */
3818 _P, _P, _P, _P, _P, _P, _P, _P, /* D8 */
3819 _P, _P, _P, _P, _P, _P, _P, _P, /* E0 */
3820 _P, _P, _P, _P, _P, _P, _P, _P, /* E8 */
3821 _P, _P, _P, _P, _P, _P, _P, _P, /* F0 */
3822 _P, _P, _P, _P, _P, _P, _P, _P /* F8 */
3823 };
3824
3825 const int *_switch_ctype_ = _switch_C_ctype_;
3826
3827 SWITCH_DECLARE(int) switch_isalnum(int c)
3828 {
3829 return (c < 0 ? 0 : c > 255 ? 0 : ((_switch_ctype_ + 1)[(unsigned char) c] & (_U | _L | _N)));
3830 }
3831
3832 SWITCH_DECLARE(int) switch_isalpha(int c)
3833 {
3834 return (c < 0 ? 0 : c > 255 ? 0 : ((_switch_ctype_ + 1)[(unsigned char) c] & (_U | _L)));
3835 }
3836
3837 SWITCH_DECLARE(int) switch_iscntrl(int c)
3838 {
3839 return (c < 0 ? 0 : c > 255 ? 0 : ((_switch_ctype_ + 1)[(unsigned char) c] & _C));
3840 }
3841
3842 SWITCH_DECLARE(int) switch_isdigit(int c)
3843 {
3844 return (c < 0 ? 0 : c > 255 ? 0 : ((_switch_ctype_ + 1)[(unsigned char) c] & _N));
3845 }
3846
3847 SWITCH_DECLARE(int) switch_isgraph(int c)
3848 {
3849 return (c < 0 ? 0 : c > 255 ? 0 : ((_switch_ctype_ + 1)[(unsigned char) c] & (_P | _U | _L | _N)));
3850 }
3851
3852 SWITCH_DECLARE(int) switch_islower(int c)
3853 {
3854 return (c < 0 ? 0 : c > 255 ? 0 : ((_switch_ctype_ + 1)[(unsigned char) c] & _L));
3855 }
3856
3857 SWITCH_DECLARE(int) switch_isprint(int c)
3858 {
3859 return (c < 0 ? 0 : c > 255 ? 0 : ((_switch_ctype_ + 1)[(unsigned char) c] & (_P | _U | _L | _N | _B)));
3860 }
3861
3862 SWITCH_DECLARE(int) switch_ispunct(int c)
3863 {
3864 return (c < 0 ? 0 : c > 255 ? 0 : ((_switch_ctype_ + 1)[(unsigned char) c] & _P));
3865 }
3866
3867 SWITCH_DECLARE(int) switch_isspace(int c)
3868 {
3869 return (c < 0 ? 0 : c > 255 ? 0 : ((_switch_ctype_ + 1)[(unsigned char) c] & _S));
3870 }
3871
3872 SWITCH_DECLARE(int) switch_isupper(int c)
3873 {
3874 return (c < 0 ? 0 : c > 255 ? 0 : ((_switch_ctype_ + 1)[(unsigned char) c] & _U));
3875 }
3876
3877 SWITCH_DECLARE(int) switch_isxdigit(int c)
3878 {
3879 return (c < 0 ? 0 : c > 255 ? 0 : ((_switch_ctype_ + 1)[(unsigned char) c] & (_N | _X)));
3880 }
3881 static const char *DOW[] = {
3882 "sun",
3883 "mon",
3884 "tue",
3885 "wed",
3886 "thu",
3887 "fri",
3888 "sat"
3889 };
3890
3891 SWITCH_DECLARE(const char *) switch_dow_int2str(int val) {
3892 if (val >= switch_arraylen(DOW)) {
3893 val = val % switch_arraylen(DOW);
3894 }
3895 return DOW[val];
3896 }
3897
3898 SWITCH_DECLARE(int) switch_dow_str2int(const char *exp) {
3899 int ret = -1;
3900 int x;
3901
3902 for (x = 0; x < switch_arraylen(DOW); x++) {
3903 if (!strncasecmp(DOW[x], exp, 3)) {
3904 ret = x + 1;
3905 break;
3906 }
3907 }
3908 return ret;
3909 }
3910
3911 typedef enum {
3912 DOW_ERR = -2,
3913 DOW_EOF = -1,
3914 DOW_SUN = 1,
3915 DOW_MON,
3916 DOW_TUE,
3917 DOW_WED,
3918 DOW_THU,
3919 DOW_FRI,
3920 DOW_SAT,
3921 DOW_HYPHEN = '-',
3922 DOW_COMA = ','
3923 } dow_t;
3924
3925 static inline dow_t _dow_read_token(const char **s)
3926 {
3927 int i;
3928
3929 if (**s == '-') {
3930 (*s)++;
3931 return DOW_HYPHEN;
3932 } else if (**s == ',') {
3933 (*s)++;
3934 return DOW_COMA;
3935 } else if (**s >= '1' && **s <= '7') {
3936 dow_t r = **s - '0';
3937 (*s)++;
3938 return r;
3939 } else if ((i = switch_dow_str2int(*s)) && i != -1) {
3940 (*s) += 3;
3941 return i;
3942 } else if (!**s) {
3943 return DOW_EOF;
3944 } else {
3945 return DOW_ERR;
3946 }
3947 }
3948
3949 SWITCH_DECLARE(switch_bool_t) switch_dow_cmp(const char *exp, int val)
3950 {
3951 dow_t cur, prev = DOW_EOF, range_start = DOW_EOF;
3952 const char *p = exp;
3953
3954 while ((cur = _dow_read_token(&p)) != DOW_EOF) {
3955 if (cur == DOW_COMA) {
3956 /* Reset state */
3957 cur = DOW_EOF;
3958 } else if (cur == DOW_HYPHEN) {
3959 /* Save the previous token and move to the next one */
3960 range_start = prev;
3961 } else if (cur == DOW_ERR) {
3962 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse error for [%s] at position %ld (%.6s)\n", exp, (long) (p - exp), p);
3963 break;
3964 } else {
3965 /* Valid day found */
3966 if (range_start != DOW_EOF) { /* Evaluating a range */
3967 if (range_start <= cur ? (val >= range_start && val <= cur) : (val >= range_start || val <= cur)) {
3968 return SWITCH_TRUE;
3969 }
3970 range_start = DOW_EOF;
3971 } else if (val == cur) {
3972 return SWITCH_TRUE;
3973 }
3974 }
3975
3976 prev = cur;
3977 }
3978
3979 return SWITCH_FALSE;
3980 }
3981
3982 SWITCH_DECLARE(int) switch_number_cmp(const char *exp, int val)
3983 {
3984 // Expression exp must be a comma separated list of numbers or ranges.
3985 // To match numbers not in range 9-17, enter the reversed range 18-8.
3986 for (;; ++exp) {
3987 int a = strtol(exp, (char **)&exp, 10);
3988 if (*exp != '-') {
3989 if (a == val)
3990 return 1;
3991 } else {
3992 int b = strtol(++exp, (char **)&exp, 10);
3993 if (a <= b ? (val >= a && val <=b ) : (val >= a || val <= b))
3994 return 1;
3995 }
3996 if (*exp != ',')
3997 return 0;
3998 }
3999 }
4000
4001 SWITCH_DECLARE(int) switch_tod_cmp(const char *exp, int val)
4002 {
4003 char *dup = strdup(exp);
4004 char *minh;
4005 char *minm;
4006 char *mins;
4007 char *maxh;
4008 char *maxm;
4009 char *maxs;
4010 char *cur;
4011 char *p;
4012 int range_start, range_end;
4013
4014 switch_assert(dup);
4015
4016 cur = dup;
4017 if ((p = strchr(cur, ','))) {
4018 *p++ = '\0';
4019 }
4020
4021 while (cur) {
4022 minh = cur;
4023 if ((minm=strchr(cur, ':'))) {
4024 *minm++ = '\0';
4025 if ((maxh=strchr(minm, '-'))) {
4026 if ((maxm=strchr(maxh, ':'))) {
4027 *maxh++ = '\0';
4028 *maxm++ = '\0';
4029 /* Check if min/max seconds are present */
4030 if ((mins=strchr(minm, ':'))) {
4031 *mins++ = '\0';
4032 } else {
4033 mins = "00";
4034 }
4035 if ((maxs=strchr(maxm, ':'))) {
4036 *maxs++ = '\0';
4037 } else {
4038 maxs = "00";
4039 }
4040
4041 range_start = (atol(minh) * 60 * 60) + (atol(minm) * 60) + atol(mins);
4042 range_end = (atol(maxh) * 60 * 60) + (atol(maxm) * 60) + atol(maxs);
4043 if (range_start <= range_end ? (val >= range_start && val <= range_end) : (val >= range_start || val <= range_end)) {
4044 switch_safe_free(dup);
4045 return 1;
4046 }
4047 }
4048 }
4049 }
4050
4051 cur = p;
4052 if (p) {
4053 if ((p = strchr(p, ','))) {
4054 *p++ = '\0';
4055 }
4056 }
4057
4058 }
4059
4060 switch_safe_free(dup);
4061 return 0;
4062
4063 }
4064
4065 SWITCH_DECLARE(int) switch_split_user_domain(char *in, char **user, char **domain)
4066 {
4067 char *p = NULL, *h = NULL, *u = NULL;
4068
4069 if (!in) return 0;
4070
4071 /* Remove URL scheme */
4072 if (!strncasecmp(in, "sip:", 4)) in += 4;
4073 else if (!strncasecmp(in, "sips:", 5)) in += 5;
4074
4075 /* Isolate the host part from the user part */
4076 if ((h = in, p = strchr(h, '@'))) *p = '\0', u = in, h = p+1;
4077
4078 /* Clean out the host part of any suffix */
4079 for (p = h; *p; p++)
4080 if (*p == ':' || *p == ';' || *p == ' ') {
4081 *p = '\0'; break;
4082 }
4083
4084 if (user) *user = u;
4085 if (domain) *domain = h;
4086 return 1;
4087 }
4088
4089
4090 SWITCH_DECLARE(char *) switch_uuid_str(char *buf, switch_size_t len)
4091 {
4092 switch_uuid_t uuid;
4093
4094 if (len < (SWITCH_UUID_FORMATTED_LENGTH + 1)) {
4095 switch_snprintf(buf, len, "INVALID");
4096 } else {
4097 switch_uuid_get(&uuid);
4098 switch_uuid_format(buf, &uuid);
4099 }
4100
4101 return buf;
4102 }
4103
4104
4105 SWITCH_DECLARE(char *) switch_format_number(const char *num)
4106 {
4107 char *r;
4108 size_t len;
4109 const char *p = num;
4110
4111 if (!p) {
4112 return (char*)p;
4113 }
4114
4115 if (zstr(p)) {
4116 return strdup(p);
4117 }
4118
4119 if (*p == '+') {
4120 p++;
4121 }
4122
4123 if (!switch_is_number(p)) {
4124 return strdup(p);
4125 }
4126
4127 len = strlen(p);
4128
4129 /* region 1, TBD add more....*/
4130 if (len == 11 && p[0] == '1') {
4131 r = switch_mprintf("%c (%c%c%c) %c%c%c-%c%c%c%c", p[0],p[1],p[2],p[3],p[4],p[5],p[6],p[7],p[8],p[9],p[10]);
4132 } else if (len == 10) {
4133 r = switch_mprintf("1 (%c%c%c) %c%c%c-%c%c%c%c", p[0],p[1],p[2],p[3],p[4],p[5],p[6],p[7],p[8],p[9]);
4134 } else {
4135 r = strdup(num);
4136 }
4137
4138 return r;
4139 }
4140
4141
4142 SWITCH_DECLARE(unsigned int) switch_atoui(const char *nptr)
4143 {
4144 int tmp = atoi(nptr);
4145 if (tmp < 0) return 0;
4146 else return (unsigned int) tmp;
4147 }
4148
4149 SWITCH_DECLARE(unsigned long) switch_atoul(const char *nptr)
4150 {
4151 long tmp = atol(nptr);
4152 if (tmp < 0) return 0;
4153 else return (unsigned long) tmp;
4154 }
4155
4156
4157 SWITCH_DECLARE(char *) switch_strerror_r(int errnum, char *buf, switch_size_t buflen)
4158 {
4159 #ifdef HAVE_STRERROR_R
4160 #ifdef STRERROR_R_CHAR_P
4161 /* GNU variant returning char *, avoids warn-unused-result error */
4162 return strerror_r(errnum, buf, buflen);
4163 #else
4164 /*
4165 * XSI variant returning int, with GNU compatible error string,
4166 * if no message could be found
4167 */
4168 if (strerror_r(errnum, buf, buflen)) {
4169 switch_snprintf(buf, buflen, "Unknown error %d", errnum);
4170 }
4171 return buf;
4172 #endif /* STRERROR_R_CHAR_P */
4173 #elif defined(WIN32)
4174 /* WIN32 variant */
4175 if (strerror_s(buf, buflen, errnum)) {
4176 switch_snprintf(buf, buflen, "Unknown error %d", errnum);
4177 }
4178 return buf;
4179 #else
4180 /* Fallback, copy string into private buffer */
4181 switch_copy_string(buf, strerror(errnum), buflen);
4182 return buf;
4183 #endif
4184 }
4185
4186 SWITCH_DECLARE(void) switch_http_parse_qs(switch_http_request_t *request, char *qs)
4187 {
4188 char *q;
4189 char *next;
4190 char *name, *val;
4191 char *dup = NULL;
4192
4193 if (qs) {
4194 q = qs;
4195 } else { /*parse our own qs, dup to avoid modify the original string */
4196 dup = q = strdup(request->qs);
4197 }
4198
4199 switch_assert(q);
4200 next = q;
4201
4202 do {
4203 char *p;
4204
4205 if ((next = strchr(next, '&'))) {
4206 *next++ = '\0';
4207 }
4208
4209 for (p = q; p && *p; p++) {
4210 if (*p == '+') *p = ' ';
4211 }
4212
4213 switch_url_decode(q);
4214
4215 name = q;
4216 if ((val = strchr(name, '='))) {
4217 *val++ = '\0';
4218 switch_event_add_header_string(request->headers, SWITCH_STACK_BOTTOM, name, val);
4219 }
4220 q = next;
4221 } while (q);
4222
4223 switch_safe_free(dup);
4224 }
4225
4226 /* clean the uri to protect us from vulnerability attack */
4227 switch_status_t clean_uri(char *uri)
4228 {
4229 int argc;
4230 char *argv[64];
4231 int last, i, len, uri_len = 0;
4232
4233 argc = switch_separate_string(uri, '/', argv, sizeof(argv) / sizeof(argv[0]));
4234
4235 if (argc == sizeof(argv)) { /* too deep */
4236 return SWITCH_STATUS_FALSE;
4237 }
4238
4239 last = 1;
4240 for(i = 1; i < argc; i++) {
4241 if (*argv[i] == '\0' || !strcmp(argv[i], ".")) {
4242 /* ignore //// or /././././ */
4243 } else if (!strcmp(argv[i], "..")) {
4244 /* got /../, go up one level */
4245 if (last > 1) last--;
4246 } else {
4247 argv[last++] = argv[i];
4248 }
4249 }
4250
4251 for(i = 1; i < last; i++) {
4252 len = strlen(argv[i]);
4253 sprintf(uri + uri_len, "/%s", argv[i]);
4254 uri_len += (len + 1);
4255 }
4256
4257 return SWITCH_STATUS_SUCCESS;
4258 }
4259
4260 SWITCH_DECLARE(switch_status_t) switch_http_parse_header(char *buffer, uint32_t datalen, switch_http_request_t *request)
4261 {
4262 switch_status_t status = SWITCH_STATUS_FALSE;
4263 char *p = buffer;
4264 int i = 10;
4265 char *http = NULL;
4266 int header_count;
4267 char *headers[64] = { 0 };
4268 int argc;
4269 char *argv[2] = { 0 };
4270 char *body = NULL;
4271
4272 if (datalen < 16) return status; /* minimum GET / HTTP/1.1\r\n */
4273
4274 while(i--) { // sanity check
4275 if (*p++ == ' ') break;
4276 }
4277
4278 if (i == 0) return status;
4279
4280 if ((body = strstr(buffer, "\r\n\r\n"))) {
4281 *body = '\0';
4282 body += 4;
4283 } else if (( body = strstr(buffer, "\n\n"))) {
4284 *body = '\0';
4285 body += 2;
4286 } else {
4287 return status;
4288 }
4289
4290 request->_buffer = strdup(buffer);
4291 switch_assert(request->_buffer);
4292 request->method = request->_buffer;
4293 request->bytes_buffered = datalen;
4294 request->bytes_header = body - buffer;
4295 request->bytes_read = body - buffer;
4296
4297 p = strchr(request->method, ' ');
4298
4299 if (!p) goto err;
4300
4301 *p++ = '\0';
4302
4303 if (*p != '/') goto err; /* must start from '/' */
4304
4305 request->uri = p;
4306 p = strchr(request->uri, ' ');
4307
4308 if (!p) goto err;
4309
4310 *p++ = '\0';
4311 http = p;
4312
4313 p = strchr(request->uri, '?');
4314
4315 if (p) {
4316 *p++ = '\0';
4317 request->qs = p;
4318 }
4319
4320 if (clean_uri((char *)request->uri) != SWITCH_STATUS_SUCCESS) {
4321 goto err;
4322 }
4323
4324 if (!strncmp(http, "HTTP/1.1", 8)) {
4325 request->keepalive = SWITCH_TRUE;
4326 } else if (strncmp(http, "HTTP/1.0", 8)) {
4327 goto err;
4328 }
4329
4330 if (!request->headers) {
4331 if (switch_event_create(&request->headers, SWITCH_EVENT_CHANNEL_DATA) != SWITCH_STATUS_SUCCESS) {
4332 goto err;
4333 }
4334 request->_destroy_headers = SWITCH_TRUE;
4335 }
4336
4337 p = strchr(http, '\n');
4338
4339 if (p) {
4340 *p++ = '\0'; // now the first header
4341 } else {
4342 goto noheader;
4343 }
4344
4345 header_count = switch_separate_string(p, '\n', headers, sizeof(headers)/ sizeof(headers[0]));
4346
4347 if (header_count < 1) goto err;
4348
4349 for (i = 0; i < header_count; i++) {
4350 char *header, *value;
4351 int len;
4352
4353 argc = switch_separate_string(headers[i], ':', argv, 2);
4354
4355 if (argc != 2) goto err;
4356
4357 header = argv[0];
4358 value = argv[1];
4359
4360 if (*value == ' ') value++;
4361
4362 len = strlen(value);
4363
4364 if (len && *(value + len - 1) == '\r') *(value + len - 1) = '\0';
4365
4366 switch_event_add_header_string(request->headers, SWITCH_STACK_BOTTOM, header, value);
4367
4368 if (!strncasecmp(header, "User-Agent", 10)) {
4369 request->user_agent = value;
4370 } else if (!strncasecmp(header, "Host", 4)) {
4371 request->host = value;
4372 p = strchr(value, ':');
4373
4374 if (p) {
4375 *p++ = '\0';
4376
4377 if (*p) request->port = (switch_port_t)atoi(p);
4378 }
4379 } else if (!strncasecmp(header, "Content-Type", 12)) {
4380 request->content_type = value;
4381 } else if (!strncasecmp(header, "Content-Length", 14)) {
4382 request->content_length = atoi(value);
4383 } else if (!strncasecmp(header, "Referer", 7)) {
4384 request->referer = value;
4385 }
4386 }
4387
4388 noheader:
4389
4390 if (request->qs) {
4391 switch_http_parse_qs(request, NULL);
4392 }
4393
4394 return SWITCH_STATUS_SUCCESS;
4395
4396 err:
4397 switch_http_free_request(request);
4398 return status;
4399 }
4400
4401 SWITCH_DECLARE(void) switch_http_free_request(switch_http_request_t *request)
4402 {
4403 if (request->_buffer) free(request->_buffer);
4404 if (request->_destroy_headers && request->headers) {
4405 switch_event_destroy(&request->headers);
4406 }
4407 }
4408
4409 /* for debugging only */
4410 SWITCH_DECLARE(void) switch_http_dump_request(switch_http_request_t *request)
4411 {
4412 switch_assert(request->method);
4413
4414 printf("method: %s\n", request->method);
4415
4416 if (request->uri) printf("uri: %s\n", request->uri);
4417 if (request->qs) printf("qs: %s\n", request->qs);
4418 if (request->host) printf("host: %s\n", request->host);
4419 if (request->port) printf("port: %d\n", request->port);
4420 if (request->from) printf("from: %s\n", request->from);
4421 if (request->user_agent) printf("user_agent: %s\n", request->user_agent);
4422 if (request->referer) printf("referer: %s\n", request->referer);
4423 if (request->user) printf("user: %s\n", request->user);
4424 if (request->keepalive) printf("uri: %d\n", request->keepalive);
4425 if (request->content_type) printf("uri: %s\n", request->content_type);
4426 if (request->content_length) printf("uri: %" SWITCH_SIZE_T_FMT "\n", request->content_length);
4427
4428 {
4429 switch_event_header_t *header = request->headers->headers;
4430
4431 printf("headers:\n-------------------------\n");
4432
4433 while(header) {
4434 printf("%s: %s\n", header->name, header->value);
4435 header = header->next;
4436 }
4437 }
4438 }
4439
4440 SWITCH_DECLARE(void) switch_getcputime(switch_cputime *t)
4441 {
4442 #if defined(_WIN32)
4443 FILETIME ct, et, kt, ut; // Times are in 100-ns ticks (div 10000 to get ms)
4444 GetProcessTimes(GetCurrentProcess(), &ct, &et, &kt, &ut);
4445 t->userms = ((int64_t)ut.dwLowDateTime | ((int64_t)ut.dwHighDateTime << 32)) / 10000;
4446 t->kernelms = ((int64_t)kt.dwLowDateTime | ((int64_t)kt.dwHighDateTime << 32)) / 10000;
4447 #elif defined(HAVE_GETRUSAGE)
4448 struct rusage r;
4449 getrusage(RUSAGE_SELF, &r);
4450 t->userms = r.ru_utime.tv_sec * 1000 + r.ru_utime.tv_usec / 1000;
4451 t->kernelms = r.ru_stime.tv_sec * 1000 + r.ru_stime.tv_usec / 1000;
4452 #else
4453 t->userms = -1;
4454 t->kernelms = -1;
4455 #endif
4456 }
4457
4458
4459 #ifdef SWITCH_HAVE_GUMBO
4460 static void process(GumboNode *node, switch_stream_handle_t *stream)
4461 {
4462 if (node->type == GUMBO_NODE_TEXT) {
4463 stream->write_function(stream, "%s", node->v.text.text);
4464 return;
4465 } else if (node->type == GUMBO_NODE_ELEMENT && node->v.element.tag != GUMBO_TAG_SCRIPT && node->v.element.tag != GUMBO_TAG_STYLE) {
4466 GumboVector *children = &node->v.element.children;
4467 int i;
4468
4469 if (node->v.element.tag != GUMBO_TAG_UNKNOWN && node->v.element.tag <= GUMBO_TAG_LAST) {
4470 GumboAttribute* attr = NULL;
4471 const char *aval = NULL;
4472
4473 if (node->v.element.tag == GUMBO_TAG_SPAN) {
4474 if ((attr = gumbo_get_attribute(&node->v.element.attributes, "class"))) {
4475 aval = attr->value;
4476 }
4477 }
4478
4479 if (aval && !strcasecmp(aval, "Apple-converted-space")) {
4480 const char *txt = ((GumboNode*)children->data[0])->v.text.text;
4481 int x, len = 0;
4482
4483 for (x = 0; txt[x]; x++) {
4484 if (txt[x] == ' ') {
4485 len++;
4486 }
4487 }
4488
4489 for (x = 0; x < len*2; x++) {
4490 stream->write_function(stream, "%s", " ");
4491 }
4492 } else {
4493 for (i = 0; i < children->length; ++i) {
4494 process((GumboNode*) children->data[i], stream);
4495 }
4496 }
4497
4498 if (node->v.element.tag == GUMBO_TAG_P || node->v.element.tag == GUMBO_TAG_BR) {
4499 stream->write_function(stream, "%s", "\n");
4500 }
4501
4502 }
4503 }
4504 }
4505 #endif
4506
4507 SWITCH_DECLARE(char *)switch_html_strip(const char *str)
4508 {
4509 char *p, *html = NULL, *text = NULL;
4510 int x = 0, got_ct = 0;
4511 #ifdef SWITCH_HAVE_GUMBO
4512 GumboOutput *output;
4513 switch_stream_handle_t stream;
4514
4515 SWITCH_STANDARD_STREAM(stream);
4516 #endif
4517
4518 for(p = (char *)str; p && *p; p++) {
4519
4520 if (!strncasecmp(p, "Content-Type:", 13)) {
4521 got_ct++;
4522 }
4523
4524 if (!got_ct) continue;
4525
4526 if (*p == '\n') {
4527 x++;
4528 if (x == 2) {
4529 break;
4530 }
4531 } else if (x && (*p != '\r')) {
4532 x = 0;
4533 }
4534 }
4535
4536 html = p;
4537
4538 #ifdef SWITCH_HAVE_GUMBO
4539 if ((output = gumbo_parse_with_options(&kGumboDefaultOptions, html, strlen(html)))) {
4540 process(output->root, &stream);
4541 gumbo_destroy_output(&kGumboDefaultOptions, output);
4542 }
4543
4544 text = (char *)stream.data;
4545 #else
4546 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Support for html parser is not compiled.\n");
4547 text = switch_safe_strdup(html);
4548 #endif
4549
4550 return text;
4551 }
4552
4553 SWITCH_DECLARE(unsigned long) switch_getpid(void)
4554 {
4555 #ifndef WIN32
4556 pid_t pid = getpid();
4557 #else
4558 int pid = _getpid();
4559 #endif
4560
4561 return (unsigned long)pid;
4562 }
4563
4564 SWITCH_DECLARE(switch_status_t) switch_digest(const char *digest_name, unsigned char **digest, const void *input, switch_size_t inputLen, unsigned int *outputlen)
4565 {
4566 #if defined(HAVE_OPENSSL)
4567 EVP_MD_CTX *mdctx;
4568 const EVP_MD *md;
4569 int size;
4570
4571 switch_assert(digest);
4572
4573 if (!digest_name) {
4574 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Message digest is not set\n");
4575 return SWITCH_STATUS_FALSE;
4576 }
4577
4578 md = EVP_get_digestbyname(digest_name);
4579
4580 if (!md) {
4581 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown message digest %s\n", digest_name);
4582 return SWITCH_STATUS_FALSE;
4583 }
4584
4585 size = EVP_MD_size(md);
4586 if (!size || !(*digest = malloc(size))) {
4587 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Zero digest size or can't allocate memory to store results %s\n", digest_name);
4588 return SWITCH_STATUS_FALSE;
4589 }
4590
4591 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
4592 mdctx = EVP_MD_CTX_new();
4593 #else
4594 mdctx = EVP_MD_CTX_create();
4595 #endif
4596
4597 if (!mdctx) {
4598 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "EVP_MD_CTX_new error\n");
4599 switch_safe_free(*digest);
4600 return SWITCH_STATUS_FALSE;
4601 }
4602
4603 EVP_MD_CTX_init(mdctx);
4604 EVP_DigestInit_ex(mdctx, md, NULL);
4605 EVP_DigestUpdate(mdctx, input, inputLen);
4606 EVP_DigestFinal_ex(mdctx, *digest, outputlen);
4607
4608 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
4609 EVP_MD_CTX_free(mdctx);
4610 #else
4611 EVP_MD_CTX_destroy(mdctx);
4612 #endif
4613
4614 return SWITCH_STATUS_SUCCESS;
4615 #else
4616 return SWITCH_STATUS_FALSE;
4617 #endif
4618 }
4619
4620 SWITCH_DECLARE(switch_status_t) switch_digest_string(const char *digest_name, char **digest_str, const void *input, switch_size_t inputLen, unsigned int *outputlen)
4621 {
4622 unsigned char *digest = NULL;
4623 switch_status_t status;
4624 short i = 0, x;
4625 uint8_t b;
4626
4627 status = switch_digest(digest_name, &digest, input, inputLen, outputlen);
4628
4629 if (status == SWITCH_STATUS_SUCCESS) {
4630 if ((*digest_str = malloc(*outputlen * 2 + 1))) {
4631 for (x = i = 0; x < *outputlen; x++) {
4632 b = (digest[x] >> 4) & 15;
4633 (*digest_str)[i++] = b + (b > 9 ? 'a' - 10 : '0');
4634 b = digest[x] & 15;
4635 (*digest_str)[i++] = b + (b > 9 ? 'a' - 10 : '0');
4636 }
4637
4638 (*digest_str)[i] = '\0';
4639 } else {
4640 switch_safe_free(digest);
4641 *outputlen = 0;
4642 return SWITCH_STATUS_FALSE;
4643 }
4644 }
4645
4646 switch_safe_free(digest);
4647 *outputlen = i;
4648
4649 return status;
4650 }
4651
4652 SWITCH_DECLARE(char *) switch_must_strdup(const char *_s)
4653 {
4654 char *s = strdup(_s);
4655 switch_assert(s);
4656 return s;
4657 }
4658
4659 SWITCH_DECLARE(const char *) switch_memory_usage_stream(switch_stream_handle_t *stream)
4660 {
4661 const char *status = NULL;
4662 #ifdef __GLIBC__
4663 /*
4664 * The mallinfo2() function was added in glibc 2.33.
4665 * https://man7.org/linux/man-pages/man3/mallinfo.3.html
4666 */
4667 #if defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2, 33)
4668 struct mallinfo2 mi;
4669
4670 mi = mallinfo2();
4671
4672 stream->write_function(stream, "Total non-mmapped bytes (arena): %" SWITCH_SIZE_T_FMT "\n", mi.arena);
4673 stream->write_function(stream, "# of free chunks (ordblks): %" SWITCH_SIZE_T_FMT "\n", mi.ordblks);
4674 stream->write_function(stream, "# of free fastbin blocks (smblks): %" SWITCH_SIZE_T_FMT "\n", mi.smblks);
4675 stream->write_function(stream, "# of mapped regions (hblks): %" SWITCH_SIZE_T_FMT "\n", mi.hblks);
4676 stream->write_function(stream, "Bytes in mapped regions (hblkhd): %" SWITCH_SIZE_T_FMT "\n", mi.hblkhd);
4677 stream->write_function(stream, "Max. total allocated space (usmblks): %" SWITCH_SIZE_T_FMT "\n", mi.usmblks);
4678 stream->write_function(stream, "Free bytes held in fastbins (fsmblks): %" SWITCH_SIZE_T_FMT "\n", mi.fsmblks);
4679 stream->write_function(stream, "Total allocated space (uordblks): %" SWITCH_SIZE_T_FMT "\n", mi.uordblks);
4680 stream->write_function(stream, "Total free space (fordblks): %" SWITCH_SIZE_T_FMT "\n", mi.fordblks);
4681 stream->write_function(stream, "Topmost releasable block (keepcost): %" SWITCH_SIZE_T_FMT "\n", mi.keepcost);
4682 #else
4683 struct mallinfo mi;
4684
4685 mi = mallinfo();
4686
4687 stream->write_function(stream, "Total non-mmapped bytes (arena): %u\n", mi.arena);
4688 stream->write_function(stream, "# of free chunks (ordblks): %u\n", mi.ordblks);
4689 stream->write_function(stream, "# of free fastbin blocks (smblks): %u\n", mi.smblks);
4690 stream->write_function(stream, "# of mapped regions (hblks): %u\n", mi.hblks);
4691 stream->write_function(stream, "Bytes in mapped regions (hblkhd): %u\n", mi.hblkhd);
4692 stream->write_function(stream, "Max. total allocated space (usmblks): %u\n", mi.usmblks);
4693 stream->write_function(stream, "Free bytes held in fastbins (fsmblks): %u\n", mi.fsmblks);
4694 stream->write_function(stream, "Total allocated space (uordblks): %u\n", mi.uordblks);
4695 stream->write_function(stream, "Total free space (fordblks): %u\n", mi.fordblks);
4696 stream->write_function(stream, "Topmost releasable block (keepcost): %u\n", mi.keepcost);
4697
4698 #endif
4699
4700 switch_goto_status(NULL, done);
4701 #else
4702 #ifdef WIN32
4703 /* Based on: https://docs.microsoft.com/en-us/windows/win32/memory/enumerating-a-heap and https://docs.microsoft.com/en-us/windows/win32/memory/getting-process-heaps */
4704 PHANDLE aHeaps;
4705 SIZE_T BytesToAllocate;
4706 DWORD HeapsIndex;
4707 DWORD HeapsLength;
4708 DWORD NumberOfHeaps;
4709 HRESULT Result;
4710 HANDLE hDefaultProcessHeap;
4711 size_t CommittedSizeTotal = 0;
4712 size_t UnCommittedSizeTotal = 0;
4713 size_t SizeTotal = 0;
4714 size_t OverheadTotal = 0;
4715
4716 NumberOfHeaps = GetProcessHeaps(0, NULL);
4717 Result = SIZETMult(NumberOfHeaps, sizeof(*aHeaps), &BytesToAllocate);
4718 if (Result != S_OK) {
4719 switch_goto_status("SIZETMult failed.", done);
4720 }
4721
4722 hDefaultProcessHeap = GetProcessHeap();
4723 if (hDefaultProcessHeap == NULL) {
4724 switch_goto_status("Failed to retrieve the default process heap", done);
4725 }
4726
4727 aHeaps = (PHANDLE)HeapAlloc(hDefaultProcessHeap, 0, BytesToAllocate);
4728 if (aHeaps == NULL) {
4729 switch_goto_status("HeapAlloc failed to allocate space for heaps", done);
4730 }
4731
4732 HeapsLength = NumberOfHeaps;
4733 NumberOfHeaps = GetProcessHeaps(HeapsLength, aHeaps);
4734
4735 if (NumberOfHeaps == 0) {
4736 switch_goto_status("Failed to retrieve heaps", cleanup);
4737 } else if (NumberOfHeaps > HeapsLength) {
4738 /*
4739 * Compare the latest number of heaps with the original number of heaps.
4740 * If the latest number is larger than the original number, another
4741 * component has created a new heap and the buffer is too small.
4742 */
4743 switch_goto_status("Another component created a heap between calls.", cleanup);
4744 }
4745
4746 stream->write_function(stream, "Process has %d heaps.\n", HeapsLength);
4747 for (HeapsIndex = 0; HeapsIndex < HeapsLength; ++HeapsIndex) {
4748 PROCESS_HEAP_ENTRY Entry;
4749 HANDLE hHeap = aHeaps[HeapsIndex];
4750
4751 stream->write_function(stream, "Heap %d at address: %#p.\n", HeapsIndex, aHeaps[HeapsIndex]);
4752
4753 /* Lock the heap to prevent other threads from accessing the heap during enumeration. */
4754 if (HeapLock(hHeap) == FALSE) {
4755 switch_goto_status("Failed to lock heap.", cleanup);
4756 }
4757
4758 Entry.lpData = NULL;
4759 while (HeapWalk(hHeap, &Entry) != FALSE) {
4760 if ((Entry.wFlags & PROCESS_HEAP_ENTRY_BUSY) != 0) {
4761 } else if ((Entry.wFlags & PROCESS_HEAP_REGION) != 0) {
4762 CommittedSizeTotal += Entry.Region.dwCommittedSize;
4763 UnCommittedSizeTotal += Entry.Region.dwUnCommittedSize;
4764 }
4765
4766 SizeTotal += Entry.cbData;
4767 OverheadTotal += Entry.cbOverhead;
4768 }
4769
4770 /* Unlock the heap to allow other threads to access the heap after enumeration has completed. */
4771 if (HeapUnlock(hHeap) == FALSE) {
4772 abort();
4773 }
4774 }
4775
4776 stream->write_function(stream, "Committed bytes: %" SWITCH_SIZE_T_FMT "\n", CommittedSizeTotal);
4777 stream->write_function(stream, "Uncommited bytes: %" SWITCH_SIZE_T_FMT "\n", UnCommittedSizeTotal);
4778 stream->write_function(stream, "Size: %" SWITCH_SIZE_T_FMT "\n", SizeTotal);
4779 stream->write_function(stream, "Overhead: %" SWITCH_SIZE_T_FMT"\n", OverheadTotal);
4780
4781 cleanup:
4782 HeapFree(hDefaultProcessHeap, 0, aHeaps);
4783 #else
4784 switch_goto_status("Memory usage statistics is not implemented on the current platform.", done);
4785 #endif
4786 #endif
4787 done:
4788 return status;
4789 }
4790
4791 /* For Emacs:
4792 * Local Variables:
4793 * mode:c
4794 * indent-tabs-mode:t
4795 * tab-width:4
4796 * c-basic-offset:4
4797 * End:
4798 * For VIM:
4799 * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
4800 */