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