Version 0.3.0 from FTP
[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 <asterisk/logger.h>
17 #include <asterisk/options.h>
18 #include <asterisk/cli.h>
19 #include <asterisk/channel.h>
20 #include <asterisk/ulaw.h>
21 #include <asterisk/alaw.h>
22 #include <asterisk/callerid.h>
23 #include <asterisk/module.h>
24 #include <asterisk/image.h>
25 #include <asterisk/tdd.h>
26 #include <asterisk/term.h>
27 #include <asterisk/manager.h>
28 #include <fcntl.h>
29 #include <stdio.h>
30 #include <signal.h>
31 #include <sched.h>
32 #include <asterisk/io.h>
33 #include <pthread.h>
34 #include <sys/socket.h>
35 #include <sys/un.h>
36 #include <sys/select.h>
37 #include <string.h>
38 #include <errno.h>
39 #include <readline/readline.h>
40 #include <readline/history.h>
41 #include "asterisk.h"
42
43 #define AST_MAX_CONNECTS 128
44 #define NUM_MSGS 64
45
46 int option_verbose=0;
47 int option_debug=0;
48 int option_nofork=0;
49 int option_quiet=0;
50 int option_console=0;
51 int option_highpriority=0;
52 int option_remote=0;
53 int option_exec=0;
54 int option_initcrypto=0;
55 int option_nocolor;
56 int fully_booted = 0;
57
58 static int ast_socket = -1;             /* UNIX Socket for allowing remote control */
59 static int ast_consock = -1;            /* UNIX Socket for controlling another asterisk */
60 static int mainpid;
61 struct console {
62         int fd;                                 /* File descriptor */
63         int p[2];                               /* Pipe */
64         pthread_t t;                    /* Thread of handler */
65 };
66
67 struct console consoles[AST_MAX_CONNECTS];
68
69 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
70
71 static int fdprint(int fd, char *s)
72 {
73         return write(fd, s, strlen(s) + 1);
74 }
75
76 static void network_verboser(char *s, int pos, int replace, int complete)
77 {
78         int x;
79         for (x=0;x<AST_MAX_CONNECTS; x++) {
80                 if (consoles[x].fd > -1) 
81                         fdprint(consoles[x].p[1], s);
82         }
83 }
84
85 static pthread_t lthread;
86
87 static void *netconsole(void *vconsole)
88 {
89         struct console *con = vconsole;
90         char hostname[256];
91         char tmp[512];
92         int res;
93         int max;
94         fd_set rfds;
95         
96         if (gethostname(hostname, sizeof(hostname)))
97                 strncpy(hostname, "<Unknown>", sizeof(hostname)-1);
98         snprintf(tmp, sizeof(tmp), "%s/%d/%s\n", hostname, mainpid, ASTERISK_VERSION);
99         fdprint(con->fd, tmp);
100         for(;;) {
101                 FD_ZERO(&rfds); 
102                 FD_SET(con->fd, &rfds);
103                 FD_SET(con->p[0], &rfds);
104                 max = con->fd;
105                 if (con->p[0] > max)
106                         max = con->p[0];
107                 res = select(max + 1, &rfds, NULL, NULL, NULL);
108                 if (res < 0) {
109                         ast_log(LOG_WARNING, "select returned < 0: %s\n", strerror(errno));
110                         continue;
111                 }
112                 if (FD_ISSET(con->fd, &rfds)) {
113                         res = read(con->fd, tmp, sizeof(tmp));
114                         if (res < 1) {
115                                 break;
116                         }
117                         tmp[res] = 0;
118                         ast_cli_command(con->fd, tmp);
119                 }
120                 if (FD_ISSET(con->p[0], &rfds)) {
121                         res = read(con->p[0], tmp, sizeof(tmp));
122                         if (res < 1) {
123                                 ast_log(LOG_ERROR, "read returned %d\n", res);
124                                 break;
125                         }
126                         res = write(con->fd, tmp, res);
127                         if (res < 1)
128                                 break;
129                 }
130         }
131         if (option_verbose > 2) 
132                 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n");
133         close(con->fd);
134         close(con->p[0]);
135         close(con->p[1]);
136         con->fd = -1;
137         
138         return NULL;
139 }
140
141 static void *listener(void *unused)
142 {
143         struct sockaddr_un sun;
144         int s;
145         int len;
146         int x;
147         int flags;
148         pthread_attr_t attr;
149         pthread_attr_init(&attr);
150         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
151         for(;;) {
152                 if (ast_socket < 0)
153                         return NULL;
154                 len = sizeof(sun);
155                 s = accept(ast_socket, (struct sockaddr *)&sun, &len);
156                 if (s < 0) {
157                         ast_log(LOG_WARNING, "Accept retured %d: %s\n", s, strerror(errno));
158                 } else {
159                         for (x=0;x<AST_MAX_CONNECTS;x++) {
160                                 if (consoles[x].fd < 0) {
161                                         if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
162                                                 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
163                                                 consoles[x].fd = -1;
164                                                 fdprint(s, "Server failed to create pipe\n");
165                                                 close(s);
166                                                 break;
167                                         }
168                                         flags = fcntl(consoles[x].p[1], F_GETFL);
169                                         fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
170                                         consoles[x].fd = s;
171                                         if (pthread_create(&consoles[x].t, &attr, netconsole, &consoles[x])) {
172                                                 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection\n");
173                                                 consoles[x].fd = -1;
174                                                 fdprint(s, "Server failed to spawn thread\n");
175                                                 close(s);
176                                         }
177                                         break;
178                                 }
179                         }
180                         if (x >= AST_MAX_CONNECTS) {
181                                 fdprint(s, "No more connections allowed\n");
182                                 ast_log(LOG_WARNING, "No more connections allowed\n");
183                                 close(s);
184                         } else if (consoles[x].fd > -1) {
185                                 if (option_verbose > 2) 
186                                         ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection\n");
187                         }
188                 }
189         }
190         return NULL;
191 }
192
193 static int ast_makesocket(void)
194 {
195         struct sockaddr_un sun;
196         int res;
197         int x;
198         for (x=0;x<AST_MAX_CONNECTS;x++)        
199                 consoles[x].fd = -1;
200         unlink(AST_SOCKET);
201         ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
202         if (ast_socket < 0) {
203                 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
204                 return -1;
205         }               
206         memset(&sun, 0, sizeof(sun));
207         sun.sun_family = AF_LOCAL;
208         strncpy(sun.sun_path, AST_SOCKET, sizeof(sun.sun_path)-1);
209         res = bind(ast_socket, (struct sockaddr *)&sun, sizeof(sun));
210         if (res) {
211                 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", AST_SOCKET, strerror(errno));
212                 close(ast_socket);
213                 ast_socket = -1;
214                 return -1;
215         }
216         res = listen(ast_socket, 2);
217         if (res < 0) {
218                 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", AST_SOCKET, strerror(errno));
219                 close(ast_socket);
220                 ast_socket = -1;
221                 return -1;
222         }
223         ast_register_verbose(network_verboser);
224         pthread_create(&lthread, NULL, listener, NULL);
225         return 0;
226 }
227
228 static int ast_tryconnect(void)
229 {
230         struct sockaddr_un sun;
231         int res;
232         ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
233         if (ast_consock < 0) {
234                 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
235                 return 0;
236         }
237         memset(&sun, 0, sizeof(sun));
238         sun.sun_family = AF_LOCAL;
239         strncpy(sun.sun_path, AST_SOCKET, sizeof(sun.sun_path)-1);
240         res = connect(ast_consock, (struct sockaddr *)&sun, sizeof(sun));
241         if (res) {
242                 close(ast_consock);
243                 ast_consock = -1;
244                 return 0;
245         } else
246                 return 1;
247 }
248
249 static void urg_handler(int num)
250 {
251         /* Called by soft_hangup to interrupt the select, read, or other
252            system call.  We don't actually need to do anything though.  */
253         if (option_debug) 
254                 ast_log(LOG_DEBUG, "Urgent handler\n");
255         signal(num, urg_handler);
256         return;
257 }
258
259 static void hup_handler(int num)
260 {
261         if (option_verbose > 1) 
262                 ast_verbose(VERBOSE_PREFIX_2 "Received HUP signal -- Reloading configs\n");
263         ast_module_reload();
264 }
265
266
267 static void pipe_handler(int num)
268 {
269         /* Ignore sigpipe */
270 }
271 static void set_title(char *text)
272 {
273         /* Set an X-term or screen title */
274         if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
275                 fprintf(stdout, "\033]2;%s\007", text);
276 }
277
278 static void set_icon(char *text)
279 {
280         if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
281                 fprintf(stdout, "\033]1;%s\007", text);
282 }
283
284 static int set_priority(int pri)
285 {
286         struct sched_param sched;
287         memset(&sched, 0, sizeof(sched));
288         /* We set ourselves to a high priority, that we might pre-empt everything
289            else.  If your PBX has heavy activity on it, this is a good thing.  */
290         if (pri) {  
291                 sched.sched_priority = 10;
292                 if (sched_setscheduler(0, SCHED_RR, &sched)) {
293                         ast_log(LOG_WARNING, "Unable to set high priority\n");
294                         return -1;
295                 } else
296                         if (option_verbose)
297                                 ast_verbose("Set to realtime thread\n");
298         } else {
299                 sched.sched_priority = 0;
300                 if (sched_setscheduler(0, SCHED_OTHER, &sched)) {
301                         ast_log(LOG_WARNING, "Unable to set normal priority\n");
302                         return -1;
303                 }
304         }
305         return 0;
306 }
307
308 static char *_argv[256];
309
310 static int shuttingdown = 0;
311
312 static void quit_handler(int num, int nice, int safeshutdown, int restart)
313 {
314         char filename[80] = "";
315         time_t s,e;
316         int x;
317         if (safeshutdown) {
318                 shuttingdown = 1;
319                 if (!nice) {
320                         /* Begin shutdown routine, hanging up active channels */
321                         ast_begin_shutdown(1);
322                         if (option_verbose && option_console)
323                                 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
324                         time(&s);
325                         for(;;) {
326                                 time(&e);
327                                 /* Wait up to 15 seconds for all channels to go away */
328                                 if ((e - s) > 15)
329                                         break;
330                                 if (!ast_active_channels())
331                                         break;
332                                 if (!shuttingdown)
333                                         break;
334                                 /* Sleep 1/10 of a second */
335                                 usleep(100000);
336                         }
337                 } else {
338                         if (nice < 2)
339                                 ast_begin_shutdown(0);
340                         if (option_verbose && option_console)
341                                 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
342                         for(;;) {
343                                 if (!ast_active_channels())
344                                         break;
345                                 if (!shuttingdown)
346                                         break;
347                                 sleep(1);
348                         }
349                 }
350
351                 if (!shuttingdown) {
352                         if (option_verbose && option_console)
353                                 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
354                         return;
355                 }
356         }
357         if (option_console || option_remote) {
358                 if (getenv("HOME")) 
359                         snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
360                 if (strlen(filename))
361                         write_history(filename);
362                 rl_callback_handler_remove();
363         }
364         /* Called on exit */
365         if (option_verbose && option_console)
366                 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
367         else if (option_debug)
368                 ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
369         if (ast_socket > -1) {
370                 close(ast_socket);
371                 ast_socket = -1;
372         }
373         if (ast_consock > -1)
374                 close(ast_consock);
375         if (ast_socket > -1)
376                 unlink(AST_SOCKET);
377         unlink(AST_PID);
378         printf(term_quit());
379         if (restart) {
380                 if (option_verbose || option_console)
381                         ast_verbose("Preparing for Asterisk restart...\n");
382                 /* Mark all FD's for closing on exec */
383                 for (x=3;x<32768;x++) {
384                         fcntl(x, F_SETFD, FD_CLOEXEC);
385                 }
386                 if (option_verbose || option_console)
387                         ast_verbose("Restarting Asterisk NOW...\n");
388                 execvp(_argv[0], _argv);
389         } else
390                 exit(0);
391 }
392
393 static void __quit_handler(int num)
394 {
395         quit_handler(num, 0, 1, 0);
396 }
397
398 static pthread_t consolethread = -1;
399
400 static int fix_header(char *outbuf, int maxout, char **s, char *cmp)
401 {
402         if (!strncmp(*s, cmp, strlen(cmp))) {
403                 *s += strlen(cmp);
404                 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
405                 return 1;
406         }
407         return 0;
408 }
409
410 static void console_verboser(char *s, int pos, int replace, int complete)
411 {
412         char tmp[80];
413         /* Return to the beginning of the line */
414         if (!pos) {
415                 fprintf(stdout, "\r");
416                 if (fix_header(tmp, sizeof(tmp), &s, VERBOSE_PREFIX_4) ||
417                         fix_header(tmp, sizeof(tmp), &s, VERBOSE_PREFIX_3) ||
418                         fix_header(tmp, sizeof(tmp), &s, VERBOSE_PREFIX_2) ||
419                         fix_header(tmp, sizeof(tmp), &s, VERBOSE_PREFIX_1))
420                         fputs(tmp, stdout);
421         }
422         fputs(s + pos,stdout);
423         fflush(stdout);
424         if (complete)
425         /* Wake up a select()ing console */
426                 if (consolethread > -1)
427                         pthread_kill(consolethread, SIGURG);
428 }
429
430 static void consolehandler(char *s)
431 {
432         printf(term_end());
433         fflush(stdout);
434         /* Called when readline data is available */
435         if (s && strlen(s))
436                 add_history(s);
437         /* Give the console access to the shell */
438         if (s) {
439                 if (s[0] == '!') {
440                         if (s[1])
441                                 system(s+1);
442                         else
443                                 system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
444                 } else 
445                 ast_cli_command(STDOUT_FILENO, s);
446                 if (!strcasecmp(s, "help"))
447                         fprintf(stdout, "          !<command>   Executes a given shell command\n");
448         } else
449                 fprintf(stdout, "\nUse \"quit\" to exit\n");
450 }
451
452
453 static char cmd[1024];
454
455 static void remoteconsolehandler(char *s)
456 {
457         /* Called when readline data is available */
458         if (s && strlen(s))
459                 add_history(s);
460         /* Give the console access to the shell */
461         if (s) {
462                 if (s[0] == '!') {
463                         if (s[1])
464                                 system(s+1);
465                         else
466                                 system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
467                 } else 
468                 strncpy(cmd, s, sizeof(cmd)-1);
469                 if (!strcasecmp(s, "help"))
470                         fprintf(stdout, "          !<command>   Executes a given shell command\n");
471                 if (!strcasecmp(s, "quit"))
472                         quit_handler(0, 0, 0, 0);
473         } else
474                 fprintf(stdout, "\nUse \"quit\" to exit\n");
475 }
476
477 static char quit_help[] = 
478 "Usage: quit\n"
479 "       Exits Asterisk.\n";
480
481 static char abort_halt_help[] = 
482 "Usage: abort shutdown\n"
483 "       Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
484 "       call operations.\n";
485
486 static char shutdown_now_help[] = 
487 "Usage: shutdown now\n"
488 "       Shuts down a running Asterisk immediately, hanging up all active calls .\n";
489
490 static char shutdown_gracefully_help[] = 
491 "Usage: shutdown gracefully\n"
492 "       Causes Asterisk to not accept new calls, and exit when all\n"
493 "       active calls have terminated normally.\n";
494
495 static char restart_now_help[] = 
496 "Usage: restart now\n"
497 "       Causes Asterisk to hangup all calls and exec() itself performing a cold.\n"
498 "       restart.\n";
499
500 static char restart_gracefully_help[] = 
501 "Usage: restart gracefully\n"
502 "       Causes Asterisk to stop accepting new calls and exec() itself performing a cold.\n"
503 "       restart when all active calls have ended.\n";
504
505 static char restart_when_convenient_help[] = 
506 "Usage: restart when convenient\n"
507 "       Causes Asterisk to perform a cold restart when all active calls have ended.\n";
508
509 static int handle_quit(int fd, int argc, char *argv[])
510 {
511         if (argc != 1)
512                 return RESULT_SHOWUSAGE;
513         quit_handler(0, 0, 1, 0);
514         return RESULT_SUCCESS;
515 }
516
517 static int handle_shutdown_now(int fd, int argc, char *argv[])
518 {
519         if (argc != 2)
520                 return RESULT_SHOWUSAGE;
521         quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
522         return RESULT_SUCCESS;
523 }
524
525 static int handle_shutdown_gracefully(int fd, int argc, char *argv[])
526 {
527         if (argc != 2)
528                 return RESULT_SHOWUSAGE;
529         quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
530         return RESULT_SUCCESS;
531 }
532
533 static int handle_restart_now(int fd, int argc, char *argv[])
534 {
535         if (argc != 2)
536                 return RESULT_SHOWUSAGE;
537         quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
538         return RESULT_SUCCESS;
539 }
540
541 static int handle_restart_gracefully(int fd, int argc, char *argv[])
542 {
543         if (argc != 2)
544                 return RESULT_SHOWUSAGE;
545         quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
546         return RESULT_SUCCESS;
547 }
548
549 static int handle_restart_when_convenient(int fd, int argc, char *argv[])
550 {
551         if (argc != 3)
552                 return RESULT_SHOWUSAGE;
553         quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
554         return RESULT_SUCCESS;
555 }
556
557 static int handle_abort_halt(int fd, int argc, char *argv[])
558 {
559         if (argc != 2)
560                 return RESULT_SHOWUSAGE;
561         ast_cancel_shutdown();
562         shuttingdown = 0;
563         return RESULT_SUCCESS;
564 }
565
566 #define ASTERISK_PROMPT "*CLI> "
567
568 #define ASTERISK_PROMPT2 "%s*CLI> "
569
570 static struct ast_cli_entry aborthalt = { { "abort", "halt", NULL }, handle_abort_halt, "Cancel a running halt", abort_halt_help };
571
572 static struct ast_cli_entry quit =      { { "quit", NULL }, handle_quit, "Exit Asterisk", quit_help };
573
574 static struct ast_cli_entry astshutdownnow =    { { "shutdown", "now", NULL }, handle_shutdown_now, "Shut down Asterisk imediately", shutdown_now_help };
575 static struct ast_cli_entry astshutdowngracefully =     { { "shutdown", "gracefully", NULL }, handle_shutdown_gracefully, "Gracefully shut down Asterisk", shutdown_gracefully_help };
576 static struct ast_cli_entry astrestartnow =     { { "restart", "now", NULL }, handle_restart_now, "Restart Asterisk immediately", restart_now_help };
577 static struct ast_cli_entry astrestartgracefully =      { { "restart", "gracefully", NULL }, handle_restart_gracefully, "Restart Asterisk gracefully", restart_gracefully_help };
578 static struct ast_cli_entry astrestartwhenconvenient=   { { "restart", "when", "convenient", NULL }, handle_restart_when_convenient, "Restart Asterisk at empty call volume", restart_when_convenient_help };
579
580 static char *cli_generator(char *text, int state)
581 {
582         return ast_cli_generator(rl_line_buffer, text, state);
583 }
584
585 static char *console_cli_generator(char *text, int state)
586 {
587         char buf[1024];
588         int res;
589 #if 0
590         fprintf(stderr, "Searching for '%s', %s %d\n", rl_line_buffer, text, state);
591 #endif  
592         snprintf(buf, sizeof(buf),"_COMMAND COMPLETE \"%s\" \"%s\" %d", rl_line_buffer, text, state); 
593         fdprint(ast_consock, buf);
594         res = read(ast_consock, buf, sizeof(buf));
595         buf[res] = '\0';
596 #if 0
597         printf("res is %d, buf is '%s'\n", res, buf);
598 #endif  
599         if (strncmp(buf, "NULL", 4))
600                 return strdup(buf);
601         else
602                 return NULL;
603 }
604
605 static void ast_remotecontrol(char * data)
606 {
607         char buf[80];
608         int res;
609         int max;
610         int lastpos = 0;
611         fd_set rfds;
612         char filename[80] = "";
613         char *hostname;
614         char *cpid;
615         char *version;
616         int pid;
617         int lastclear=0;
618         int oldstatus=0;
619         char tmp[80];
620         read(ast_consock, buf, sizeof(buf));
621         if (data) {
622                         write(ast_consock, data, strlen(data) + 1);
623                         return;
624         }
625         hostname = strtok(buf, "/");
626         cpid = strtok(NULL, "/");
627         version = strtok(NULL, "/");
628         if (!version)
629                 version = "<Version Unknown>";
630         strtok(hostname, ".");
631         if (cpid)
632                 pid = atoi(cpid);
633         else
634                 pid = -1;
635         snprintf(tmp, sizeof(tmp), "set verbose atleast %d", option_verbose);
636         fdprint(ast_consock, tmp);
637         ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
638         snprintf(tmp, sizeof(tmp), ASTERISK_PROMPT2, hostname);
639         if (getenv("HOME")) 
640                 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
641         if (strlen(filename))
642                 read_history(filename);
643         ast_cli_register(&quit);
644 #if 0
645         ast_cli_register(&astshutdown);
646 #endif  
647         rl_callback_handler_install(tmp, remoteconsolehandler);
648         rl_completion_entry_function = (void *)(Function *)console_cli_generator;
649         for(;;) {
650                 FD_ZERO(&rfds);
651                 FD_SET(ast_consock, &rfds);
652                 FD_SET(STDIN_FILENO, &rfds);
653                 max = ast_consock;
654                 if (STDIN_FILENO > max)
655                         max = STDIN_FILENO;
656                 res = select(max + 1, &rfds, NULL, NULL, NULL);
657                 if (res < 0) {
658                         if (errno == EINTR)
659                                 continue;
660                         ast_log(LOG_ERROR, "select failed: %s\n", strerror(errno));
661                         break;
662                 }
663                 if (FD_ISSET(STDIN_FILENO, &rfds)) {
664                         rl_callback_read_char();
665                         if (strlen(cmd)) {
666                                 res = write(ast_consock, cmd, strlen(cmd) + 1);
667                                 if (res < 1) {
668                                         ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
669                                         break;
670                                 }
671                                 strcpy(cmd, "");
672                         }
673                 }
674                 if (FD_ISSET(ast_consock, &rfds)) {
675                         res = read(ast_consock, buf, sizeof(buf));
676                         if (res < 1)
677                                 break;
678                         buf[res] = 0;
679                         /* If someone asks for a pass code, hide the password */
680                         if (!memcmp(buf, ">>>>", 4)) {
681                                 printf("Ooh, i should hide password!\n");
682                                 if (!lastclear) {
683                                         oldstatus = ast_hide_password(STDIN_FILENO);
684                                         printf("Oldstatus = %d\n", oldstatus);
685                                 }
686                                 lastclear = 1;
687                         } else if (lastclear) {
688                                 ast_restore_tty(STDIN_FILENO, oldstatus);
689                                 lastclear = 0;
690                         }
691                         if (!lastpos)
692                                 write(STDOUT_FILENO, "\r", 2);
693                         write(STDOUT_FILENO, buf, res);
694                         if ((buf[res-1] == '\n') || (buf[res-2] == '\n')) {
695                                 rl_forced_update_display();
696                                 lastpos = 0;
697                         } else {
698                                 lastpos = 1;
699                         }
700                 }
701         }
702         printf("\nDisconnected from Asterisk server\n");
703 }
704
705 int show_cli_help(void) {
706         printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 2000-2002, Digium.\n");
707         printf("Usage: asterisk [OPTIONS]\n");
708         printf("Valid Options:\n");
709         printf("   -h           This help screen\n");
710         printf("   -r           Connect to Asterisk on this machine\n");
711         printf("   -f           Do not fork\n");
712         printf("   -n           Disable console colorization\n");
713         printf("   -p           Run as pseudo-realtime thread\n");
714         printf("   -v           Increase verbosity (multiple v's = more verbose)\n");
715         printf("   -q           Quiet mode (supress output)\n");
716         printf("   -x <cmd>     Execute command <cmd> (only valid with -r)\n");
717         printf("   -i           Initializie crypto keys at startup\n");
718         printf("   -c           Provide console CLI\n");
719         printf("   -d           Enable extra debugging\n");
720         printf("\n");
721         return 0;
722 }
723
724 int main(int argc, char *argv[])
725 {
726         char c;
727         fd_set rfds;
728         int res;
729         char filename[80] = "";
730         char hostname[256];
731         char tmp[80];
732         char * xarg = NULL;
733         int x;
734         FILE *f;
735         sigset_t sigs;
736
737         /* Remember original args for restart */
738         if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
739                 fprintf(stderr, "Truncating argument size to %d\n", sizeof(_argv) / sizeof(_argv[0]) - 1);
740                 argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
741         }
742         for (x=0;x<argc;x++)
743                 _argv[x] = argv[x];
744         _argv[x] = NULL;
745
746         if (gethostname(hostname, sizeof(hostname)))
747                 strncpy(hostname, "<Unknown>", sizeof(hostname)-1);
748         mainpid = getpid();
749         ast_ulaw_init();
750         ast_alaw_init();
751         callerid_init();
752         tdd_init();
753         if (getenv("HOME")) 
754                 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
755         /* Check if we're root */
756         if (geteuid()) {
757                 ast_log(LOG_ERROR, "Must be run as root\n");
758                 exit(1);
759         }
760         /* Check for options */
761         while((c=getopt(argc, argv, "hfdvqprcinx:")) != EOF) {
762                 switch(c) {
763                 case 'd':
764                         option_debug++;
765                         option_nofork++;
766                         break;
767                 case 'c':
768                         option_console++;
769                         option_nofork++;
770                         break;
771                 case 'f':
772                         option_nofork++;
773                         break;
774                 case 'n':
775                         option_nocolor++;
776                         break;
777                 case 'r':
778                         option_remote++;
779                         option_nofork++;
780                         break;
781                 case 'p':
782                         option_highpriority++;
783                         break;
784                 case 'v':
785                         option_verbose++;
786                         option_nofork++;
787                         break;
788                 case 'q':
789                         option_quiet++;
790                         break;
791                 case 'x':
792                         option_exec++;
793                         xarg = optarg;
794                         break;
795                 case 'i':
796                         option_initcrypto++;
797                         break;
798                 case 'h':
799                         show_cli_help();
800                         exit(0);
801                 case '?':
802                         exit(1);
803                 }
804         }
805
806         term_init();
807         printf(term_end());
808         fflush(stdout);
809         
810         if (ast_tryconnect()) {
811                 /* One is already running */
812                 if (option_remote) {
813                         if (option_exec) {
814                                 ast_remotecontrol(xarg);
815                                 quit_handler(0, 0, 0, 0);
816                                 exit(0);
817                         }
818                         printf(term_quit());
819                         ast_register_verbose(console_verboser);
820                         ast_verbose( "Asterisk " ASTERISK_VERSION ", Copyright (C) 1999-2001 Linux Support Services, Inc.\n");
821                         ast_verbose( "Written by Mark Spencer <markster@linux-support.net>\n");
822                         ast_verbose( "=========================================================================\n");
823                         ast_remotecontrol(NULL);
824                         quit_handler(0, 0, 0, 0);
825                         exit(0);
826                 } else {
827                         ast_log(LOG_ERROR, "Asterisk already running on %s.  Use 'asterisk -r' to connect.\n", AST_SOCKET);
828                         printf(term_quit());
829                         exit(1);
830                 }
831         } else if (option_remote || option_exec) {
832                 ast_log(LOG_ERROR, "Unable to connect to remote asterisk\n");
833                 printf(term_quit());
834                 exit(1);
835         }
836         /* Blindly write pid file since we couldn't connect */
837         unlink(AST_PID);
838         f = fopen(AST_PID, "w");
839         if (f) {
840                 fprintf(f, "%d\n", getpid());
841                 fclose(f);
842         } else
843                 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", AST_PID, strerror(errno));
844
845         if (!option_verbose && !option_debug && !option_nofork && !option_console) {
846 #if 1
847                 daemon(0,0);
848 #else   
849                 pid = fork();
850                 if (pid < 0) {
851                         ast_log(LOG_ERROR, "Unable to fork(): %s\n", strerror(errno));
852                         printf(term_quit());
853                         exit(1);
854                 }
855                 if (pid) 
856                         exit(0);
857 #endif                  
858         }
859
860         ast_makesocket();
861         sigemptyset(&sigs);
862         sigaddset(&sigs, SIGHUP);
863         sigaddset(&sigs, SIGTERM);
864         sigaddset(&sigs, SIGINT);
865         sigaddset(&sigs, SIGPIPE);
866         sigaddset(&sigs, SIGWINCH);
867         pthread_sigmask(SIG_BLOCK, &sigs, NULL);
868         if (option_console || option_verbose || option_remote)
869                 ast_register_verbose(console_verboser);
870         /* Print a welcome message if desired */
871         if (option_verbose || option_console) {
872                 ast_verbose( "Asterisk " ASTERISK_VERSION ", Copyright (C) 1999-2001 Linux Support Services, Inc.\n");
873                 ast_verbose( "Written by Mark Spencer <markster@linux-support.net>\n");
874                 ast_verbose( "=========================================================================\n");
875         }
876         if (option_console && !option_verbose) 
877                 ast_verbose("[ Booting...");
878         signal(SIGURG, urg_handler);
879         signal(SIGINT, __quit_handler);
880         signal(SIGTERM, __quit_handler);
881         signal(SIGHUP, hup_handler);
882         signal(SIGPIPE, pipe_handler);
883         if (set_priority(option_highpriority)) {
884                 printf(term_quit());
885                 exit(1);
886         }
887         if (init_logger()) {
888                 printf(term_quit());
889                 exit(1);
890         }
891         if (init_manager()) {
892                 printf(term_quit());
893                 exit(1);
894         }
895         if (ast_image_init()) {
896                 printf(term_quit());
897                 exit(1);
898         }
899         if (load_pbx()) {
900                 printf(term_quit());
901                 exit(1);
902         }
903         if (load_modules()) {
904                 printf(term_quit());
905                 exit(1);
906         }
907         if (init_framer()) {
908                 printf(term_quit());
909                 exit(1);
910         }
911         /* We might have the option of showing a console, but for now just
912            do nothing... */
913         if (option_console && !option_verbose)
914                 ast_verbose(" ]\n");
915         if (option_verbose || option_console)
916                 ast_verbose(term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
917         fully_booted = 1;
918         pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
919         ast_cli_register(&astshutdownnow);
920         ast_cli_register(&astshutdowngracefully);
921         ast_cli_register(&astrestartnow);
922         ast_cli_register(&astrestartgracefully);
923         ast_cli_register(&astrestartwhenconvenient);
924         ast_cli_register(&aborthalt);
925         if (option_console) {
926                 /* Console stuff now... */
927                 /* Register our quit function */
928                 char title[256];
929                 set_icon("Asterisk");
930                 snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %d)", hostname, mainpid);
931                 set_title(title);
932             ast_cli_register(&quit);
933                 consolethread = pthread_self();
934                 if (strlen(filename))
935                         read_history(filename);
936                 term_prompt(tmp, ASTERISK_PROMPT, sizeof(tmp));
937                 rl_callback_handler_install(tmp, consolehandler);
938                 rl_completion_entry_function = (void *)(Function *)cli_generator;
939                 for(;;) {
940                         FD_ZERO(&rfds);
941                         FD_SET(STDIN_FILENO, &rfds);
942                         res = select(STDIN_FILENO + 1, &rfds, NULL, NULL, NULL);
943                         if (res > 0) {
944                                 printf(term_prep());
945                                 rl_callback_read_char();
946                                 printf(term_end());
947                                 fflush(stdout);
948                         } else if (res < 1) {
949                                 rl_forced_update_display();
950                         }
951         
952                 }       
953         } else {
954                 /* Do nothing */
955                 select(0,NULL,NULL,NULL,NULL);
956         }
957         return 0;
958 }