remove extraneous svn:executable properties
[asterisk/asterisk.git] / utils / astman.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  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*
20  *
21  * ASTerisk MANager
22  *
23  */
24  
25 #include <newt.h>
26 #include <stdio.h>
27 #include <sys/time.h>
28 #include <netdb.h>
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
31 #include <sys/socket.h>
32 #include <sys/select.h>
33 #include <fcntl.h>
34 #include <string.h>
35 #include <stdio.h>
36 #include <errno.h>
37 #include <unistd.h>
38 #include <stdlib.h>
39
40 #include "asterisk/md5.h"
41 #include "asterisk/manager.h"
42
43 #undef gethostbyname
44
45 #define MAX_HEADERS 80
46 #define MAX_LEN 256
47
48 /*
49  * 2005.05.27 - different versions of newt define the type of the buffer
50  * for the 5th argument to newtEntry() as char ** or const char ** . To 
51  * let the code compile cleanly with -Werror, we cast it to void * through 
52  * _NEWT_CAST.
53  */
54 #define _NEWT_CAST (void *)
55
56 static struct ast_mansession {
57         struct sockaddr_in sin;
58         int fd;
59         char inbuf[MAX_LEN];
60         int inlen;
61 } session;
62
63 static struct ast_chan {
64         char name[80];
65         char exten[20];
66         char context[20];
67         char priority[20];
68         char callerid[40];
69         char state[10];
70         struct ast_chan *next;
71 } *chans;
72
73 /* dummy functions to be compatible with the Asterisk core for md5.c */
74 void ast_register_file_version(const char *file, const char *version);
75 void ast_register_file_version(const char *file, const char *version)
76 {
77 }
78
79 void ast_unregister_file_version(const char *file);
80 void ast_unregister_file_version(const char *file)
81 {
82 }
83
84 static struct ast_chan *find_chan(char *name)
85 {
86         struct ast_chan *prev = NULL, *chan = chans;
87         while(chan) {
88                 if (!strcmp(name, chan->name))
89                         return chan;
90                 prev = chan;
91                 chan = chan->next;
92         }
93         chan = malloc(sizeof(struct ast_chan));
94         if (chan) {
95                 memset(chan, 0, sizeof(struct ast_chan));
96                 strncpy(chan->name, name, sizeof(chan->name) - 1);
97                 if (prev) 
98                         prev->next = chan;
99                 else
100                         chans = chan;
101         }
102         return chan;
103 }
104
105 static void del_chan(char *name)
106 {
107         struct ast_chan *prev = NULL, *chan = chans;
108         while(chan) {
109                 if (!strcmp(name, chan->name)) {
110                         if (prev)
111                                 prev->next = chan->next;
112                         else
113                                 chans = chan->next;
114                         return;
115                 }
116                 prev = chan;
117                 chan = chan->next;
118         }
119 }
120
121 static void fdprintf(int fd, char *fmt, ...)
122 {
123         char stuff[4096];
124         va_list ap;
125         va_start(ap, fmt);
126         vsnprintf(stuff, sizeof(stuff), fmt, ap);
127         va_end(ap);
128         write(fd, stuff, strlen(stuff));
129 }
130
131 static char *get_header(struct message *m, char *var)
132 {
133         char cmp[80];
134         int x;
135         snprintf(cmp, sizeof(cmp), "%s: ", var);
136         for (x=0;x<m->hdrcount;x++)
137                 if (!strncasecmp(cmp, m->headers[x], strlen(cmp)))
138                         return m->headers[x] + strlen(cmp);
139         return "";
140 }
141
142 static int event_newstate(struct ast_mansession *s, struct message *m)
143 {
144         struct ast_chan *chan;
145         chan = find_chan(get_header(m, "Channel"));
146         strncpy(chan->state, get_header(m, "State"), sizeof(chan->state) - 1);
147         return 0;
148 }
149
150 static int event_newexten(struct ast_mansession *s, struct message *m)
151 {
152         struct ast_chan *chan;
153         chan = find_chan(get_header(m, "Channel"));
154         strncpy(chan->exten, get_header(m, "Extension"), sizeof(chan->exten) - 1);
155         strncpy(chan->context, get_header(m, "Context"), sizeof(chan->context) - 1);
156         strncpy(chan->priority, get_header(m, "Priority"), sizeof(chan->priority) - 1);
157         return 0;
158 }
159
160 static int event_newchannel(struct ast_mansession *s, struct message *m)
161 {
162         struct ast_chan *chan;
163         chan = find_chan(get_header(m, "Channel"));
164         strncpy(chan->state, get_header(m, "State"), sizeof(chan->state) - 1);
165         strncpy(chan->callerid, get_header(m, "Callerid"), sizeof(chan->callerid) - 1);
166         return 0;
167 }
168
169 static int event_status(struct ast_mansession *s, struct message *m)
170 {
171         struct ast_chan *chan;
172         chan = find_chan(get_header(m, "Channel"));
173         strncpy(chan->state, get_header(m, "State"), sizeof(chan->state) - 1);
174         strncpy(chan->callerid, get_header(m, "Callerid"), sizeof(chan->callerid) - 1);
175         strncpy(chan->exten, get_header(m, "Extension"), sizeof(chan->exten) - 1);
176         strncpy(chan->context, get_header(m, "Context"), sizeof(chan->context) - 1);
177         strncpy(chan->priority, get_header(m, "Priority"), sizeof(chan->priority) - 1);
178         return 0;
179 }
180
181 static int event_hangup(struct ast_mansession *s, struct message *m)
182 {
183         del_chan(get_header(m, "Channel"));
184         return 0;
185 }
186
187 static int event_ignore(struct ast_mansession *s, struct message *m)
188 {
189         return 0;
190 }
191
192 static int event_rename(struct ast_mansession *s, struct message *m)
193 {
194         struct ast_chan *chan;
195         chan = find_chan(get_header(m, "Oldname"));
196         strncpy(chan->name, get_header(m, "Newname"), sizeof(chan->name) - 1);
197         return 0;
198 }
199 static struct event {
200         char *event;
201         int (*func)(struct ast_mansession *s, struct message *m);
202 } events[] = {
203         { "Newstate", event_newstate },
204         { "Newchannel", event_newchannel },
205         { "Newexten", event_newexten },
206         { "Hangup", event_hangup },
207         { "Rename", event_rename },
208         { "Status", event_status },
209         { "Link", event_ignore },
210         { "Unlink", event_ignore },
211         { "StatusComplete", event_ignore }
212 };
213
214 static int process_message(struct ast_mansession *s, struct message *m)
215 {
216         int x;
217         char event[80] = "";
218         strncpy(event, get_header(m, "Event"), sizeof(event) - 1);
219         if (!strlen(event)) {
220                 fprintf(stderr, "Missing event in request");
221                 return 0;
222         }
223         for (x=0;x<sizeof(events) / sizeof(events[0]);x++) {
224                 if (!strcasecmp(event, events[x].event)) {
225                         if (events[x].func(s, m))
226                                 return -1;
227                         break;
228                 }
229         }
230         if (x >= sizeof(events) / sizeof(events[0]))
231                 fprintf(stderr, "Ignoring unknown event '%s'", event);
232 #if 0
233         for (x=0;x<m->hdrcount;x++) {
234                 printf("Header: %s\n", m->headers[x]);
235         }
236 #endif  
237         return 0;
238 }
239
240 static void rebuild_channels(newtComponent c)
241 {
242         void *prev = NULL;
243         struct ast_chan *chan;
244         char tmpn[42];
245         char tmp[256];
246         int x=0;
247         prev = newtListboxGetCurrent(c);
248         newtListboxClear(c);
249         chan = chans;
250         while(chan) {
251                 snprintf(tmpn, sizeof(tmpn), "%s (%s)", chan->name, chan->callerid);
252                 if (strlen(chan->exten)) 
253                         snprintf(tmp, sizeof(tmp), "%-30s %8s -> %s@%s:%s", 
254                                 tmpn, chan->state,
255                                 chan->exten, chan->context, chan->priority);
256                 else
257                         snprintf(tmp, sizeof(tmp), "%-30s %8s",
258                                 tmpn, chan->state);
259                 newtListboxAppendEntry(c, tmp, chan);
260                 x++;
261                 chan = chan->next;
262         }
263         if (!x)
264                 newtListboxAppendEntry(c, " << No Active Channels >> ", NULL);
265         newtListboxSetCurrentByKey(c, prev);
266 }
267
268 static int has_input(struct ast_mansession *s)
269 {
270         int x;
271         for (x=1;x<s->inlen;x++) 
272                 if ((s->inbuf[x] == '\n') && (s->inbuf[x-1] == '\r')) 
273                         return 1;
274         return 0;
275 }
276
277 static int get_input(struct ast_mansession *s, char *output)
278 {
279         /* output must have at least sizeof(s->inbuf) space */
280         int res;
281         int x;
282         struct timeval tv = {0, 0};
283         fd_set fds;
284         for (x=1;x<s->inlen;x++) {
285                 if ((s->inbuf[x] == '\n') && (s->inbuf[x-1] == '\r')) {
286                         /* Copy output data up to and including \r\n */
287                         memcpy(output, s->inbuf, x + 1);
288                         /* Add trailing \0 */
289                         output[x+1] = '\0';
290                         /* Move remaining data back to the front */
291                         memmove(s->inbuf, s->inbuf + x + 1, s->inlen - x);
292                         s->inlen -= (x + 1);
293                         return 1;
294                 }
295         } 
296         if (s->inlen >= sizeof(s->inbuf) - 1) {
297                 fprintf(stderr, "Dumping long line with no return from %s: %s\n", inet_ntoa(s->sin.sin_addr), s->inbuf);
298                 s->inlen = 0;
299         }
300         FD_ZERO(&fds);
301         FD_SET(s->fd, &fds);
302         res = select(s->fd + 1, &fds, NULL, NULL, &tv);
303         if (res < 0) {
304                 fprintf(stderr, "Select returned error: %s\n", strerror(errno));
305         } else if (res > 0) {
306                 res = read(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen);
307                 if (res < 1)
308                         return -1;
309                 s->inlen += res;
310                 s->inbuf[s->inlen] = '\0';
311         } else {
312                 return 2;
313         }
314         return 0;
315 }
316
317 static int input_check(struct ast_mansession *s, struct message **mout)
318 {
319         static struct message m;
320         int res;
321
322         if (mout)
323                 *mout = NULL;
324
325         for(;;) {
326                 res = get_input(s, m.headers[m.hdrcount]);
327                 if (res == 1) {
328 #if 0
329                         fprintf(stderr, "Got header: %s", m.headers[m.hdrcount]);
330                         fgetc(stdin);
331 #endif
332                         /* Strip trailing \r\n */
333                         if (strlen(m.headers[m.hdrcount]) < 2)
334                                 continue;
335                         m.headers[m.hdrcount][strlen(m.headers[m.hdrcount]) - 2] = '\0';
336                         if (!strlen(m.headers[m.hdrcount])) {
337                                 if (mout && strlen(get_header(&m, "Response"))) {
338                                         *mout = &m;
339                                         return 0;
340                                 }
341                                 if (process_message(s, &m))
342                                         break;
343                                 memset(&m, 0, sizeof(&m));
344                         } else if (m.hdrcount < MAX_HEADERS - 1)
345                                 m.hdrcount++;
346                 } else if (res < 0) {
347                         return -1;
348                 } else if (res == 2)
349                         return 0;
350         }
351         return -1;
352 }
353
354 static struct message *wait_for_response(int timeout)
355 {
356         struct message *m;
357         struct timeval tv;
358         int res;
359         fd_set fds;
360         for (;;) {
361                 tv.tv_sec = timeout / 1000;
362                 tv.tv_usec = (timeout % 1000) * 1000;
363                 FD_SET(session.fd, &fds);
364                 res = select(session.fd + 1, &fds, NULL, NULL, &tv);
365                 if (res < 1)
366                         break;
367                 if (input_check(&session, &m) < 0) {
368                         return NULL;
369                 }
370                 if (m)
371                         return m;
372         }
373         return NULL;
374 }
375
376 static int manager_action(char *action, char *fmt, ...)
377 {
378         struct ast_mansession *s;
379         char tmp[4096];
380         va_list ap;
381
382         s = &session;
383         fdprintf(s->fd, "Action: %s\r\n", action);
384         va_start(ap, fmt);
385         vsnprintf(tmp, sizeof(tmp), fmt, ap);
386         va_end(ap);
387         write(s->fd, tmp, strlen(tmp));
388         fdprintf(s->fd, "\r\n");
389         return 0;
390 }
391
392 static int show_message(char *title, char *msg)
393 {
394         newtComponent form;
395         newtComponent label;
396         newtComponent ok;
397         struct newtExitStruct es;
398
399         newtCenteredWindow(60,7, title);
400
401         label = newtLabel(4,1,msg);
402         ok = newtButton(27, 3, "OK");
403         form = newtForm(NULL, NULL, 0);
404         newtFormAddComponents(form, label, ok, NULL);
405         newtFormRun(form, &es);
406         newtPopWindow();
407         newtFormDestroy(form);
408         return 0;
409 }
410
411 static newtComponent showform;
412 static int show_doing(char *title, char *tmp)
413 {
414         struct newtExitStruct es;
415         newtComponent label;
416         showform = newtForm(NULL, NULL, 0);
417         newtCenteredWindow(70,4, title);
418         label = newtLabel(3,1,tmp);
419         newtFormAddComponents(showform,label, NULL);
420         newtFormSetTimer(showform, 200);
421         newtFormRun(showform, &es);
422         return 0;
423 }
424
425 static int hide_doing(void)
426 {
427         newtPopWindow();
428         newtFormDestroy(showform);
429         return 0;
430 }
431
432 static void try_status(void)
433 {
434         struct message *m;
435         manager_action("Status", "");
436         m = wait_for_response(10000);
437         if (!m) {
438                 show_message("Status Failed", "Timeout waiting for response");
439         } else if (strcasecmp(get_header(m, "Response"), "Success"))  {
440                 show_message("Status Failed Failed", get_header(m, "Message"));
441         }
442 }
443         
444
445 static void try_hangup(newtComponent c)
446 {
447         struct ast_chan *chan;
448         struct message *m;
449
450         chan = newtListboxGetCurrent(c);
451         if (chan) {
452                 manager_action("Hangup", "Channel: %s\r\n", chan->name);
453                 m = wait_for_response(10000);
454                 if (!m) {
455                         show_message("Hangup Failed", "Timeout waiting for response");
456                 } else if (strcasecmp(get_header(m, "Response"), "Success"))  {
457                         show_message("Hangup Failed", get_header(m, "Message"));
458                 }
459         }
460         
461 }
462
463 static int get_user_input(char *msg, char *buf, int buflen)
464 {
465         newtComponent form;
466         newtComponent ok;
467         newtComponent cancel;
468         newtComponent inpfield;
469         const char *input;
470         int res = -1;
471         struct newtExitStruct es;
472
473         newtCenteredWindow(60,7, msg);
474
475         inpfield = newtEntry(5, 2, "", 50, _NEWT_CAST &input, 0);
476         ok = newtButton(22, 3, "OK");
477         cancel = newtButton(32, 3, "Cancel");
478         form = newtForm(NULL, NULL, 0);
479         newtFormAddComponents(form, inpfield, ok, cancel, NULL);
480         newtFormRun(form, &es);
481         strncpy(buf, input, buflen - 1);
482         if (es.u.co == ok) 
483                 res = 0;
484         else
485                 res = -1;
486         newtPopWindow();
487         newtFormDestroy(form);
488         return res;
489 }
490
491 static void try_redirect(newtComponent c)
492 {
493         struct ast_chan *chan;
494         char dest[256];
495         struct message *m;
496         char channame[256];
497         char tmp[80];
498         char *context;
499
500         chan = newtListboxGetCurrent(c);
501         if (chan) {
502                 strncpy(channame, chan->name, sizeof(channame) - 1);
503                 snprintf(tmp, sizeof(tmp), "Enter new extension for %s", channame);
504                 if (get_user_input(tmp, dest, sizeof(dest))) 
505                         return;
506                 if ((context = strchr(dest, '@'))) {
507                         *context = '\0';
508                         context++;
509                         manager_action("Redirect", "Channel: %s\r\nContext: %s\r\nExten: %s\r\nPriority: 1\r\n", chan->name,context,dest);
510                 } else {
511                         manager_action("Redirect", "Channel: %s\r\nExten: %s\r\nPriority: 1\r\n", chan->name, dest);
512                 }
513                 m = wait_for_response(10000);
514                 if (!m) {
515                         show_message("Hangup Failed", "Timeout waiting for response");
516                 } else if (strcasecmp(get_header(m, "Response"), "Success"))  {
517                         show_message("Hangup Failed", get_header(m, "Message"));
518                 }
519         }
520         
521 }
522
523 static int manage_calls(char *host)
524 {
525         newtComponent form;
526         newtComponent quit;
527         newtComponent hangup;
528         newtComponent redirect;
529         newtComponent channels;
530         struct newtExitStruct es;
531         char tmp[80];
532
533         /* If there's one thing you learn from this code, it is this...
534            Never, ever fly Air France.  Their customer service is absolutely
535            the worst.  I've never heard the words "That's not my problem" as 
536            many times as I have from their staff -- It should, without doubt
537            be their corporate motto if it isn't already.  Don't bother giving 
538            them business because you're just a pain in their side and they
539            will be sure to let you know the first time you speak to them.
540            
541            If you ever want to make me happy just tell me that you, too, will
542            never fly Air France again either (in spite of their excellent
543            cuisine). */
544         snprintf(tmp, sizeof(tmp), "Asterisk Manager at %s", host);
545         newtCenteredWindow(74, 20, tmp);
546         form = newtForm(NULL, NULL, 0);
547         newtFormWatchFd(form, session.fd, NEWT_FD_READ);
548         newtFormSetTimer(form, 100);
549         quit = newtButton(62, 16, "Quit");
550         redirect = newtButton(35, 16, "Redirect");
551         hangup = newtButton(50, 16, "Hangup");
552         channels = newtListbox(1,1,14, NEWT_FLAG_SCROLL);
553         newtFormAddComponents(form, channels, redirect, hangup, quit, NULL);
554         newtListboxSetWidth(channels, 72);
555         
556         show_doing("Getting Status", "Retrieving system status...");
557         try_status();
558         hide_doing();
559
560         for(;;) {
561                 newtFormRun(form, &es);
562                 if (has_input(&session) || (es.reason == NEWT_EXIT_FDREADY)) {
563                         if (input_check(&session, NULL)) {
564                                 show_message("Disconnected", "Disconnected from remote host");
565                                 break;
566                         }
567                 } else if (es.reason == NEWT_EXIT_COMPONENT) {
568                         if (es.u.co == quit)
569                                 break;
570                         if (es.u.co == hangup) {
571                                 try_hangup(channels);
572                         } else if (es.u.co == redirect) {
573                                 try_redirect(channels);
574                         }
575                 }
576                 rebuild_channels(channels);
577         }
578         newtFormDestroy(form);
579         return 0;
580 }
581
582 static int login(char *hostname)
583 {
584         newtComponent form;
585         newtComponent cancel;
586         newtComponent login;
587         newtComponent username;
588         newtComponent password;
589         newtComponent label;
590         newtComponent ulabel;
591         newtComponent plabel;
592         const char *user;
593         const char *pass;
594         struct message *m;
595         struct newtExitStruct es;
596         char tmp[55];
597         struct hostent *hp;
598         int res = -1;
599         
600         session.fd = socket(AF_INET, SOCK_STREAM, 0);
601         if (session.fd < 0) {
602                 snprintf(tmp, sizeof(tmp), "socket() failed: %s\n", strerror(errno));
603                 show_message("Socket failed", tmp);
604                 return -1;
605         }
606         
607         snprintf(tmp, sizeof(tmp), "Looking up %s\n", hostname);
608         show_doing("Connecting....", tmp);
609         
610         
611         hp = gethostbyname(hostname);
612         if (!hp) {
613                 snprintf(tmp, sizeof(tmp), "No such address: %s\n", hostname);
614                 show_message("Host lookup failed", tmp);
615                 return -1;
616         }
617         hide_doing();
618         snprintf(tmp, sizeof(tmp), "Connecting to %s", hostname);
619         show_doing("Connecting...", tmp);
620
621         session.sin.sin_family = AF_INET;
622         session.sin.sin_port = htons(DEFAULT_MANAGER_PORT);
623         memcpy(&session.sin.sin_addr, hp->h_addr, sizeof(session.sin.sin_addr));
624
625         if (connect(session.fd,(struct sockaddr*)&session.sin, sizeof(session.sin))) {
626                 snprintf(tmp, sizeof(tmp), "%s failed: %s\n", hostname, strerror(errno));
627                 show_message("Connect Failed", tmp);
628                 return -1;
629         }
630         
631         hide_doing();
632         
633         login = newtButton(5, 6, "Login");
634         cancel = newtButton(25, 6, "Cancel");
635         newtCenteredWindow(40, 10, "Asterisk Manager Login");
636         snprintf(tmp, sizeof(tmp), "Host:     %s", hostname);
637         label = newtLabel(4,1, tmp);
638         
639         ulabel = newtLabel(4,2,"Username:");
640         plabel = newtLabel(4,3,"Password:");
641         
642         username = newtEntry(14, 2, "", 20, _NEWT_CAST &user, 0);
643         password = newtEntry(14, 3, "", 20, _NEWT_CAST &pass, NEWT_FLAG_HIDDEN);
644         
645         form = newtForm(NULL, NULL, 0);
646         newtFormAddComponents(form, username, password, login, cancel, label, ulabel, plabel,NULL);
647         newtFormRun(form, &es);
648         if (es.reason == NEWT_EXIT_COMPONENT) {
649                 if (es.u.co == login) {
650                         snprintf(tmp, sizeof(tmp), "Logging in '%s'...", user);
651                         show_doing("Logging in", tmp);
652                         /* Check to see if the remote host supports MD5 Authentication */
653                         manager_action("Challenge", "AuthType: MD5\r\n");
654                         m = wait_for_response(10000);
655                         if (m && !strcasecmp(get_header(m, "Response"), "Success")) {
656                                 char *challenge = get_header(m, "Challenge");
657                                 int x;
658                                 int len = 0;
659                                 char md5key[256] = "";
660                                 struct MD5Context md5;
661                                 unsigned char digest[16];
662                                 MD5Init(&md5);
663                                 MD5Update(&md5, challenge, strlen(challenge));
664                                 MD5Update(&md5, pass, strlen(pass));
665                                 MD5Final(digest, &md5);
666                                 for (x=0; x<16; x++)
667                                         len += sprintf(md5key + len, "%2.2x", digest[x]);
668                                 manager_action("Login",
669                                                 "AuthType: MD5\r\n"
670                                                 "Username: %s\r\n"
671                                                 "Key: %s\r\n",
672                                                 user, md5key);
673                                 m = wait_for_response(10000);
674                                 hide_doing();
675                                 if (!strcasecmp(get_header(m, "Response"), "Success")) {
676                                         res = 0;
677                                 } else {
678                                         show_message("Login Failed", get_header(m, "Message"));
679                                 }
680                         } else {
681                                 memset(m, 0, sizeof(m));
682                                 manager_action("Login", 
683                                         "Username: %s\r\n"
684                                         "Secret: %s\r\n",
685                                                 user, pass);
686                                 m = wait_for_response(10000);
687                                 hide_doing();
688                                 if (m) {
689                                         if (!strcasecmp(get_header(m, "Response"), "Success")) {
690                                                 res = 0;
691                                         } else {
692                                                 show_message("Login Failed", get_header(m, "Message"));
693                                         }
694                                 }
695                         }
696                 }
697         }
698         newtFormDestroy(form);
699         return res;
700 }
701
702 int main(int argc, char *argv[])
703 {
704         if (argc < 2) {
705                 fprintf(stderr, "Usage: astman <host>\n");
706                 exit(1);
707         }
708         newtInit();
709         newtCls();
710         newtDrawRootText(0, 0, "Asterisk Manager (C)2002, Linux Support Services, Inc.");
711         newtPushHelpLine("Welcome to the Asterisk Manager!");
712         if (login(argv[1])) {
713                 newtFinished();
714                 exit(1);
715         }
716         manage_calls(argv[1]);
717         newtFinished();
718         return 0;
719 }