71d1ee44842e23796eb9a9d0aea6f2dd6d4d5b52
[asterisk/asterisk.git] / asterisk.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Top level source file for asterisk
5  * 
6  * Copyright (C) 1999, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <unistd.h>
15 #include <stdlib.h>
16 #include <sys/poll.h>
17 #include <asterisk/logger.h>
18 #include <asterisk/options.h>
19 #include <asterisk/cli.h>
20 #include <asterisk/channel.h>
21 #include <asterisk/ulaw.h>
22 #include <asterisk/alaw.h>
23 #include <asterisk/callerid.h>
24 #include <asterisk/module.h>
25 #include <asterisk/image.h>
26 #include <asterisk/tdd.h>
27 #include <asterisk/term.h>
28 #include <asterisk/manager.h>
29 #include <asterisk/pbx.h>
30 #include <asterisk/enum.h>
31 #include <asterisk/rtp.h>
32 #include <asterisk/app.h>
33 #include <asterisk/lock.h>
34 #include <asterisk/utils.h>
35 #include <asterisk/file.h>
36 #include <sys/resource.h>
37 #include <fcntl.h>
38 #include <stdio.h>
39 #include <signal.h>
40 #include <sched.h>
41 #include <asterisk/io.h>
42 #include <asterisk/lock.h>
43 #include <sys/socket.h>
44 #include <sys/un.h>
45 #include <sys/wait.h>
46 #include <string.h>
47 #include <errno.h>
48 #include <ctype.h>
49 #include "editline/histedit.h"
50 #include "asterisk.h"
51 #include <asterisk/config.h>
52 #include <asterisk/config_pvt.h>
53 #include <sys/resource.h>
54 #include <grp.h>
55 #include <pwd.h>
56
57 #if  defined(__FreeBSD__)
58 #include <netdb.h>
59 #endif
60
61 #define AST_MAX_CONNECTS 128
62 #define NUM_MSGS 64
63
64 #define WELCOME_MESSAGE ast_verbose( "Asterisk " ASTERISK_VERSION ", Copyright (C) 1999-2004 Digium.\n"); \
65                 ast_verbose( "Written by Mark Spencer <markster@digium.com>\n"); \
66                 ast_verbose( "=========================================================================\n")
67
68 int option_verbose=0;
69 int option_debug=0;
70 int option_nofork=0;
71 int option_quiet=0;
72 int option_console=0;
73 int option_highpriority=0;
74 int option_remote=0;
75 int option_exec=0;
76 int option_initcrypto=0;
77 int option_nocolor;
78 int option_dumpcore = 0;
79 int option_overrideconfig = 0;
80 int option_reconnect = 0;
81 int fully_booted = 0;
82
83 static int ast_socket = -1;             /* UNIX Socket for allowing remote control */
84 static int ast_consock = -1;            /* UNIX Socket for controlling another asterisk */
85 int ast_mainpid;
86 struct console {
87         int fd;                                 /* File descriptor */
88         int p[2];                               /* Pipe */
89         pthread_t t;                    /* Thread of handler */
90 };
91
92 static struct ast_atexit {
93         void (*func)(void);
94         struct ast_atexit *next;
95 } *atexits = NULL;
96 AST_MUTEX_DEFINE_STATIC(atexitslock);
97
98 time_t ast_startuptime;
99 time_t ast_lastreloadtime;
100
101 static History *el_hist = NULL;
102 static EditLine *el = NULL;
103 static char *remotehostname;
104
105 struct console consoles[AST_MAX_CONNECTS];
106
107 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
108
109 static int ast_el_add_history(char *);
110 static int ast_el_read_history(char *);
111 static int ast_el_write_history(char *);
112
113 char ast_config_AST_CONFIG_DIR[AST_CONFIG_MAX_PATH];
114 char ast_config_AST_CONFIG_FILE[AST_CONFIG_MAX_PATH];
115 char ast_config_AST_MODULE_DIR[AST_CONFIG_MAX_PATH];
116 char ast_config_AST_SPOOL_DIR[AST_CONFIG_MAX_PATH];
117 char ast_config_AST_VAR_DIR[AST_CONFIG_MAX_PATH];
118 char ast_config_AST_LOG_DIR[AST_CONFIG_MAX_PATH];
119 char ast_config_AST_AGI_DIR[AST_CONFIG_MAX_PATH];
120 char ast_config_AST_DB[AST_CONFIG_MAX_PATH];
121 char ast_config_AST_KEY_DIR[AST_CONFIG_MAX_PATH];
122 char ast_config_AST_PID[AST_CONFIG_MAX_PATH];
123 char ast_config_AST_SOCKET[AST_CONFIG_MAX_PATH];
124 char ast_config_AST_RUN_DIR[AST_CONFIG_MAX_PATH];
125
126 static char *_argv[256];
127 static int shuttingdown = 0;
128 static int restartnow = 0;
129 static pthread_t consolethread = AST_PTHREADT_NULL;
130
131 int ast_register_atexit(void (*func)(void))
132 {
133         int res = -1;
134         struct ast_atexit *ae;
135         ast_unregister_atexit(func);
136         ae = malloc(sizeof(struct ast_atexit));
137         ast_mutex_lock(&atexitslock);
138         if (ae) {
139                 memset(ae, 0, sizeof(struct ast_atexit));
140                 ae->next = atexits;
141                 ae->func = func;
142                 atexits = ae;
143                 res = 0;
144         }
145         ast_mutex_unlock(&atexitslock);
146         return res;
147 }
148
149 void ast_unregister_atexit(void (*func)(void))
150 {
151         struct ast_atexit *ae, *prev = NULL;
152         ast_mutex_lock(&atexitslock);
153         ae = atexits;
154         while(ae) {
155                 if (ae->func == func) {
156                         if (prev)
157                                 prev->next = ae->next;
158                         else
159                                 atexits = ae->next;
160                         break;
161                 }
162                 prev = ae;
163                 ae = ae->next;
164         }
165         ast_mutex_unlock(&atexitslock);
166 }
167
168 static int fdprint(int fd, const char *s)
169 {
170         return write(fd, s, strlen(s) + 1);
171 }
172
173 int ast_safe_system(const char *s)
174 {
175         /* XXX This function needs some optimization work XXX */
176         pid_t pid;
177         int x;
178         int res;
179         struct rusage rusage;
180         int status;
181         pid = fork();
182         if (pid == 0) {
183                 /* Close file descriptors and launch system command */
184                 for (x=STDERR_FILENO + 1; x<4096;x++) {
185                         close(x);
186                 }
187                 res = execl("/bin/sh", "/bin/sh", "-c", s, NULL);
188                 exit(1);
189         } else if (pid > 0) {
190                 for(;;) {
191                         res = wait4(pid, &status, 0, &rusage);
192                         if (res > -1) {
193                                 if (WIFEXITED(status))
194                                         res = WEXITSTATUS(status);
195                                 else
196                                         res = -1;
197                                 break;
198                         } else {
199                                 if (errno != EINTR) 
200                                         break;
201                         }
202                 }
203         } else {
204                 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
205                 res = -1;
206         }
207         return res;
208 }
209
210 /*
211  * write the string to all attached console clients
212  */
213 static void ast_network_puts(const char *string)
214 {
215         int x;
216         for (x=0;x<AST_MAX_CONNECTS; x++) {
217                 if (consoles[x].fd > -1) 
218                         fdprint(consoles[x].p[1], string);
219         }
220 }
221
222 /*
223  * write the string to the console, and all attached
224  * console clients
225  */
226 void ast_console_puts(const char *string)
227 {
228         fputs(string, stdout);
229         fflush(stdout);
230         ast_network_puts(string);
231 }
232
233 static void network_verboser(const char *s, int pos, int replace, int complete)
234         /* ARGUSED */
235 {
236         if (replace) {
237                 char *t = alloca(strlen(s) + 2);
238                 if (t) {
239                         sprintf(t, "\r%s", s);
240                         ast_network_puts(t);
241                 } else {
242                         ast_log(LOG_ERROR, "Out of memory\n");
243                         ast_network_puts(s);
244                 }
245         } else {
246                 ast_network_puts(s);
247         }
248 }
249
250 static pthread_t lthread;
251
252 static void *netconsole(void *vconsole)
253 {
254         struct console *con = vconsole;
255         char hostname[256];
256         char tmp[512];
257         int res;
258         struct pollfd fds[2];
259         
260         if (gethostname(hostname, sizeof(hostname)))
261                 strncpy(hostname, "<Unknown>", sizeof(hostname)-1);
262         snprintf(tmp, sizeof(tmp), "%s/%d/%s\n", hostname, ast_mainpid, ASTERISK_VERSION);
263         fdprint(con->fd, tmp);
264         for(;;) {
265                 fds[0].fd = con->fd;
266                 fds[0].events = POLLIN;
267                 fds[1].fd = con->p[0];
268                 fds[1].events = POLLIN;
269
270                 res = poll(fds, 2, -1);
271                 if (res < 0) {
272                         if (errno != EINTR)
273                                 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
274                         continue;
275                 }
276                 if (fds[0].revents) {
277                         res = read(con->fd, tmp, sizeof(tmp));
278                         if (res < 1) {
279                                 break;
280                         }
281                         tmp[res] = 0;
282                         ast_cli_command(con->fd, tmp);
283                 }
284                 if (fds[1].revents) {
285                         res = read(con->p[0], tmp, sizeof(tmp));
286                         if (res < 1) {
287                                 ast_log(LOG_ERROR, "read returned %d\n", res);
288                                 break;
289                         }
290                         res = write(con->fd, tmp, res);
291                         if (res < 1)
292                                 break;
293                 }
294         }
295         if (option_verbose > 2) 
296                 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n");
297         close(con->fd);
298         close(con->p[0]);
299         close(con->p[1]);
300         con->fd = -1;
301         
302         return NULL;
303 }
304
305 static void *listener(void *unused)
306 {
307         struct sockaddr_un sun;
308         int s;
309         int len;
310         int x;
311         int flags;
312         struct pollfd fds[1];
313         pthread_attr_t attr;
314         pthread_attr_init(&attr);
315         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
316         for(;;) {
317                 if (ast_socket < 0)
318                         return NULL;
319                 fds[0].fd = ast_socket;
320                 fds[0].events= POLLIN;
321                 s = poll(fds, 1, -1);
322                 if (s < 0) {
323                         if (errno != EINTR)
324                                 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
325                         continue;
326                 }
327                 len = sizeof(sun);
328                 s = accept(ast_socket, (struct sockaddr *)&sun, &len);
329                 if (s < 0) {
330                         if (errno != EINTR)
331                                 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
332                 } else {
333                         for (x=0;x<AST_MAX_CONNECTS;x++) {
334                                 if (consoles[x].fd < 0) {
335                                         if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
336                                                 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
337                                                 consoles[x].fd = -1;
338                                                 fdprint(s, "Server failed to create pipe\n");
339                                                 close(s);
340                                                 break;
341                                         }
342                                         flags = fcntl(consoles[x].p[1], F_GETFL);
343                                         fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
344                                         consoles[x].fd = s;
345                                         if (ast_pthread_create(&consoles[x].t, &attr, netconsole, &consoles[x])) {
346                                                 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
347                                                 consoles[x].fd = -1;
348                                                 fdprint(s, "Server failed to spawn thread\n");
349                                                 close(s);
350                                         }
351                                         break;
352                                 }
353                         }
354                         if (x >= AST_MAX_CONNECTS) {
355                                 fdprint(s, "No more connections allowed\n");
356                                 ast_log(LOG_WARNING, "No more connections allowed\n");
357                                 close(s);
358                         } else if (consoles[x].fd > -1) {
359                                 if (option_verbose > 2) 
360                                         ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection\n");
361                         }
362                 }
363         }
364         return NULL;
365 }
366
367 static int ast_makesocket(void)
368 {
369         struct sockaddr_un sun;
370         int res;
371         int x;
372         for (x=0;x<AST_MAX_CONNECTS;x++)        
373                 consoles[x].fd = -1;
374         unlink((char *)ast_config_AST_SOCKET);
375         ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
376         if (ast_socket < 0) {
377                 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
378                 return -1;
379         }               
380         memset(&sun, 0, sizeof(sun));
381         sun.sun_family = AF_LOCAL;
382         strncpy(sun.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sun.sun_path)-1);
383         res = bind(ast_socket, (struct sockaddr *)&sun, sizeof(sun));
384         if (res) {
385                 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", (char *)ast_config_AST_SOCKET, strerror(errno));
386                 close(ast_socket);
387                 ast_socket = -1;
388                 return -1;
389         }
390         res = listen(ast_socket, 2);
391         if (res < 0) {
392                 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", (char *)ast_config_AST_SOCKET, strerror(errno));
393                 close(ast_socket);
394                 ast_socket = -1;
395                 return -1;
396         }
397         ast_register_verbose(network_verboser);
398         ast_pthread_create(&lthread, NULL, listener, NULL);
399         return 0;
400 }
401
402 static int ast_tryconnect(void)
403 {
404         struct sockaddr_un sun;
405         int res;
406         ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
407         if (ast_consock < 0) {
408                 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
409                 return 0;
410         }
411         memset(&sun, 0, sizeof(sun));
412         sun.sun_family = AF_LOCAL;
413         strncpy(sun.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sun.sun_path)-1);
414         res = connect(ast_consock, (struct sockaddr *)&sun, sizeof(sun));
415         if (res) {
416                 close(ast_consock);
417                 ast_consock = -1;
418                 return 0;
419         } else
420                 return 1;
421 }
422
423 static void urg_handler(int num)
424 {
425         /* Called by soft_hangup to interrupt the poll, read, or other
426            system call.  We don't actually need to do anything though.  */
427         /* Cannot EVER ast_log from within a signal handler */
428         if (option_debug) 
429                 printf("Urgent handler\n");
430         signal(num, urg_handler);
431         return;
432 }
433
434 static void hup_handler(int num)
435 {
436         if (option_verbose > 1) 
437                 printf("Received HUP signal -- Reloading configs\n");
438         if (restartnow)
439                 execvp(_argv[0], _argv);
440         /* XXX This could deadlock XXX */
441         ast_module_reload();
442 }
443
444 static void child_handler(int sig)
445 {
446         /* Must not ever ast_log or ast_verbose within signal handler */
447         int n, status;
448
449         /*
450          * Reap all dead children -- not just one
451          */
452         for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
453                 ;
454         if (n == 0 && option_debug)     
455                 printf("Huh?  Child handler, but nobody there?\n");
456 }
457
458 static void set_title(char *text)
459 {
460         /* Set an X-term or screen title */
461         if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
462                 fprintf(stdout, "\033]2;%s\007", text);
463 }
464
465 static void set_icon(char *text)
466 {
467         if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
468                 fprintf(stdout, "\033]1;%s\007", text);
469 }
470
471 static int set_priority(int pri)
472 {
473         struct sched_param sched;
474         memset(&sched, 0, sizeof(sched));
475         /* We set ourselves to a high priority, that we might pre-empt everything
476            else.  If your PBX has heavy activity on it, this is a good thing.  */
477 #ifdef __linux__
478         if (pri) {  
479                 sched.sched_priority = 10;
480                 if (sched_setscheduler(0, SCHED_RR, &sched)) {
481                         ast_log(LOG_WARNING, "Unable to set high priority\n");
482                         return -1;
483                 } else
484                         if (option_verbose)
485                                 ast_verbose("Set to realtime thread\n");
486         } else {
487                 sched.sched_priority = 0;
488                 if (sched_setscheduler(0, SCHED_OTHER, &sched)) {
489                         ast_log(LOG_WARNING, "Unable to set normal priority\n");
490                         return -1;
491                 }
492         }
493 #else
494         if (pri) {
495                 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
496                         ast_log(LOG_WARNING, "Unable to set high priority\n");
497                         return -1;
498                 } else
499                         if (option_verbose)
500                                 ast_verbose("Set to high priority\n");
501         } else {
502                 if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
503                         ast_log(LOG_WARNING, "Unable to set normal priority\n");
504                         return -1;
505                 }
506         }
507 #endif
508         return 0;
509 }
510
511 static void ast_run_atexits(void)
512 {
513         struct ast_atexit *ae;
514         ast_mutex_lock(&atexitslock);
515         ae = atexits;
516         while(ae) {
517                 if (ae->func) 
518                         ae->func();
519                 ae = ae->next;
520         }
521         ast_mutex_unlock(&atexitslock);
522 }
523
524 static void quit_handler(int num, int nice, int safeshutdown, int restart)
525 {
526         char filename[80] = "";
527         time_t s,e;
528         int x;
529         if (safeshutdown) {
530                 shuttingdown = 1;
531                 if (!nice) {
532                         /* Begin shutdown routine, hanging up active channels */
533                         ast_begin_shutdown(1);
534                         if (option_verbose && option_console)
535                                 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
536                         time(&s);
537                         for(;;) {
538                                 time(&e);
539                                 /* Wait up to 15 seconds for all channels to go away */
540                                 if ((e - s) > 15)
541                                         break;
542                                 if (!ast_active_channels())
543                                         break;
544                                 if (!shuttingdown)
545                                         break;
546                                 /* Sleep 1/10 of a second */
547                                 usleep(100000);
548                         }
549                 } else {
550                         if (nice < 2)
551                                 ast_begin_shutdown(0);
552                         if (option_verbose && option_console)
553                                 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
554                         for(;;) {
555                                 if (!ast_active_channels())
556                                         break;
557                                 if (!shuttingdown)
558                                         break;
559                                 sleep(1);
560                         }
561                 }
562
563                 if (!shuttingdown) {
564                         if (option_verbose && option_console)
565                                 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
566                         return;
567                 }
568         }
569         if (option_console || option_remote) {
570                 if (getenv("HOME")) 
571                         snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
572                 if (!ast_strlen_zero(filename))
573                         ast_el_write_history(filename);
574                 if (el != NULL)
575                         el_end(el);
576                 if (el_hist != NULL)
577                         history_end(el_hist);
578         }
579         if (option_verbose)
580                 ast_verbose("Executing last minute cleanups\n");
581         ast_run_atexits();
582         /* Called on exit */
583         if (option_verbose && option_console)
584                 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
585         else if (option_debug)
586                 ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
587         manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
588         if (ast_socket > -1) {
589                 close(ast_socket);
590                 ast_socket = -1;
591         }
592         if (ast_consock > -1)
593                 close(ast_consock);
594         if (ast_socket > -1)
595                 unlink((char *)ast_config_AST_SOCKET);
596         if (!option_remote) unlink((char *)ast_config_AST_PID);
597         printf(term_quit());
598         if (restart) {
599                 if (option_verbose || option_console)
600                         ast_verbose("Preparing for Asterisk restart...\n");
601                 /* Mark all FD's for closing on exec */
602                 for (x=3;x<32768;x++) {
603                         fcntl(x, F_SETFD, FD_CLOEXEC);
604                 }
605                 if (option_verbose || option_console)
606                         ast_verbose("Restarting Asterisk NOW...\n");
607                 restartnow = 1;
608
609                 /* close logger */
610                 close_logger();
611
612                 /* If there is a consolethread running send it a SIGHUP 
613                    so it can execvp, otherwise we can do it ourselves */
614                 if (consolethread != AST_PTHREADT_NULL) {
615                         pthread_kill(consolethread, SIGHUP);
616                         /* Give the signal handler some time to complete */
617                         sleep(2);
618                 } else
619                         execvp(_argv[0], _argv);
620         
621         } else {
622                 /* close logger */
623                 close_logger();
624         }
625         exit(0);
626 }
627
628 static void __quit_handler(int num)
629 {
630         quit_handler(num, 0, 1, 0);
631 }
632
633 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
634 {
635         const char *c;
636         if (!strncmp(s, cmp, strlen(cmp))) {
637                 c = s + strlen(cmp);
638                 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
639                 return c;
640         }
641         return NULL;
642 }
643
644 static void console_verboser(const char *s, int pos, int replace, int complete)
645 {
646         char tmp[80];
647         const char *c=NULL;
648         /* Return to the beginning of the line */
649         if (!pos) {
650                 fprintf(stdout, "\r");
651                 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
652                         (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
653                         (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
654                         (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1)))
655                         fputs(tmp, stdout);
656         }
657         if (c)
658                 fputs(c + pos,stdout);
659         else
660                 fputs(s + pos,stdout);
661         fflush(stdout);
662         if (complete)
663         /* Wake up a poll()ing console */
664                 if (option_console && consolethread != AST_PTHREADT_NULL)
665                         pthread_kill(consolethread, SIGURG);
666 }
667
668 static int ast_all_zeros(char *s)
669 {
670         while(*s) {
671                 if (*s > 32)
672                         return 0;
673                 s++;  
674         }
675         return 1;
676 }
677
678 static void consolehandler(char *s)
679 {
680         printf(term_end());
681         fflush(stdout);
682         /* Called when readline data is available */
683         if (s && !ast_all_zeros(s))
684                 ast_el_add_history(s);
685         /* Give the console access to the shell */
686         if (s) {
687                 /* The real handler for bang */
688                 if (s[0] == '!') {
689                         if (s[1])
690                                 ast_safe_system(s+1);
691                         else
692                                 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
693                 } else 
694                 ast_cli_command(STDOUT_FILENO, s);
695         } else
696                 fprintf(stdout, "\nUse \"quit\" to exit\n");
697 }
698
699 static int remoteconsolehandler(char *s)
700 {
701         int ret = 0;
702         /* Called when readline data is available */
703         if (s && !ast_all_zeros(s))
704                 ast_el_add_history(s);
705         /* Give the console access to the shell */
706         if (s) {
707                 /* The real handler for bang */
708                 if (s[0] == '!') {
709                         if (s[1])
710                                 ast_safe_system(s+1);
711                         else
712                                 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
713                         ret = 1;
714                 }
715                 if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
716                     (s[4] == '\0' || isspace(s[4]))) {
717                         quit_handler(0, 0, 0, 0);
718                         ret = 1;
719                 }
720         } else
721                 fprintf(stdout, "\nUse \"quit\" to exit\n");
722
723         return ret;
724 }
725
726 static char quit_help[] = 
727 "Usage: quit\n"
728 "       Exits Asterisk.\n";
729
730 static char abort_halt_help[] = 
731 "Usage: abort shutdown\n"
732 "       Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
733 "       call operations.\n";
734
735 static char shutdown_now_help[] = 
736 "Usage: stop now\n"
737 "       Shuts down a running Asterisk immediately, hanging up all active calls .\n";
738
739 static char shutdown_gracefully_help[] = 
740 "Usage: stop gracefully\n"
741 "       Causes Asterisk to not accept new calls, and exit when all\n"
742 "       active calls have terminated normally.\n";
743
744 static char shutdown_when_convenient_help[] = 
745 "Usage: stop when convenient\n"
746 "       Causes Asterisk to perform a shutdown when all active calls have ended.\n";
747
748 static char restart_now_help[] = 
749 "Usage: restart now\n"
750 "       Causes Asterisk to hangup all calls and exec() itself performing a cold.\n"
751 "       restart.\n";
752
753 static char restart_gracefully_help[] = 
754 "Usage: restart gracefully\n"
755 "       Causes Asterisk to stop accepting new calls and exec() itself performing a cold.\n"
756 "       restart when all active calls have ended.\n";
757
758 static char restart_when_convenient_help[] = 
759 "Usage: restart when convenient\n"
760 "       Causes Asterisk to perform a cold restart when all active calls have ended.\n";
761
762 static char bang_help[] =
763 "Usage: !<command>\n"
764 "       Executes a given shell command\n";
765
766 #if 0
767 static int handle_quit(int fd, int argc, char *argv[])
768 {
769         if (argc != 1)
770                 return RESULT_SHOWUSAGE;
771         quit_handler(0, 0, 1, 0);
772         return RESULT_SUCCESS;
773 }
774 #endif
775
776 static int no_more_quit(int fd, int argc, char *argv[])
777 {
778         if (argc != 1)
779                 return RESULT_SHOWUSAGE;
780         ast_cli(fd, "The QUIT and EXIT commands may no longer be used to shutdown the PBX.\n"
781                     "Please use STOP NOW instead, if you wish to shutdown the PBX.\n");
782         return RESULT_SUCCESS;
783 }
784
785 static int handle_shutdown_now(int fd, int argc, char *argv[])
786 {
787         if (argc != 2)
788                 return RESULT_SHOWUSAGE;
789         quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
790         return RESULT_SUCCESS;
791 }
792
793 static int handle_shutdown_gracefully(int fd, int argc, char *argv[])
794 {
795         if (argc != 2)
796                 return RESULT_SHOWUSAGE;
797         quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
798         return RESULT_SUCCESS;
799 }
800
801 static int handle_shutdown_when_convenient(int fd, int argc, char *argv[])
802 {
803         if (argc != 3)
804                 return RESULT_SHOWUSAGE;
805         quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
806         return RESULT_SUCCESS;
807 }
808
809 static int handle_restart_now(int fd, int argc, char *argv[])
810 {
811         if (argc != 2)
812                 return RESULT_SHOWUSAGE;
813         quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
814         return RESULT_SUCCESS;
815 }
816
817 static int handle_restart_gracefully(int fd, int argc, char *argv[])
818 {
819         if (argc != 2)
820                 return RESULT_SHOWUSAGE;
821         quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
822         return RESULT_SUCCESS;
823 }
824
825 static int handle_restart_when_convenient(int fd, int argc, char *argv[])
826 {
827         if (argc != 3)
828                 return RESULT_SHOWUSAGE;
829         quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
830         return RESULT_SUCCESS;
831 }
832
833 static int handle_abort_halt(int fd, int argc, char *argv[])
834 {
835         if (argc != 2)
836                 return RESULT_SHOWUSAGE;
837         ast_cancel_shutdown();
838         shuttingdown = 0;
839         return RESULT_SUCCESS;
840 }
841
842 static int handle_bang(int fd, int argc, char *argv[])
843 {
844         return RESULT_SUCCESS;
845 }
846
847 #define ASTERISK_PROMPT "*CLI> "
848
849 #define ASTERISK_PROMPT2 "%s*CLI> "
850
851 static struct ast_cli_entry aborthalt = { { "abort", "halt", NULL }, handle_abort_halt, "Cancel a running halt", abort_halt_help };
852
853 static struct ast_cli_entry quit =      { { "quit", NULL }, no_more_quit, "Exit Asterisk", quit_help };
854 static struct ast_cli_entry astexit =   { { "exit", NULL }, no_more_quit, "Exit Asterisk", quit_help };
855
856 static struct ast_cli_entry astshutdownnow =    { { "stop", "now", NULL }, handle_shutdown_now, "Shut down Asterisk immediately", shutdown_now_help };
857 static struct ast_cli_entry astshutdowngracefully =     { { "stop", "gracefully", NULL }, handle_shutdown_gracefully, "Gracefully shut down Asterisk", shutdown_gracefully_help };
858 static struct ast_cli_entry astshutdownwhenconvenient =         { { "stop", "when","convenient", NULL }, handle_shutdown_when_convenient, "Shut down Asterisk at empty call volume", shutdown_when_convenient_help };
859 static struct ast_cli_entry astrestartnow =     { { "restart", "now", NULL }, handle_restart_now, "Restart Asterisk immediately", restart_now_help };
860 static struct ast_cli_entry astrestartgracefully =      { { "restart", "gracefully", NULL }, handle_restart_gracefully, "Restart Asterisk gracefully", restart_gracefully_help };
861 static struct ast_cli_entry astrestartwhenconvenient=   { { "restart", "when", "convenient", NULL }, handle_restart_when_convenient, "Restart Asterisk at empty call volume", restart_when_convenient_help };
862 static struct ast_cli_entry astbang = { { "!", NULL }, handle_bang, "Execute a shell command", bang_help };
863
864 static int ast_el_read_char(EditLine *el, char *cp)
865 {
866         int num_read=0;
867         int lastpos=0;
868         struct pollfd fds[2];
869         int res;
870         int max;
871         char buf[512];
872
873         for (;;) {
874                 max = 1;
875                 fds[0].fd = ast_consock;
876                 fds[0].events = POLLIN;
877                 if (!option_exec) {
878                         fds[1].fd = STDIN_FILENO;
879                         fds[1].events = POLLIN;
880                         max++;
881                 }
882                 res = poll(fds, max, -1);
883                 if (res < 0) {
884                         if (errno == EINTR)
885                                 continue;
886                         ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
887                         break;
888                 }
889
890                 if (!option_exec && fds[1].revents) {
891                         num_read = read(STDIN_FILENO, cp, 1);
892                         if (num_read < 1) {
893                                 break;
894                         } else 
895                                 return (num_read);
896                 }
897                 if (fds[0].revents) {
898                         res = read(ast_consock, buf, sizeof(buf) - 1);
899                         /* if the remote side disappears exit */
900                         if (res < 1) {
901                                 fprintf(stderr, "\nDisconnected from Asterisk server\n");
902                                 if (!option_reconnect) {
903                                         quit_handler(0, 0, 0, 0);
904                                 } else {
905                                         int tries;
906                                         int reconnects_per_second = 20;
907                                         fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
908                                         for (tries=0;tries<30 * reconnects_per_second;tries++) {
909                                                 if (ast_tryconnect()) {
910                                                         fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
911                                                         printf(term_quit());
912                                                         WELCOME_MESSAGE;
913                                                         break;
914                                                 } else {
915                                                         usleep(1000000 / reconnects_per_second);
916                                                 }
917                                         }
918                                         if (tries >= 30) {
919                                                 fprintf(stderr, "Failed to reconnect for 30 seconds.  Quitting.\n");
920                                                 quit_handler(0, 0, 0, 0);
921                                         }
922                                 }
923                         }
924
925                         buf[res] = '\0';
926
927                         if (!option_exec && !lastpos)
928                                 write(STDOUT_FILENO, "\r", 1);
929                         write(STDOUT_FILENO, buf, res);
930                         if ((buf[res-1] == '\n') || (buf[res-2] == '\n')) {
931                                 *cp = CC_REFRESH;
932                                 return(1);
933                         } else {
934                                 lastpos = 1;
935                         }
936                 }
937         }
938
939         *cp = '\0';
940         return (0);
941 }
942
943 static char *cli_prompt(EditLine *el)
944 {
945         static char prompt[200];
946         char *pfmt;
947         int color_used=0;
948         char term_code[20];
949
950         if ((pfmt = getenv("ASTERISK_PROMPT"))) {
951                 char *t = pfmt, *p = prompt;
952                 memset(prompt, 0, sizeof(prompt));
953                 while (*t != '\0' && *p < sizeof(prompt)) {
954                         if (*t == '%') {
955                                 char hostname[256];
956                                 int i;
957                                 struct timeval tv;
958                                 struct tm tm;
959 #ifdef linux
960                                 FILE *LOADAVG;
961 #endif
962                                 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
963
964                                 t++;
965                                 switch (*t) {
966                                         case 'C': /* color */
967                                                 t++;
968                                                 if (sscanf(t, "%d;%d%n", &fgcolor, &bgcolor, &i) == 2) {
969                                                         strncat(p, term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
970                                                         t += i - 1;
971                                                 } else if (sscanf(t, "%d%n", &fgcolor, &i) == 1) {
972                                                         strncat(p, term_color_code(term_code, fgcolor, 0, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
973                                                         t += i - 1;
974                                                 }
975
976                                                 /* If the color has been reset correctly, then there's no need to reset it later */
977                                                 if ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) {
978                                                         color_used = 0;
979                                                 } else {
980                                                         color_used = 1;
981                                                 }
982                                                 break;
983                                         case 'd': /* date */
984                                                 memset(&tm, 0, sizeof(struct tm));
985                                                 gettimeofday(&tv, NULL);
986                                                 if (localtime_r(&(tv.tv_sec), &tm)) {
987                                                         strftime(p, sizeof(prompt) - strlen(prompt), "%Y-%m-%d", &tm);
988                                                 }
989                                                 break;
990                                         case 'h': /* hostname */
991                                                 if (!gethostname(hostname, sizeof(hostname) - 1)) {
992                                                         strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
993                                                 } else {
994                                                         strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
995                                                 }
996                                                 break;
997                                         case 'H': /* short hostname */
998                                                 if (!gethostname(hostname, sizeof(hostname) - 1)) {
999                                                         for (i=0;i<sizeof(hostname);i++) {
1000                                                                 if (hostname[i] == '.') {
1001                                                                         hostname[i] = '\0';
1002                                                                         break;
1003                                                                 }
1004                                                         }
1005                                                         strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1006                                                 } else {
1007                                                         strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1008                                                 }
1009                                                 break;
1010 #ifdef linux
1011                                         case 'l': /* load avg */
1012                                                 t++;
1013                                                 if ((LOADAVG = fopen("/proc/loadavg", "r"))) {
1014                                                         float avg1, avg2, avg3;
1015                                                         int actproc, totproc, npid, which;
1016                                                         fscanf(LOADAVG, "%f %f %f %d/%d %d",
1017                                                                 &avg1, &avg2, &avg3, &actproc, &totproc, &npid);
1018                                                         if (sscanf(t, "%d", &which) == 1) {
1019                                                                 switch (which) {
1020                                                                         case 1:
1021                                                                                 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg1);
1022                                                                                 break;
1023                                                                         case 2:
1024                                                                                 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg2);
1025                                                                                 break;
1026                                                                         case 3:
1027                                                                                 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg3);
1028                                                                                 break;
1029                                                                         case 4:
1030                                                                                 snprintf(p, sizeof(prompt) - strlen(prompt), "%d/%d", actproc, totproc);
1031                                                                                 break;
1032                                                                         case 5:
1033                                                                                 snprintf(p, sizeof(prompt) - strlen(prompt), "%d", npid);
1034                                                                                 break;
1035                                                                 }
1036                                                         }
1037                                                 }
1038                                                 break;
1039 #endif
1040                                         case 't': /* time */
1041                                                 memset(&tm, 0, sizeof(struct tm));
1042                                                 gettimeofday(&tv, NULL);
1043                                                 if (localtime_r(&(tv.tv_sec), &tm)) {
1044                                                         strftime(p, sizeof(prompt) - strlen(prompt), "%H:%M:%S", &tm);
1045                                                 }
1046                                                 break;
1047                                         case '#': /* process console or remote? */
1048                                                 if (! option_remote) {
1049                                                         strncat(p, "#", sizeof(prompt) - strlen(prompt) - 1);
1050                                                 } else {
1051                                                         strncat(p, ">", sizeof(prompt) - strlen(prompt) - 1);
1052                                                 }
1053                                                 break;
1054                                         case '%': /* literal % */
1055                                                 strncat(p, "%", sizeof(prompt) - strlen(prompt) - 1);
1056                                                 break;
1057                                         case '\0': /* % is last character - prevent bug */
1058                                                 t--;
1059                                                 break;
1060                                 }
1061                                 while (*p != '\0') {
1062                                         p++;
1063                                 }
1064                                 t++;
1065                         } else {
1066                                 *p = *t;
1067                                 p++;
1068                                 t++;
1069                         }
1070                 }
1071                 if (color_used) {
1072                         /* Force colors back to normal at end */
1073                         term_color_code(term_code, COLOR_WHITE, COLOR_BLACK, sizeof(term_code));
1074                         if (strlen(term_code) > sizeof(prompt) - strlen(prompt)) {
1075                                 strncat(prompt + sizeof(prompt) - strlen(term_code) - 1, term_code, strlen(term_code));
1076                         } else {
1077                                 strncat(p, term_code, sizeof(term_code));
1078                         }
1079                 }
1080         } else if (remotehostname)
1081                 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname);
1082         else
1083                 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT);
1084
1085         return(prompt); 
1086 }
1087
1088 static char **ast_el_strtoarr(char *buf)
1089 {
1090         char **match_list = NULL, *retstr;
1091         size_t match_list_len;
1092         int matches = 0;
1093
1094         match_list_len = 1;
1095         while ( (retstr = strsep(&buf, " ")) != NULL) {
1096
1097                 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
1098                         break;
1099                 if (matches + 1 >= match_list_len) {
1100                         match_list_len <<= 1;
1101                         match_list = realloc(match_list, match_list_len * sizeof(char *));
1102                 }
1103
1104                 match_list[matches++] = strdup(retstr);
1105         }
1106
1107         if (!match_list)
1108                 return (char **) NULL;
1109
1110         if (matches>= match_list_len)
1111                 match_list = realloc(match_list, (match_list_len + 1) * sizeof(char *));
1112
1113         match_list[matches] = (char *) NULL;
1114
1115         return match_list;
1116 }
1117
1118 static int ast_el_sort_compare(const void *i1, const void *i2)
1119 {
1120         char *s1, *s2;
1121
1122         s1 = ((char **)i1)[0];
1123         s2 = ((char **)i2)[0];
1124
1125         return strcasecmp(s1, s2);
1126 }
1127
1128 static int ast_cli_display_match_list(char **matches, int len, int max)
1129 {
1130         int i, idx, limit, count;
1131         int screenwidth = 0;
1132         int numoutput = 0, numoutputline = 0;
1133
1134         screenwidth = ast_get_termcols(STDOUT_FILENO);
1135
1136         /* find out how many entries can be put on one line, with two spaces between strings */
1137         limit = screenwidth / (max + 2);
1138         if (limit == 0)
1139                 limit = 1;
1140
1141         /* how many lines of output */
1142         count = len / limit;
1143         if (count * limit < len)
1144                 count++;
1145
1146         idx = 1;
1147
1148         qsort(&matches[0], (size_t)(len + 1), sizeof(char *), ast_el_sort_compare);
1149
1150         for (; count > 0; count--) {
1151                 numoutputline = 0;
1152                 for (i=0; i < limit && matches[idx]; i++, idx++) {
1153
1154                         /* Don't print dupes */
1155                         if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
1156                                 i--;
1157                                 free(matches[idx]);
1158                                 matches[idx] = NULL;
1159                                 continue;
1160                         }
1161
1162                         numoutput++;  numoutputline++;
1163                         fprintf(stdout, "%-*s  ", max, matches[idx]);
1164                         free(matches[idx]);
1165                         matches[idx] = NULL;
1166                 }
1167                 if (numoutputline > 0)
1168                         fprintf(stdout, "\n");
1169         }
1170
1171         return numoutput;
1172 }
1173
1174
1175 static char *cli_complete(EditLine *el, int ch)
1176 {
1177         int len=0;
1178         char *ptr;
1179         int nummatches = 0;
1180         char **matches;
1181         int retval = CC_ERROR;
1182         char buf[2048];
1183         int res;
1184
1185         LineInfo *lf = (LineInfo *)el_line(el);
1186
1187         *(char *)lf->cursor = '\0';
1188         ptr = (char *)lf->cursor;
1189         if (ptr) {
1190                 while (ptr > lf->buffer) {
1191                         if (isspace(*ptr)) {
1192                                 ptr++;
1193                                 break;
1194                         }
1195                         ptr--;
1196                 }
1197         }
1198
1199         len = lf->cursor - ptr;
1200
1201         if (option_remote) {
1202                 snprintf(buf, sizeof(buf),"_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr); 
1203                 fdprint(ast_consock, buf);
1204                 res = read(ast_consock, buf, sizeof(buf));
1205                 buf[res] = '\0';
1206                 nummatches = atoi(buf);
1207
1208                 if (nummatches > 0) {
1209                         char *mbuf;
1210                         int mlen = 0, maxmbuf = 2048;
1211                         /* Start with a 2048 byte buffer */
1212                         mbuf = malloc(maxmbuf);
1213                         if (!mbuf)
1214                                 return (char *)(CC_ERROR);
1215                         snprintf(buf, sizeof(buf),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr); 
1216                         fdprint(ast_consock, buf);
1217                         res = 0;
1218                         mbuf[0] = '\0';
1219                         while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
1220                                 if (mlen + 1024 > maxmbuf) {
1221                                         /* Every step increment buffer 1024 bytes */
1222                                         maxmbuf += 1024;
1223                                         mbuf = realloc(mbuf, maxmbuf);
1224                                         if (!mbuf)
1225                                                 return (char *)(CC_ERROR);
1226                                 }
1227                                 /* Only read 1024 bytes at a time */
1228                                 res = read(ast_consock, mbuf + mlen, 1024);
1229                                 if (res > 0)
1230                                         mlen += res;
1231                         }
1232                         mbuf[mlen] = '\0';
1233
1234                         matches = ast_el_strtoarr(mbuf);
1235                         free(mbuf);
1236                 } else
1237                         matches = (char **) NULL;
1238
1239
1240         }  else {
1241
1242                 nummatches = ast_cli_generatornummatches((char *)lf->buffer,ptr);
1243                 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
1244         }
1245
1246         if (matches) {
1247                 int i;
1248                 int matches_num, maxlen, match_len;
1249
1250                 if (matches[0][0] != '\0') {
1251                         el_deletestr(el, (int) len);
1252                         el_insertstr(el, matches[0]);
1253                         retval = CC_REFRESH;
1254                 }
1255
1256                 if (nummatches == 1) {
1257                         /* Found an exact match */
1258                         el_insertstr(el, " ");
1259                         retval = CC_REFRESH;
1260                 } else {
1261                         /* Must be more than one match */
1262                         for (i=1, maxlen=0; matches[i]; i++) {
1263                                 match_len = strlen(matches[i]);
1264                                 if (match_len > maxlen)
1265                                         maxlen = match_len;
1266                         }
1267                         matches_num = i - 1;
1268                         if (matches_num >1) {
1269                                 fprintf(stdout, "\n");
1270                                 ast_cli_display_match_list(matches, nummatches, maxlen);
1271                                 retval = CC_REDISPLAY;
1272                         } else { 
1273                                 el_insertstr(el," ");
1274                                 retval = CC_REFRESH;
1275                         }
1276                 }
1277         free(matches);
1278         }
1279
1280         return (char *)(long)retval;
1281 }
1282
1283 static int ast_el_initialize(void)
1284 {
1285         HistEvent ev;
1286         char *editor = getenv("AST_EDITOR");
1287
1288         if (el != NULL)
1289                 el_end(el);
1290         if (el_hist != NULL)
1291                 history_end(el_hist);
1292
1293         el = el_init("asterisk", stdin, stdout, stderr);
1294         el_set(el, EL_PROMPT, cli_prompt);
1295
1296         el_set(el, EL_EDITMODE, 1);             
1297         el_set(el, EL_EDITOR, editor ? editor : "emacs");               
1298         el_hist = history_init();
1299         if (!el || !el_hist)
1300                 return -1;
1301
1302         /* setup history with 100 entries */
1303         history(el_hist, &ev, H_SETSIZE, 100);
1304
1305         el_set(el, EL_HIST, history, el_hist);
1306
1307         el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
1308         /* Bind <tab> to command completion */
1309         el_set(el, EL_BIND, "^I", "ed-complete", NULL);
1310         /* Bind ? to command completion */
1311         el_set(el, EL_BIND, "?", "ed-complete", NULL);
1312         /* Bind ^D to redisplay */
1313         el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
1314
1315         return 0;
1316 }
1317
1318 static int ast_el_add_history(char *buf)
1319 {
1320         HistEvent ev;
1321
1322         if (el_hist == NULL || el == NULL)
1323                 ast_el_initialize();
1324         if (strlen(buf) > 256)
1325                 return 0;
1326         return (history(el_hist, &ev, H_ENTER, buf));
1327 }
1328
1329 static int ast_el_write_history(char *filename)
1330 {
1331         HistEvent ev;
1332
1333         if (el_hist == NULL || el == NULL)
1334                 ast_el_initialize();
1335
1336         return (history(el_hist, &ev, H_SAVE, filename));
1337 }
1338
1339 static int ast_el_read_history(char *filename)
1340 {
1341         char buf[256];
1342         FILE *f;
1343         int ret = -1;
1344
1345         if (el_hist == NULL || el == NULL)
1346                 ast_el_initialize();
1347
1348         if ((f = fopen(filename, "r")) == NULL)
1349                 return ret;
1350
1351         while (!feof(f)) {
1352                 fgets(buf, sizeof(buf), f);
1353                 if (!strcmp(buf, "_HiStOrY_V2_\n"))
1354                         continue;
1355                 if (ast_all_zeros(buf))
1356                         continue;
1357                 if ((ret = ast_el_add_history(buf)) == -1)
1358                         break;
1359         }
1360         fclose(f);
1361
1362         return ret;
1363 }
1364
1365 static void ast_remotecontrol(char * data)
1366 {
1367         char buf[80];
1368         int res;
1369         char filename[80] = "";
1370         char *hostname;
1371         char *cpid;
1372         char *version;
1373         int pid;
1374         char tmp[80];
1375         char *stringp=NULL;
1376
1377         char *ebuf;
1378         int num = 0;
1379
1380         read(ast_consock, buf, sizeof(buf));
1381         if (data)
1382                 write(ast_consock, data, strlen(data) + 1);
1383         stringp=buf;
1384         hostname = strsep(&stringp, "/");
1385         cpid = strsep(&stringp, "/");
1386         version = strsep(&stringp, "\n");
1387         if (!version)
1388                 version = "<Version Unknown>";
1389         stringp=hostname;
1390         strsep(&stringp, ".");
1391         if (cpid)
1392                 pid = atoi(cpid);
1393         else
1394                 pid = -1;
1395         snprintf(tmp, sizeof(tmp), "set verbose atleast %d", option_verbose);
1396         fdprint(ast_consock, tmp);
1397         ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
1398         remotehostname = hostname;
1399         if (getenv("HOME")) 
1400                 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1401         if (el_hist == NULL || el == NULL)
1402                 ast_el_initialize();
1403
1404         el_set(el, EL_GETCFN, ast_el_read_char);
1405
1406         if (!ast_strlen_zero(filename))
1407                 ast_el_read_history(filename);
1408
1409         ast_cli_register(&quit);
1410         ast_cli_register(&astexit);
1411 #if 0
1412         ast_cli_register(&astshutdown);
1413 #endif  
1414         if (option_exec && data) {  /* hack to print output then exit if asterisk -rx is used */
1415                 char tempchar;
1416                 struct pollfd fds[0];
1417                 fds[0].fd = ast_consock;
1418                 fds[0].events = POLLIN;
1419                 fds[0].revents = 0;
1420                 while(poll(fds, 1, 100) > 0) {
1421                         ast_el_read_char(el, &tempchar);
1422                 }
1423                 return;
1424         }
1425         for(;;) {
1426                 ebuf = (char *)el_gets(el, &num);
1427
1428                 if (ebuf && !ast_strlen_zero(ebuf)) {
1429                         if (ebuf[strlen(ebuf)-1] == '\n')
1430                                 ebuf[strlen(ebuf)-1] = '\0';
1431                         if (!remoteconsolehandler(ebuf)) {
1432                                 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
1433                                 if (res < 1) {
1434                                         ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
1435                                         break;
1436                                 }
1437                         }
1438                 }
1439         }
1440         printf("\nDisconnected from Asterisk server\n");
1441 }
1442
1443 static int show_version(void)
1444 {
1445         printf("Asterisk " ASTERISK_VERSION "\n");
1446         return 0;
1447 }
1448
1449 static int show_cli_help(void) {
1450         printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 2000-2004, Digium.\n");
1451         printf("Usage: asterisk [OPTIONS]\n");
1452         printf("Valid Options:\n");
1453         printf("   -V              Display version number and exit\n");
1454         printf("   -C <configfile> Use an alternate configuration file\n");
1455         printf("   -G <group>      Run as a group other than the caller\n");
1456         printf("   -U <user>       Run as a user other than the caller\n");
1457         printf("   -c              Provide console CLI\n");
1458         printf("   -d              Enable extra debugging\n");
1459         printf("   -f              Do not fork\n");
1460         printf("   -g              Dump core in case of a crash\n");
1461         printf("   -h              This help screen\n");
1462         printf("   -i              Initializie crypto keys at startup\n");
1463         printf("   -n              Disable console colorization\n");
1464         printf("   -p              Run as pseudo-realtime thread\n");
1465         printf("   -q              Quiet mode (supress output)\n");
1466         printf("   -r              Connect to Asterisk on this machine\n");
1467         printf("   -R              Connect to Asterisk, and attempt to reconnect if disconnected\n");
1468         printf("   -v              Increase verbosity (multiple v's = more verbose)\n");
1469         printf("   -x <cmd>        Execute command <cmd> (only valid with -r)\n");
1470         printf("\n");
1471         return 0;
1472 }
1473
1474 static void ast_readconfig(void) {
1475         struct ast_config *cfg;
1476         struct ast_variable *v;
1477         char *config = ASTCONFPATH;
1478
1479         if (option_overrideconfig == 1) {
1480             cfg = ast_load((char *)ast_config_AST_CONFIG_FILE);
1481         } else {
1482             cfg = ast_load(config);
1483         }
1484
1485         /* init with buildtime config */
1486         strncpy((char *)ast_config_AST_CONFIG_DIR,AST_CONFIG_DIR,sizeof(ast_config_AST_CONFIG_DIR)-1);
1487         strncpy((char *)ast_config_AST_SPOOL_DIR,AST_SPOOL_DIR,sizeof(ast_config_AST_SPOOL_DIR)-1);
1488         strncpy((char *)ast_config_AST_MODULE_DIR,AST_MODULE_DIR,sizeof(ast_config_AST_VAR_DIR)-1);
1489         strncpy((char *)ast_config_AST_VAR_DIR,AST_VAR_DIR,sizeof(ast_config_AST_VAR_DIR)-1);
1490         strncpy((char *)ast_config_AST_LOG_DIR,AST_LOG_DIR,sizeof(ast_config_AST_LOG_DIR)-1);
1491         strncpy((char *)ast_config_AST_AGI_DIR,AST_AGI_DIR,sizeof(ast_config_AST_AGI_DIR)-1);
1492         strncpy((char *)ast_config_AST_DB,AST_DB,sizeof(ast_config_AST_DB)-1);
1493         strncpy((char *)ast_config_AST_KEY_DIR,AST_KEY_DIR,sizeof(ast_config_AST_KEY_DIR)-1);
1494         strncpy((char *)ast_config_AST_PID,AST_PID,sizeof(ast_config_AST_PID)-1);
1495         strncpy((char *)ast_config_AST_SOCKET,AST_SOCKET,sizeof(ast_config_AST_SOCKET)-1);
1496         strncpy((char *)ast_config_AST_RUN_DIR,AST_RUN_DIR,sizeof(ast_config_AST_RUN_DIR)-1);
1497         
1498         /* no asterisk.conf? no problem, use buildtime config! */
1499         if (!cfg) {
1500             return;
1501         }
1502         v = ast_variable_browse(cfg, "directories");
1503         while(v) {
1504                 if (!strcasecmp(v->name, "astetcdir")) {
1505                     strncpy((char *)ast_config_AST_CONFIG_DIR,v->value,sizeof(ast_config_AST_CONFIG_DIR)-1);
1506                 } else if (!strcasecmp(v->name, "astspooldir")) {
1507                     strncpy((char *)ast_config_AST_SPOOL_DIR,v->value,sizeof(ast_config_AST_SPOOL_DIR)-1);
1508                 } else if (!strcasecmp(v->name, "astvarlibdir")) {
1509                     strncpy((char *)ast_config_AST_VAR_DIR,v->value,sizeof(ast_config_AST_VAR_DIR)-1);
1510                     snprintf((char *)ast_config_AST_DB,sizeof(ast_config_AST_DB),"%s/%s",v->value,"astdb");    
1511                 } else if (!strcasecmp(v->name, "astlogdir")) {
1512                     strncpy((char *)ast_config_AST_LOG_DIR,v->value,sizeof(ast_config_AST_LOG_DIR)-1);
1513                 } else if (!strcasecmp(v->name, "astagidir")) {
1514                     strncpy((char *)ast_config_AST_AGI_DIR,v->value,sizeof(ast_config_AST_AGI_DIR)-1);
1515                 } else if (!strcasecmp(v->name, "astrundir")) {
1516                     snprintf((char *)ast_config_AST_PID,sizeof(ast_config_AST_PID),"%s/%s",v->value,"asterisk.pid");    
1517                     snprintf((char *)ast_config_AST_SOCKET,sizeof(ast_config_AST_SOCKET),"%s/%s",v->value,"asterisk.ctl");    
1518                     strncpy((char *)ast_config_AST_RUN_DIR,v->value,sizeof(ast_config_AST_RUN_DIR)-1);
1519                 } else if (!strcasecmp(v->name, "astmoddir")) {
1520                     strncpy((char *)ast_config_AST_MODULE_DIR,v->value,sizeof(ast_config_AST_MODULE_DIR)-1);
1521                 }
1522                 v = v->next;
1523         }
1524         ast_destroy(cfg);
1525 }
1526
1527 int main(int argc, char *argv[])
1528 {
1529         int c;
1530         char filename[80] = "";
1531         char hostname[256];
1532         char tmp[80];
1533         char * xarg = NULL;
1534         int x;
1535         FILE *f;
1536         sigset_t sigs;
1537         int num;
1538         char *buf;
1539         char *runuser=NULL, *rungroup=NULL;
1540
1541         /* Remember original args for restart */
1542         if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
1543                 fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1);
1544                 argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
1545         }
1546         for (x=0;x<argc;x++)
1547                 _argv[x] = argv[x];
1548         _argv[x] = NULL;
1549
1550         /* if the progname is rasterisk consider it a remote console */
1551         if ( argv[0] && (strstr(argv[0], "rasterisk")) != NULL)  {
1552                 option_remote++;
1553                 option_nofork++;
1554         }
1555         if (gethostname(hostname, sizeof(hostname)))
1556                 strncpy(hostname, "<Unknown>", sizeof(hostname)-1);
1557         ast_mainpid = getpid();
1558         ast_ulaw_init();
1559         ast_alaw_init();
1560         callerid_init();
1561         ast_utils_init();
1562         tdd_init();
1563         if (getenv("HOME")) 
1564                 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1565         /* Check if we're root */
1566         /*
1567         if (geteuid()) {
1568                 ast_log(LOG_ERROR, "Must be run as root\n");
1569                 exit(1);
1570         }
1571         */
1572         /* Check for options */
1573         while((c=getopt(argc, argv, "hfdvVqprRgcinx:U:G:C:")) != -1) {
1574                 switch(c) {
1575                 case 'd':
1576                         option_debug++;
1577                         option_nofork++;
1578                         break;
1579                 case 'c':
1580                         option_console++;
1581                         option_nofork++;
1582                         break;
1583                 case 'f':
1584                         option_nofork++;
1585                         break;
1586                 case 'n':
1587                         option_nocolor++;
1588                         break;
1589                 case 'r':
1590                         option_remote++;
1591                         option_nofork++;
1592                         break;
1593                 case 'R':
1594                         option_remote++;
1595                         option_nofork++;
1596                         option_reconnect++;
1597                         break;
1598                 case 'p':
1599                         option_highpriority++;
1600                         break;
1601                 case 'v':
1602                         option_verbose++;
1603                         option_nofork++;
1604                         break;
1605                 case 'q':
1606                         option_quiet++;
1607                         break;
1608                 case 'x':
1609                         option_exec++;
1610                         xarg = optarg;
1611                         break;
1612                 case 'C':
1613                         strncpy((char *)ast_config_AST_CONFIG_FILE,optarg,sizeof(ast_config_AST_CONFIG_FILE) - 1);
1614                         option_overrideconfig++;
1615                         break;
1616                 case 'i':
1617                         option_initcrypto++;
1618                         break;
1619                 case'g':
1620                         option_dumpcore++;
1621                         break;
1622                 case 'h':
1623                         show_cli_help();
1624                         exit(0);
1625                 case 'V':
1626                         show_version();
1627                         exit(0);
1628                 case 'U':
1629                         runuser = optarg;
1630                         break;
1631                 case 'G':
1632                         rungroup = optarg;
1633                         break;
1634                 case '?':
1635                         exit(1);
1636                 }
1637         }
1638
1639         if (option_dumpcore) {
1640                 struct rlimit l;
1641                 memset(&l, 0, sizeof(l));
1642                 l.rlim_cur = RLIM_INFINITY;
1643                 l.rlim_max = RLIM_INFINITY;
1644                 if (setrlimit(RLIMIT_CORE, &l)) {
1645                         ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
1646                 }
1647         }
1648
1649         if (rungroup) {
1650                 struct group *gr;
1651                 gr = getgrnam(rungroup);
1652                 if (!gr) {
1653                         ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
1654                         exit(1);
1655                 }
1656                 if (setgid(gr->gr_gid)) {
1657                         ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", gr->gr_gid, rungroup);
1658                         exit(1);
1659                 }
1660                 if (option_verbose)
1661                         ast_verbose("Running as group '%s'\n", rungroup);
1662         }
1663
1664         if (set_priority(option_highpriority)) {
1665                 exit(1);
1666         }
1667         if (runuser) {
1668                 struct passwd *pw;
1669                 pw = getpwnam(runuser);
1670                 if (!pw) {
1671                         ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
1672                         exit(1);
1673                 }
1674                 if (setuid(pw->pw_uid)) {
1675                         ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", pw->pw_uid, runuser);
1676                         exit(1);
1677                 }
1678                 if (option_verbose)
1679                         ast_verbose("Running as user '%s'\n", runuser);
1680         }
1681
1682         term_init();
1683         printf(term_end());
1684         fflush(stdout);
1685
1686         /* Test recursive mutex locking. */
1687         if (test_for_thread_safety())
1688                 ast_verbose("Warning! Asterisk is not thread safe.\n");
1689
1690         if (option_console && !option_verbose) 
1691                 ast_verbose("[ Reading Master Configuration ]");
1692         ast_readconfig();
1693
1694         if (option_console && !option_verbose) 
1695                 ast_verbose("[ Initializing Custom Configuration Options]");
1696         /* custom config setup */
1697         register_config_cli();
1698         read_ast_cust_config();
1699         
1700
1701         if (option_console) {
1702                 if (el_hist == NULL || el == NULL)
1703                         ast_el_initialize();
1704
1705                 if (!ast_strlen_zero(filename))
1706                         ast_el_read_history(filename);
1707         }
1708
1709         if (ast_tryconnect()) {
1710                 /* One is already running */
1711                 if (option_remote) {
1712                         if (option_exec) {
1713                                 ast_remotecontrol(xarg);
1714                                 quit_handler(0, 0, 0, 0);
1715                                 exit(0);
1716                         }
1717                         printf(term_quit());
1718                         ast_register_verbose(console_verboser);
1719                         WELCOME_MESSAGE;
1720                         ast_remotecontrol(NULL);
1721                         quit_handler(0, 0, 0, 0);
1722                         exit(0);
1723                 } else {
1724                         ast_log(LOG_ERROR, "Asterisk already running on %s.  Use 'asterisk -r' to connect.\n", (char *)ast_config_AST_SOCKET);
1725                         printf(term_quit());
1726                         exit(1);
1727                 }
1728         } else if (option_remote || option_exec) {
1729                 ast_log(LOG_ERROR, "Unable to connect to remote asterisk\n");
1730                 printf(term_quit());
1731                 exit(1);
1732         }
1733         /* Blindly write pid file since we couldn't connect */
1734         unlink((char *)ast_config_AST_PID);
1735         f = fopen((char *)ast_config_AST_PID, "w");
1736         if (f) {
1737                 fprintf(f, "%d\n", getpid());
1738                 fclose(f);
1739         } else
1740                 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", (char *)ast_config_AST_PID, strerror(errno));
1741
1742         if (!option_verbose && !option_debug && !option_nofork && !option_console) {
1743                 daemon(0,0);
1744                 /* Blindly re-write pid file since we are forking */
1745                 unlink((char *)ast_config_AST_PID);
1746                 f = fopen((char *)ast_config_AST_PID, "w");
1747                 if (f) {
1748                         fprintf(f, "%d\n", getpid());
1749                         fclose(f);
1750                 } else
1751                         ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", (char *)ast_config_AST_PID, strerror(errno));
1752         }
1753
1754         ast_makesocket();
1755         sigemptyset(&sigs);
1756         sigaddset(&sigs, SIGHUP);
1757         sigaddset(&sigs, SIGTERM);
1758         sigaddset(&sigs, SIGINT);
1759         sigaddset(&sigs, SIGPIPE);
1760         sigaddset(&sigs, SIGWINCH);
1761         pthread_sigmask(SIG_BLOCK, &sigs, NULL);
1762         if (option_console || option_verbose || option_remote)
1763                 ast_register_verbose(console_verboser);
1764         /* Print a welcome message if desired */
1765         if (option_verbose || option_console) {
1766                 WELCOME_MESSAGE;
1767         }
1768         if (option_console && !option_verbose) 
1769                 ast_verbose("[ Booting...");
1770
1771         signal(SIGURG, urg_handler);
1772         signal(SIGINT, __quit_handler);
1773         signal(SIGTERM, __quit_handler);
1774         signal(SIGHUP, hup_handler);
1775         signal(SIGCHLD, child_handler);
1776         signal(SIGPIPE, SIG_IGN);
1777
1778         if (init_logger()) {
1779                 printf(term_quit());
1780                 exit(1);
1781         }
1782         if (init_manager()) {
1783                 printf(term_quit());
1784                 exit(1);
1785         }
1786         ast_rtp_init();
1787         if (ast_image_init()) {
1788                 printf(term_quit());
1789                 exit(1);
1790         }
1791         if (ast_file_init()) {
1792                 printf(term_quit());
1793                 exit(1);
1794         }
1795         if (load_pbx()) {
1796                 printf(term_quit());
1797                 exit(1);
1798         }
1799         if (load_modules()) {
1800                 printf(term_quit());
1801                 exit(1);
1802         }
1803         if (init_framer()) {
1804                 printf(term_quit());
1805                 exit(1);
1806         }
1807         if (astdb_init()) {
1808                 printf(term_quit());
1809                 exit(1);
1810         }
1811         if (ast_enum_init()) {
1812                 printf(term_quit());
1813                 exit(1);
1814         }
1815         /* reload logger in case a custom config handler binded to logger.conf*/
1816         reload_logger(0);
1817
1818         /* We might have the option of showing a console, but for now just
1819            do nothing... */
1820         if (option_console && !option_verbose)
1821                 ast_verbose(" ]\n");
1822         if (option_verbose || option_console)
1823                 ast_verbose(term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
1824         if (option_nofork)
1825                 consolethread = pthread_self();
1826         fully_booted = 1;
1827         pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
1828 #ifdef __AST_DEBUG_MALLOC
1829         __ast_mm_init();
1830 #endif  
1831         time(&ast_startuptime);
1832         ast_cli_register(&astshutdownnow);
1833         ast_cli_register(&astshutdowngracefully);
1834         ast_cli_register(&astrestartnow);
1835         ast_cli_register(&astrestartgracefully);
1836         ast_cli_register(&astrestartwhenconvenient);
1837         ast_cli_register(&astshutdownwhenconvenient);
1838         ast_cli_register(&aborthalt);
1839         ast_cli_register(&astbang);
1840         if (option_console) {
1841                 /* Console stuff now... */
1842                 /* Register our quit function */
1843                 char title[256];
1844                 set_icon("Asterisk");
1845                 snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %d)", hostname, ast_mainpid);
1846                 set_title(title);
1847             ast_cli_register(&quit);
1848             ast_cli_register(&astexit);
1849
1850                 for (;;) {
1851                         buf = (char *)el_gets(el, &num);
1852                         if (buf) {
1853                                 if (buf[strlen(buf)-1] == '\n')
1854                                         buf[strlen(buf)-1] = '\0';
1855
1856                                 consolehandler((char *)buf);
1857                         } else {
1858                                 if (option_remote)
1859                                         ast_cli(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n");
1860                         }
1861                 }
1862
1863         } else {
1864                 /* Do nothing */
1865                 for(;;) 
1866                         poll(NULL,0, -1);
1867         }
1868         return 0;
1869 }