Merge "BuildSystem: For consistency, avoid double-checking via if clauses."
[asterisk/asterisk.git] / utils / muted.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * Updated for Mac OSX CoreAudio
9  * by Josh Roberson <josh@asteriasgi.com>
10  *
11  * See http://www.asterisk.org for more information about
12  * the Asterisk project. Please do not directly contact
13  * any of the maintainers of this project for assistance;
14  * the project provides a web site, mailing lists and IRC
15  * channels for your use.
16  *
17  * This program is free software, distributed under the terms of
18  * the GNU General Public License Version 2. See the LICENSE file
19  * at the top of the source tree.
20  */
21
22 /*! \file
23  *
24  * \brief Mute Daemon
25  *
26  * \author Mark Spencer <markster@digium.com>
27  *
28  * Updated for Mac OSX CoreAudio
29  * \arg Josh Roberson <josh@asteriasgi.com>
30  *
31  * \note Specially written for Malcolm Davenport, but I think I'll use it too
32  * Connects to the Asterisk Manager Interface, AMI, and listens for events
33  * on certain devices. If a phone call is connected to one of the devices (phones)
34  * the local sound is muted to a lower volume during the call.
35  *
36  */
37
38 /*! \li \ref muted.c uses the configuration file \ref muted.conf
39  * \addtogroup configuration_file Configuration Files
40  */
41
42 /*!
43  * \page muted.conf muted.conf
44  * \verbinclude muted.conf.sample
45  */
46
47 /*** MODULEINFO
48         <support_level>extended</support_level>
49  ***/
50
51 #include "asterisk/autoconfig.h"
52
53 #ifdef __Darwin__
54 #include <CoreAudio/AudioHardware.h>
55 #include <sys/types.h>
56 #include <pwd.h>
57 #include <sys/stat.h>
58 #elif defined(__linux__) || defined(__FreeBSD__) || defined(__GLIBC__)
59 #include <sys/soundcard.h>
60 #endif
61 #include <stdio.h>
62 #include <errno.h>
63 #include <stdlib.h>
64 #include <unistd.h>
65 #include <fcntl.h>
66 #include <string.h>
67 #include <netdb.h>
68 #include <sys/socket.h>
69 #include <sys/ioctl.h>
70 #include <netinet/in.h>
71 #include <arpa/inet.h>
72
73 #define ast_strlen_zero(a)      (!(*(a)))
74
75 static char *config = "/etc/asterisk/muted.conf";
76
77 static char host[256] = "";
78 static char user[256] = "";
79 static char pass[256] = "";
80 static int smoothfade = 0;
81 static int mutelevel = 20;
82 static int muted = 0;
83 static int needfork = 1;
84 static int debug = 0;
85 static int stepsize = 3;
86 #ifndef __Darwin__
87 static int mixchan = SOUND_MIXER_VOLUME;
88 #endif
89
90 struct subchannel {
91         char *name;
92         struct subchannel *next;
93 };
94
95 static struct channel {
96         char *tech;
97         char *location;
98         struct channel *next;
99         struct subchannel *subs;
100 } *channels;
101
102 static void add_channel(char *tech, char *location)
103 {
104         struct channel *chan;
105         chan = malloc(sizeof(struct channel));
106         if (chan) {
107                 memset(chan, 0, sizeof(struct channel));
108                 if (!(chan->tech = strdup(tech))) {
109                         free(chan);
110                         return;
111                 }
112                 if (!(chan->location = strdup(location))) {
113                         free(chan->tech);
114                         free(chan);
115                         return;
116                 }
117                 chan->next = channels;
118                 channels = chan;
119         }
120
121 }
122
123 static int load_config(void)
124 {
125         FILE *f;
126         char buf[1024];
127         char *val;
128         char *val2;
129         int lineno=0;
130         int x;
131         f = fopen(config, "r");
132         if (!f) {
133                 fprintf(stderr, "Unable to open config file '%s': %s\n", config, strerror(errno));
134                 return -1;
135         }
136         while(!feof(f)) {
137                 if (!fgets(buf, sizeof(buf), f)) {
138                         continue;
139                 }
140                 if (!feof(f)) {
141                         lineno++;
142                         val = strchr(buf, '#');
143                         if (val) *val = '\0';
144                         while(strlen(buf) && (buf[strlen(buf) - 1] < 33))
145                                 buf[strlen(buf) - 1] = '\0';
146                         if (!strlen(buf))
147                                 continue;
148                         val = buf;
149                         while(*val) {
150                                 if (*val < 33)
151                                         break;
152                                 val++;
153                         }
154                         if (*val) {
155                                 *val = '\0';
156                                 val++;
157                                 while(*val && (*val < 33)) val++;
158                         }
159                         if (!strcasecmp(buf, "host")) {
160                                 if (val && strlen(val))
161                                         strncpy(host, val, sizeof(host) - 1);
162                                 else
163                                         fprintf(stderr, "host needs an argument (the host) at line %d\n", lineno);
164                         } else if (!strcasecmp(buf, "user")) {
165                                 if (val && strlen(val))
166                                         strncpy(user, val, sizeof(user) - 1);
167                                 else
168                                         fprintf(stderr, "user needs an argument (the user) at line %d\n", lineno);
169                         } else if (!strcasecmp(buf, "pass")) {
170                                 if (val && strlen(val))
171                                         strncpy(pass, val, sizeof(pass) - 1);
172                                 else
173                                         fprintf(stderr, "pass needs an argument (the password) at line %d\n", lineno);
174                         } else if (!strcasecmp(buf, "smoothfade")) {
175                                 smoothfade = 1;
176                         } else if (!strcasecmp(buf, "mutelevel")) {
177                                 if (val && (sscanf(val, "%3d", &x) == 1) && (x > -1) && (x < 101)) {
178                                         mutelevel = x;
179                                 } else
180                                         fprintf(stderr, "mutelevel must be a number from 0 (most muted) to 100 (no mute) at line %d\n", lineno);
181                         } else if (!strcasecmp(buf, "channel")) {
182                                 if (val && strlen(val)) {
183                                         val2 = strchr(val, '/');
184                                         if (val2) {
185                                                 *val2 = '\0';
186                                                 val2++;
187                                                 add_channel(val, val2);
188                                         } else
189                                                 fprintf(stderr, "channel needs to be of the format Tech/Location at line %d\n", lineno);
190                                 } else
191                                         fprintf(stderr, "channel needs an argument (the channel) at line %d\n", lineno);
192                         } else {
193                                 fprintf(stderr, "ignoring unknown keyword '%s'\n", buf);
194                         }
195                 }
196         }
197         fclose(f);
198         if (!strlen(host))
199                 fprintf(stderr, "no 'host' specification in config file\n");
200         else if (!strlen(user))
201                 fprintf(stderr, "no 'user' specification in config file\n");
202         else if (!channels)
203                 fprintf(stderr, "no 'channel' specifications in config file\n");
204         else
205                 return 0;
206         return -1;
207 }
208
209 static FILE *astf;
210 #ifndef __Darwin__
211 static int mixfd;
212
213 static int open_mixer(void)
214 {
215         mixfd = open("/dev/mixer", O_RDWR);
216         if (mixfd < 0) {
217                 fprintf(stderr, "Unable to open /dev/mixer: %s\n", strerror(errno));
218                 return -1;
219         }
220         return 0;
221 }
222 #endif /* !__Darwin */
223
224 /*! Connect to the asterisk manager interface */
225 static int connect_asterisk(void)
226 {
227         int sock;
228         struct hostent *hp;
229         char *ports;
230         int port = 5038;
231         struct sockaddr_in sin;
232
233         ports = strchr(host, ':');
234         if (ports) {
235                 *ports = '\0';
236                 ports++;
237                 if ((sscanf(ports, "%5d", &port) != 1) || (port < 1) || (port > 65535)) {
238                         fprintf(stderr, "'%s' is not a valid port number in the hostname\n", ports);
239                         return -1;
240                 }
241         }
242         hp = gethostbyname(host);
243         if (!hp) {
244                 fprintf(stderr, "Can't find host '%s'\n", host);
245                 return -1;
246         }
247         sock = socket(AF_INET, SOCK_STREAM, 0);
248         if (sock < 0) {
249                 fprintf(stderr, "Failed to create socket: %s\n", strerror(errno));
250                 return -1;
251         }
252         sin.sin_family = AF_INET;
253         sin.sin_port = htons(port);
254         memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
255         if (connect(sock, (struct sockaddr *)&sin, sizeof(sin))) {
256                 fprintf(stderr, "Failed to connect to '%s' port '%d': %s\n", host, port, strerror(errno));
257                 close(sock);
258                 return -1;
259         }
260         astf = fdopen(sock, "r+");
261         if (!astf) {
262                 fprintf(stderr, "fdopen failed: %s\n", strerror(errno));
263                 close(sock);
264                 return -1;
265         }
266         return 0;
267 }
268
269 static char *get_line(void)
270 {
271         static char buf[1024];
272         if (fgets(buf, sizeof(buf), astf)) {
273                 while(strlen(buf) && (buf[strlen(buf) - 1] < 33))
274                         buf[strlen(buf) - 1] = '\0';
275                 return buf;
276         } else
277                 return NULL;
278 }
279
280 /*! Login to the asterisk manager interface */
281 static int login_asterisk(void)
282 {
283         char *welcome;
284         char *resp;
285         if (!(welcome = get_line())) {
286                 fprintf(stderr, "disconnected (1)\n");
287                 return -1;
288         }
289         fprintf(astf,
290                 "Action: Login\r\n"
291                 "Username: %s\r\n"
292                 "Secret: %s\r\n\r\n", user, pass);
293         if (!(welcome = get_line())) {
294                 fprintf(stderr, "disconnected (2)\n");
295                 return -1;
296         }
297         if (strcasecmp(welcome, "Response: Success")) {
298                 fprintf(stderr, "login failed ('%s')\n", welcome);
299                 return -1;
300         }
301         /* Eat the rest of the event */
302         while((resp = get_line()) && strlen(resp));
303         if (!resp) {
304                 fprintf(stderr, "disconnected (3)\n");
305                 return -1;
306         }
307         fprintf(astf,
308                 "Action: Status\r\n\r\n");
309         if (!(welcome = get_line())) {
310                 fprintf(stderr, "disconnected (4)\n");
311                 return -1;
312         }
313         if (strcasecmp(welcome, "Response: Success")) {
314                 fprintf(stderr, "status failed ('%s')\n", welcome);
315                 return -1;
316         }
317         /* Eat the rest of the event */
318         while((resp = get_line()) && strlen(resp));
319         if (!resp) {
320                 fprintf(stderr, "disconnected (5)\n");
321                 return -1;
322         }
323         return 0;
324 }
325
326 static struct channel *find_channel(char *channel)
327 {
328         char tmp[256] = "";
329         char *s, *t;
330         struct channel *chan;
331         strncpy(tmp, channel, sizeof(tmp) - 1);
332         s = strchr(tmp, '/');
333         if (s) {
334                 *s = '\0';
335                 s++;
336                 t = strrchr(s, '-');
337                 if (t) {
338                         *t = '\0';
339                 }
340                 if (debug)
341                         printf("Searching for '%s' tech, '%s' location\n", tmp, s);
342                 chan = channels;
343                 while(chan) {
344                         if (!strcasecmp(chan->tech, tmp) && !strcasecmp(chan->location, s)) {
345                                 if (debug)
346                                         printf("Found '%s'/'%s'\n", chan->tech, chan->location);
347                                 break;
348                         }
349                         chan = chan->next;
350                 }
351         } else
352                 chan = NULL;
353         return chan;
354 }
355
356 #ifndef __Darwin__
357 static int getvol(void)
358 {
359         int vol;
360
361         if (ioctl(mixfd, MIXER_READ(mixchan), &vol)) {
362 #else
363 static float getvol(void)
364 {
365         float volumeL, volumeR, vol;
366         OSStatus err;
367         AudioDeviceID device;
368         UInt32 size;
369         UInt32 channels[2];
370         AudioObjectPropertyAddress OutputAddr = { kAudioHardwarePropertyDefaultOutputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
371         AudioObjectPropertyAddress ChannelAddr = { kAudioDevicePropertyPreferredChannelsForStereo, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementWildcard };
372         AudioObjectPropertyAddress VolumeAddr = { kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeOutput, };
373
374         size = sizeof(device);
375         err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &OutputAddr, 0, NULL, &size, &device);
376         size = sizeof(channels);
377         if (!err) {
378                 err = AudioObjectGetPropertyData(device, &ChannelAddr, 0, NULL, &size, &channels);
379         }
380         size = sizeof(vol);
381         if (!err) {
382                 VolumeAddr.mElement = channels[0];
383                 err = AudioObjectGetPropertyData(device, &VolumeAddr, 0, NULL, &size, &volumeL);
384         }
385         if (!err) {
386                 VolumeAddr.mElement = channels[1];
387                 err = AudioObjectGetPropertyData(device, &VolumeAddr, 0, NULL, &size, &volumeR);
388         }
389         if (!err)
390                 vol = (volumeL < volumeR) ? volumeR : volumeL;
391         else {
392 #endif
393                 fprintf(stderr, "Unable to read mixer volume: %s\n", strerror(errno));
394                 return -1;
395         }
396         return vol;
397 }
398
399 #ifndef __Darwin__
400 static int setvol(int vol)
401 #else
402 static int setvol(float vol)
403 #endif
404 {
405 #ifndef __Darwin__
406         if (ioctl(mixfd, MIXER_WRITE(mixchan), &vol)) {
407 #else
408         float volumeL = vol;
409         float volumeR = vol;
410         OSStatus err;
411         AudioDeviceID device;
412         UInt32 size;
413         UInt32 channels[2];
414         AudioObjectPropertyAddress OutputAddr = { kAudioHardwarePropertyDefaultOutputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
415         AudioObjectPropertyAddress ChannelAddr = { kAudioDevicePropertyPreferredChannelsForStereo, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementWildcard };
416         AudioObjectPropertyAddress VolumeAddr = { kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeOutput, };
417
418         size = sizeof(device);
419         err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &OutputAddr, 0, NULL, &size, &device);
420         size = sizeof(channels);
421         err = AudioObjectGetPropertyData(device, &ChannelAddr, 0, NULL, &size, &channels);
422         size = sizeof(vol);
423         if (!err) {
424                 VolumeAddr.mElement = channels[0];
425                 err = AudioObjectSetPropertyData(device, &VolumeAddr, 0, NULL, size, &volumeL);
426         }
427         if (!err) {
428                 VolumeAddr.mElement = channels[1];
429                 err = AudioObjectSetPropertyData(device, &VolumeAddr, 0, NULL, size, &volumeR);
430         }
431         if (err) {
432 #endif
433
434                 fprintf(stderr, "Unable to write mixer volume: %s\n", strerror(errno));
435                 return -1;
436
437         }
438         return 0;
439 }
440
441 #ifndef __Darwin__
442 static int oldvol = 0;
443 static int mutevol = 0;
444 #else
445 static float oldvol = 0;
446 static float mutevol = 0;
447 #endif
448
449 #ifndef __Darwin__
450 static int mutedlevel(int orig, int level)
451 {
452         int l = orig >> 8;
453         int r = orig & 0xff;
454         l = (float)(level) * (float)(l) / 100.0;
455         r = (float)(level) * (float)(r) / 100.0;
456
457         return (l << 8) | r;
458 #else
459 static float mutedlevel(float orig, float level)
460 {
461         float master = orig;
462         master = level * master / 100.0;
463         return master;
464 #endif
465
466 }
467
468 static void mute(void)
469 {
470 #ifndef __Darwin__
471         int vol;
472         int start;
473         int x;
474 #else
475         float vol;
476         float start = 1.0;
477         float x;
478 #endif
479         vol = getvol();
480         oldvol = vol;
481         if (smoothfade)
482 #ifdef __Darwin__
483                 start = mutelevel;
484 #else
485                 start = 100;
486         else
487                 start = mutelevel;
488 #endif
489         for (x=start;x>=mutelevel;x-=stepsize) {
490                 mutevol = mutedlevel(vol, x);
491                 setvol(mutevol);
492                 /* Wait 0.01 sec */
493                 usleep(10000);
494         }
495         mutevol = mutedlevel(vol, mutelevel);
496         setvol(mutevol);
497         if (debug)
498 #ifdef __Darwin__
499                 printf("Mute from '%f' to '%f'!\n", oldvol, mutevol);
500 #else
501                 printf("Mute from '%04x' to '%04x'!\n", oldvol, mutevol);
502 #endif
503         muted = 1;
504 }
505
506 static void unmute(void)
507 {
508 #ifdef __Darwin__
509         float vol;
510         float start;
511         float x;
512 #else
513         int vol;
514         int start;
515         int x;
516 #endif
517         vol = getvol();
518         if (debug)
519 #ifdef __Darwin__
520                 printf("Unmute from '%f' (should be '%f') to '%f'!\n", vol, mutevol, oldvol);
521         mutevol = vol;
522         if (vol == mutevol) {
523 #else
524                 printf("Unmute from '%04x' (should be '%04x') to '%04x'!\n", vol, mutevol, oldvol);
525         if ((int)vol == mutevol) {
526 #endif
527                 if (smoothfade)
528                         start = mutelevel;
529                 else
530 #ifdef __Darwin__
531                         start = 1.0;
532 #else
533                         start = 100;
534 #endif
535                 for (x=start;x<100;x+=stepsize) {
536                         mutevol = mutedlevel(oldvol, x);
537                         setvol(mutevol);
538                         /* Wait 0.01 sec */
539                         usleep(10000);
540                 }
541                 setvol(oldvol);
542         } else
543                 printf("Whoops, it's already been changed!\n");
544         muted = 0;
545 }
546
547 static void check_mute(void)
548 {
549         int offhook = 0;
550         struct channel *chan;
551         chan = channels;
552         while(chan) {
553                 if (chan->subs) {
554                         offhook++;
555                         break;
556                 }
557                 chan = chan->next;
558         }
559         if (offhook && !muted)
560                 mute();
561         else if (!offhook && muted)
562                 unmute();
563 }
564
565 static void delete_sub(struct channel *chan, char *name)
566 {
567         struct subchannel *sub, *prev;
568         prev = NULL;
569         sub = chan->subs;
570         while(sub) {
571                 if (!strcasecmp(sub->name, name)) {
572                         if (prev)
573                                 prev->next = sub->next;
574                         else
575                                 chan->subs = sub->next;
576                         free(sub->name);
577                         free(sub);
578                         return;
579                 }
580                 prev = sub;
581                 sub = sub->next;
582         }
583 }
584
585 static void append_sub(struct channel *chan, char *name)
586 {
587         struct subchannel *sub;
588         sub = chan->subs;
589         while(sub) {
590                 if (!strcasecmp(sub->name, name))
591                         return;
592                 sub = sub->next;
593         }
594         sub = malloc(sizeof(struct subchannel));
595         if (sub) {
596                 memset(sub, 0, sizeof(struct subchannel));
597                 if (!(sub->name = strdup(name))) {
598                         free(sub);
599                         return;
600                 }
601                 sub->next = chan->subs;
602                 chan->subs = sub;
603         }
604 }
605
606 static void hangup_chan(char *channel)
607 {
608         struct channel *chan;
609         if (debug)
610                 printf("Hangup '%s'\n", channel);
611         chan = find_channel(channel);
612         if (chan)
613                 delete_sub(chan, channel);
614         check_mute();
615 }
616
617 static void offhook_chan(char *channel)
618 {
619         struct channel *chan;
620         if (debug)
621                 printf("Offhook '%s'\n", channel);
622         chan = find_channel(channel);
623         if (chan)
624                 append_sub(chan, channel);
625         check_mute();
626 }
627
628 static int wait_event(void)
629 {
630         char *resp;
631         char event[120]="";
632         char channel[120]="";
633         char oldname[120]="";
634         char newname[120]="";
635
636         resp = get_line();
637         if (!resp) {
638                 fprintf(stderr, "disconnected (6)\n");
639                 return -1;
640         }
641         if (!strncasecmp(resp, "Event: ", strlen("Event: "))) {
642                 strncpy(event, resp + strlen("Event: "), sizeof(event) - 1);
643                 /* Consume the rest of the non-event */
644                 while((resp = get_line()) && strlen(resp)) {
645                         if (!strncasecmp(resp, "Channel: ", strlen("Channel: ")))
646                                 strncpy(channel, resp + strlen("Channel: "), sizeof(channel) - 1);
647                         if (!strncasecmp(resp, "Newname: ", strlen("Newname: ")))
648                                 strncpy(newname, resp + strlen("Newname: "), sizeof(newname) - 1);
649                         if (!strncasecmp(resp, "Oldname: ", strlen("Oldname: ")))
650                                 strncpy(oldname, resp + strlen("Oldname: "), sizeof(oldname) - 1);
651                 }
652                 if (strlen(channel)) {
653                         if (!strcasecmp(event, "Hangup"))
654                                 hangup_chan(channel);
655                         else
656                                 offhook_chan(channel);
657                 }
658                 if (strlen(newname) && strlen(oldname)) {
659                         if (!strcasecmp(event, "Rename")) {
660                                 hangup_chan(oldname);
661                                 offhook_chan(newname);
662                         }
663                 }
664         } else {
665                 /* Consume the rest of the non-event */
666                 while((resp = get_line()) && strlen(resp));
667         }
668         if (!resp) {
669                 fprintf(stderr, "disconnected (7)\n");
670                 return -1;
671         }
672         return 0;
673 }
674
675 static void usage(void)
676 {
677         printf("Usage: muted [-f] [-d]\n"
678                "        -f : Do not fork\n"
679                "        -d : Debug (implies -f)\n");
680 }
681
682 int main(int argc, char *argv[])
683 {
684         int x;
685         while((x = getopt(argc, argv, "fhd")) > 0) {
686                 switch(x) {
687                 case 'd':
688                         debug = 1;
689                         needfork = 0;
690                         break;
691                 case 'f':
692                         needfork = 0;
693                         break;
694                 case 'h':
695                         /* Fall through */
696                 default:
697                         usage();
698                         exit(1);
699                 }
700         }
701         if (load_config())
702                 exit(1);
703 #ifndef __Darwin__
704         if (open_mixer())
705                 exit(1);
706 #endif
707         if (connect_asterisk()) {
708 #ifndef __Darwin__
709                 close(mixfd);
710 #endif
711                 exit(1);
712         }
713         if (login_asterisk()) {
714 #ifndef __Darwin__
715                 close(mixfd);
716 #endif
717                 fclose(astf);
718                 exit(1);
719         }
720 #ifdef HAVE_WORKING_FORK
721         if (needfork) {
722 #ifndef HAVE_SBIN_LAUNCHD
723                 if (daemon(0,0) < 0) {
724                         fprintf(stderr, "daemon() failed: %s\n", strerror(errno));
725                         exit(1);
726                 }
727 #else
728                 const char *found = NULL, *paths[] = {
729                         "/Library/LaunchAgents/org.asterisk.muted.plist",
730                         "/Library/LaunchDaemons/org.asterisk.muted.plist",
731                         "contrib/init.d/org.asterisk.muted.plist",
732                         "<path-to-asterisk-source>/contrib/init.d/org.asterisk.muted.plist" };
733                 char userpath[256];
734                 struct stat unused;
735                 struct passwd *pwd = getpwuid(getuid());
736                 int i;
737
738                 snprintf(userpath, sizeof(userpath), "%s%s", pwd->pw_dir, paths[0]);
739                 if (!stat(userpath, &unused)) {
740                         found = userpath;
741                 }
742
743                 if (!found) {
744                         for (i = 0; i < 3; i++) {
745                                 if (!stat(paths[i], &unused)) {
746                                         found = paths[i];
747                                         break;
748                                 }
749                         }
750                 }
751
752                 fprintf(stderr, "Mac OS X detected.  Use 'launchctl load -w %s' to launch.\n", found ? found : paths[3]);
753                 exit(1);
754 #endif /* !defined(HAVE_SBIN_LAUNCHD */
755         }
756 #endif
757         for(;;) {
758                 if (wait_event()) {
759                         fclose(astf);
760                         while(connect_asterisk()) {
761                                 sleep(5);
762                         }
763                         if (login_asterisk()) {
764                                 fclose(astf);
765                                 exit(1);
766                         }
767                 }
768         }
769         exit(0);
770 }