]> git.mxchange.org Git - flightgear.git/blob - 3rdparty/iaxclient/lib/libiax2/src/winiphone.c
VS2015 compatability fixes.
[flightgear.git] / 3rdparty / iaxclient / lib / libiax2 / src / winiphone.c
1 /*
2  * Miniphone: A simple, command line telephone
3  *
4  * IAX Support for talking to Asterisk and other Gnophone clients
5  *
6  * Copyright (C) 1999, Linux Support Services, Inc.
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 /* #define      PRINTCHUCK /* enable this to indicate chucked incomming packets */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <fcntl.h>
20 #include <io.h>
21 #include <conio.h>
22 #include <stdio.h>
23 #include <errno.h>
24 #include <time.h>
25 #include <process.h>
26 #include <windows.h>
27 #include <winsock.h>
28 #include <mmsystem.h>
29 #include <malloc.h>
30 #include "gsm.h"
31 #include "iax-client.h"
32 #include "frame.h"
33 #include "miniphone.h"
34
35
36 struct peer {
37         int time;
38         gsm gsmin;
39         gsm gsmout;
40
41         struct iax_session *session;
42         struct peer *next;
43 };
44
45 static struct peer *peers;
46 static int answered_call = 0;
47
48 /* stuff for wave audio device */
49 HWAVEOUT wout;
50 HWAVEIN win;
51
52 typedef struct whout {
53         WAVEHDR w;
54         short   data[160];
55         struct whout *next;
56 } WHOUT;
57
58 WHOUT *outqueue = NULL;
59
60 /* parameters for audio in */
61 #define NWHIN 8                         /* number of input buffer entries */
62 /* NOTE the OUT_INTERVAL parameter *SHOULD* be more around 18 to 20 or so, since the packets should
63 be spaced by 20 milliseconds. However, in practice, especially in Windoze-95, setting it that high
64 caused underruns. 10 is just ever so slightly agressive, and the receiver has to chuck a packet
65 every now and then. Thats about the way it should be to be happy. */
66 #define OUT_INTERVAL 10         /* number of ms to wait before sending more data to peer */
67 /* parameters for audio out */
68 #define OUT_DEPTH 12            /* number of outbut buffer entries */
69 #define OUT_PAUSE_THRESHOLD 2 /* number of active entries needed to start output (for smoothing) */
70
71 /* audio input buffer headers */
72 WAVEHDR whin[NWHIN];
73 /* audio input buffers */
74 char bufin[NWHIN][320];
75
76 /* initialize the sequence variables for the audio in stuff */
77 unsigned int whinserial = 1,nextwhin = 1;
78
79 static struct peer *find_peer(struct iax_session *);
80 static void parse_args(FILE *, unsigned char *);
81 void do_iax_event(FILE *);
82 void call(FILE *, char *);
83 void answer_call(void);
84 void reject_call(void);
85 static void handle_event(FILE *, struct iax_event *e, struct peer *p);
86 void parse_cmd(FILE *, int, char **);
87 void issue_prompt(FILE *);
88 void dump_array(FILE *, char **);
89
90 static char *help[] = {
91 "Welcome to the miniphone telephony client, the commands are as follows:\n",
92 "Help\t\t-\tDisplays this screen.",
93 "Call <Number>\t-\tDials the number supplied.",
94 "Answer\t\t-\tAnswers an Inbound call.",
95 "Reject\t\t-\tRejects an Inbound call.",
96 "Dump\t\t-\tDumps (disconnects) the current call.",
97 "Dtmf <Digit>\t-\tSends specified DTMF digit.",
98 "Status\t\t-\tLists the current sessions and their current status.",
99 "Quit\t\t-\tShuts down the client.",
100 "",
101 0
102 };
103
104 static struct peer *most_recent_answer;
105 static struct iax_session *newcall = 0;
106
107 /* holder of the time, relative to startup in system ticks. See our
108 gettimeofday() implementation */
109 time_t  startuptime;
110
111 /* routine called at exit to shutdown audio I/O and close nicely.
112 NOTE: If all this isnt done, the system doesnt not handle this
113 cleanly and has to be rebooted. What a pile of doo doo!! */
114 void killem(void)
115 {
116         waveInStop(win);
117         waveInReset(win);
118         waveInClose(win); 
119         waveOutReset(wout);
120         waveOutClose(wout);
121         WSACleanup(); /* dont forget socket stuff too */
122         return;
123 }
124
125 /* Win-doze doenst have gettimeofday(). This sux. So, what we did is
126 provide some gettimeofday-like functionality that works for our purposes.
127 In the main(), we take a sample of the system tick counter (into startuptime).
128 This function returns the relative time since program startup, more or less,
129 which is certainly good enough for our purposes. */
130 void gettimeofday(struct timeval *tv, struct timezone *tz)
131 {
132         long l = startuptime + GetTickCount();
133
134         tv->tv_sec = l / 1000;
135         tv->tv_usec = (l % 1000) * 1000;
136         return;
137 }
138
139
140 static struct peer *find_peer(struct iax_session *session)
141 {
142         struct peer *cur = peers;
143         while(cur) {
144                 if (cur->session == session)
145                         return cur;
146                 cur = cur->next;
147         }
148         return NULL;
149 }
150
151 void
152 parse_args(FILE *f, unsigned char *cmd)
153 {
154         static char *argv[MAXARGS];
155         unsigned char *parse = cmd;
156         int argc = 0, t = 0;
157
158         // Don't mess with anything that doesn't exist...
159         if(!*parse)
160                 return;
161
162         memset(argv, 0, sizeof(argv));
163         while(*parse) {
164                 if(*parse < 33 || *parse > 128) {
165                         *parse = 0, t++;
166                         if(t > MAXARG) {
167                                 fprintf(f, "Warning: Argument exceeds maximum argument size, command ignored!\n");
168                                 return;
169                         }
170                 } else if(t || !argc) {
171                         if(argc == MAXARGS) {
172                                 fprintf(f, "Warning: Command ignored, too many arguments\n");
173                                 return;
174                         }
175                         argv[argc++] = parse;
176                         t = 0;
177                 }
178
179                 parse++;
180         }
181
182         if(argc)
183                 parse_cmd(f, argc, argv);
184 }
185
186 /* handle all network requests, and a pending scheduled event, if any */
187 void service_network(int netfd, FILE *f)
188 {
189         fd_set readfd;
190         struct timeval dumbtimer;
191
192         /* set up a timer that falls-through */
193         dumbtimer.tv_sec = 0;
194         dumbtimer.tv_usec = 0;
195
196
197                 for(;;) /* suck everything outa network stuff */
198                 {
199                         FD_ZERO(&readfd);
200                         FD_SET(netfd, &readfd);
201                         if (select(netfd + 1, &readfd, 0, 0, &dumbtimer) > 0)
202                         {
203                                 if (FD_ISSET(netfd,&readfd))
204                                 {
205                                         do_iax_event(f);
206                                         (void) iax_time_to_next_event();
207                                 } else break;
208                         } else break;
209                 }
210                 do_iax_event(f); /* do pending event if any */
211 }
212
213
214 int
215 main(int argc, char *argv[])
216 {
217         int port;
218         int netfd;
219         int c, i;
220         FILE *f;
221         char rcmd[RBUFSIZE];
222         gsm_frame fo;
223         WSADATA foop;
224         time_t  t;
225         WAVEFORMATEX wf;
226         WHOUT *wh,*wh1,*wh2;
227         unsigned long lastouttick = 0;
228
229
230
231         /* get time of day in milliseconds, offset by tick count (see our
232            gettimeofday() implementation) */
233         time(&t);
234         startuptime = ((t % 86400) * 1000) - GetTickCount();
235
236         f = stdout;
237         _dup2(fileno(stdout),fileno(stderr));
238
239         /* start up the windoze-socket layer stuff */
240         if (WSAStartup(0x0101,&foop)) {
241                 fprintf(stderr,"Fatal error: Falied to startup windows sockets\n");
242                 return -1;
243         }
244
245
246         /* setup the format for opening audio channels */
247         wf.wFormatTag = WAVE_FORMAT_PCM;
248         wf.nChannels = 1;
249         wf.nSamplesPerSec = 8000;
250         wf.nAvgBytesPerSec = 16000;
251         wf.nBlockAlign = 2;
252         wf.wBitsPerSample = 16;
253         wf.cbSize = 0;
254         /* open the audio out channel */
255         if (waveOutOpen(&wout,0,&wf,0,0,CALLBACK_NULL) != MMSYSERR_NOERROR)
256                 {
257                         fprintf(stderr,"Fatal Error: Failed to open wave output device\n");
258                         return -1;
259                 }
260         /* open the audio in channel */
261         if (waveInOpen(&win,0,&wf,0,0,CALLBACK_NULL) != MMSYSERR_NOERROR)
262                 {
263                         fprintf(stderr,"Fatal Error: Failed to open wave input device\n");
264                         waveOutReset(wout);
265                         waveOutClose(wout);
266                         return -1;
267                 }
268         /* activate the exit handler */
269         atexit(killem);
270         /* initialize the audio in buffer structures */
271         memset(&whin,0,sizeof(whin));
272
273         if ( (port = iax_init(0) < 0)) {
274                 fprintf(stderr, "Fatal error: failed to initialize iax with port %d\n", port);
275                 return -1;
276         }
277
278
279         iax_set_formats(AST_FORMAT_GSM);
280         netfd = iax_get_fd();
281
282         fprintf(f, "Text Based Telephony Client.\n\n");
283         issue_prompt(f);
284
285         /* main tight loop */
286         while(1) {
287                 /* service the network stuff */
288                 service_network(netfd,f);
289                 if (outqueue) /* if stuff in audio output queue, free it up if its available */
290                 {
291                         /* go through audio output queue */
292                         for(wh = outqueue,wh1 = wh2 = NULL,i = 0; wh != NULL; wh = wh->next)
293                         {
294                                 service_network(netfd,f); /* service network here for better performance */
295                                 /* if last one was removed from queue, zot it here */
296                                 if (i && wh1)
297                                 { 
298                                         free(wh1);
299                                         wh1 = wh2;
300                                 }
301                                 i = 0; /* reset "last one removed" flag */
302                                 if (wh->w.dwFlags & WHDR_DONE) /* if this one is done */
303                                 {
304                                         /* prepare audio header */
305                                         if ((c = waveOutUnprepareHeader(wout,&wh->w,sizeof(WAVEHDR))) != MMSYSERR_NOERROR)
306                                         { 
307                                                 fprintf(stderr,"Cannot unprepare audio out header, error %d\n",c);
308                                                 exit(255);
309                                         }
310                                         if (wh1 != NULL) /* if there was a last one */
311                                         {
312                                                 wh1->next = wh->next;
313                                         } 
314                                         if (outqueue == wh) /* is first one, so set outqueue to next one */
315                                         {
316                                                 outqueue = wh->next;
317                                         }
318                                         i = 1; /* set 'to free' flag */
319                                 }
320                                 wh2 = wh1;      /* save old,old wh pointer */
321                                 wh1 = wh; /* save the old wh pointer */
322                         }
323                 }
324                 /* go through all audio in buffers, and prepare and queue ones that are currently idle */
325                 for(i = 0; i < NWHIN; i++)
326                 {
327                         service_network(netfd,f); /* service network stuff here for better performance */
328                         if (!(whin[i].dwFlags & WHDR_PREPARED)) /* if not prepared, do so */
329                         {
330                                 /* setup this input buffer header */
331                                 memset(&whin[i],0,sizeof(WAVEHDR));
332                                 whin[i].lpData = bufin[i];
333                                 whin[i].dwBufferLength = 320;
334                                 whin[i].dwUser = whinserial++; /* set 'user data' to current serial number */
335                                 /* prepare the buffer */
336                                 if (waveInPrepareHeader(win,&whin[i],sizeof(WAVEHDR)))
337                                 {
338                                         fprintf(stderr,"Unable to prepare header for input\n");
339                                         return -1;
340                                 }
341                                 /* add it to device (queue) */
342                                 if (waveInAddBuffer(win,&whin[i],sizeof(WAVEHDR)))
343                                 {
344                                         fprintf(stderr,"Unable to prepare header for input\n");
345                                         return -1;
346                                 }
347                         }
348                         waveInStart(win); /* start it (if not already started) */
349                 }
350                 
351                 /* if key pressed, do command stuff */
352                 if(_kbhit())
353                 {
354                                 if ( ( fgets(&*rcmd, 256, stdin))) {
355                                         rcmd[strlen(rcmd)-1] = 0;
356                                         parse_args(f, &*rcmd);
357                                 } else fprintf(f, "Fatal error: failed to read data!\n");
358
359                                 issue_prompt(f);
360                 }
361                 /* do audio input stuff for buffers that have received data from audio in device already. Must
362                         do them in serial number order (the order in which they were originally queued). */
363                 if(answered_call) /* send audio only if call answered */
364                 {
365                         for(;;) /* loop until all are found */
366                         {
367                                 for(i = 0; i < NWHIN; i++) /* find an available one that's the one we are looking for */
368                                 {
369                                         service_network(netfd,f); /* service network here for better performance */
370                                         /* if not time to send any more, dont */
371                                         if (GetTickCount() < (lastouttick + OUT_INTERVAL))
372                                         {
373                                                 i = NWHIN; /* set to value that WILL exit loop */
374                                                 break;
375                                         }
376                                         if ((whin[i].dwUser == nextwhin) && (whin[i].dwFlags & WHDR_DONE)) { /* if audio is ready */
377
378                                                 /* must have read exactly 320 bytes */
379                                                 if (whin[i].dwBytesRecorded != whin[i].dwBufferLength)
380                                                 {
381                                                         fprintf(stderr,"Short audio read, got %d bytes, expected %d bytes\n", whin[i].dwBytesRecorded,
382                                                                 whin[i].dwBufferLength);
383                                                         return -1;
384                                                 }
385                                                 if(!most_recent_answer->gsmout)
386                                                                 most_recent_answer->gsmout = gsm_create();
387
388                                                 service_network(netfd,f); /* service network here for better performance */
389                                                 /* encode the audio from the buffer into GSM format */
390                                                 gsm_encode(most_recent_answer->gsmout, (short *) ((char *) whin[i].lpData), fo);
391                                                 if(iax_send_voice(most_recent_answer->session,
392                                                         AST_FORMAT_GSM, (char *)fo, sizeof(gsm_frame)) == -1)
393                                                                         puts("Failed to send voice!"); 
394                                                 lastouttick = GetTickCount(); /* save time of last output */
395
396                                                 /* unprepare (free) the header */
397                                                 waveInUnprepareHeader(win,&whin[i],sizeof(WAVEHDR));
398                                                 /* initialize the buffer */
399                                                 memset(&whin[i],0,sizeof(WAVEHDR));
400                                                 /* bump the serial number to look for the next time */
401                                                 nextwhin++;
402                                                 /* exit the loop so that we can start at lowest buffer again */
403                                                 break;
404                                         }
405                                 } 
406                                 if (i >= NWHIN) break; /* if all found, get out of loop */
407                         }
408                 }
409
410         }
411         return 0;
412 }
413
414 void
415 do_iax_event(FILE *f) {
416         int sessions = 0;
417         struct iax_event *e = 0;
418         struct peer *peer;
419
420         while ( (e = iax_get_event(0))) {
421                 peer = find_peer(e->session);
422                 if(peer) {
423                         handle_event(f, e, peer);
424                 } else {
425                         if(e->etype != IAX_EVENT_CONNECT) {
426                                 fprintf(stderr, "Huh? This is an event for a non-existant session?\n");
427                         }
428                         sessions++;
429
430                         if(sessions >= MAX_SESSIONS) {
431                                 fprintf(f, "Missed a call... too many sessions open.\n");
432                         }
433
434
435                         if(e->event.connect.callerid && e->event.connect.dnid)
436                                 fprintf(f, "Call from '%s' for '%s'", e->event.connect.callerid, 
437                                 e->event.connect.dnid);
438                         else if(e->event.connect.dnid) {
439                                 fprintf(f, "Call from '%s'", e->event.connect.dnid);
440                         } else if(e->event.connect.callerid) {
441                                 fprintf(f, "Call from '%s'", e->event.connect.callerid);
442                         } else printf("Call from");
443                         fprintf(f, " (%s)\n", inet_ntoa(iax_get_peer_addr(e->session).sin_addr));
444
445                         if(most_recent_answer) {
446                                 fprintf(f, "Incoming call ignored, there's already a call waiting for answer... \
447 please accept or reject first\n");
448                                 iax_reject(e->session, "Too many calls, we're busy!");
449                         } else {
450                                 if ( !(peer = malloc(sizeof(struct peer)))) {
451                                         fprintf(f, "Warning: Unable to allocate memory!\n");
452                                         return;
453                                 }
454
455                                 peer->time = time(0);
456                                 peer->session = e->session;
457                                 peer->gsmin = 0;
458                                 peer->gsmout = 0;
459
460                                 peer->next = peers;
461                                 peers = peer;
462
463                                 iax_accept(peer->session);
464                                 iax_ring_announce(peer->session);
465                                 most_recent_answer = peer;
466                                 fprintf(f, "Incoming call!\n");
467                         }
468                         iax_event_free(e);
469                         issue_prompt(f);
470                 }
471         }
472 }
473
474 void
475 call(FILE *f, char *num)
476 {
477         struct peer *peer;
478
479         if(!newcall)
480                 newcall = iax_session_new();
481         else {
482                 fprintf(f, "Already attempting to call somewhere, please cancel first!\n");
483                 return;
484         }
485
486         if ( !(peer = malloc(sizeof(struct peer)))) {
487                 fprintf(f, "Warning: Unable to allocate memory!\n");
488                 return;
489         }
490
491         peer->time = time(0);
492         peer->session = newcall;
493         peer->gsmin = 0;
494         peer->gsmout = 0;
495
496         peer->next = peers;
497         peers = peer;
498
499         most_recent_answer = peer;
500
501         iax_call(peer->session, num, 10);
502 }
503
504 void
505 answer_call(void)
506 {
507         if(most_recent_answer)
508                 iax_answer(most_recent_answer->session);
509         printf("Answering call!\n");
510         answered_call = 1;
511 }
512
513 void
514 dump_call(void)
515 {
516         if(most_recent_answer)
517         {
518                 iax_hangup(most_recent_answer->session,"");
519                 free(most_recent_answer);
520         }
521         printf("Dumping call!\n");
522         answered_call = 0;
523         most_recent_answer = 0;
524         answered_call = 0;
525         peers = 0;
526         newcall = 0;
527 }
528
529 void
530 reject_call(void)
531 {
532         iax_reject(most_recent_answer->session, "Call rejected manually.");
533         most_recent_answer = 0;
534 }
535
536 void
537 handle_event(FILE *f, struct iax_event *e, struct peer *p)
538 {
539         int len,n;
540         WHOUT *wh,*wh1;
541         short fr[160];
542         static paused_xmit = 0;
543
544
545         switch(e->etype) {
546                 case IAX_EVENT_HANGUP:
547                         iax_hangup(most_recent_answer->session, "Byeee!");
548                         fprintf(f, "Call disconnected by peer\n");
549                         free(most_recent_answer);
550                         most_recent_answer = 0;
551                         answered_call = 0;
552                         peers = 0;
553                         newcall = 0;
554                         
555                         break;
556
557                 case IAX_EVENT_REJECT:
558                         fprintf(f, "Authentication was rejected\n");
559                         break;
560                 case IAX_EVENT_ACCEPT:
561                         fprintf(f, "Waiting for answer... RING RING\n");
562                         issue_prompt(f);
563                         break;
564                 case IAX_EVENT_ANSWER:
565                         answer_call();
566                         break;
567                 case IAX_EVENT_VOICE:
568                         switch(e->event.voice.format) {
569                                 case AST_FORMAT_GSM:
570                                         if(e->event.voice.datalen % 33) {
571                                                 fprintf(stderr, "Weird gsm frame, not a multiple of 33.\n");
572                                                 break;
573                                         }
574
575                                         if (!p->gsmin)
576                                                 p->gsmin = gsm_create();
577
578                                         len = 0;
579                                         while(len < e->event.voice.datalen) {
580                                                 if(gsm_decode(p->gsmin, (char *) e->event.voice.data + len, fr)) {
581                                                         fprintf(stderr, "Bad GSM data\n");
582                                                         break;
583                                                 } else {  /* its an audio packet to be output to user */
584
585                                                         /* get count of pending items in audio output queue */
586                                                         n = 0; 
587                                                         if (outqueue) 
588                                                         {       /* determine number of pending out queue items */
589                                                                 for(wh = outqueue; wh != NULL; wh = wh->next)
590                                                                 {
591                                                                         if (!(wh->w.dwFlags & WHDR_DONE)) n++;
592                                                                 }
593                                                         }
594                                                         /* if not too many, send to user, otherwise chuck packet */
595                                                         if (n <= OUT_DEPTH) /* if not to chuck packet */
596                                                         {
597                                                                 /* malloc the memory for the queue item */
598                                                                 wh = (WHOUT *) malloc(sizeof(WHOUT));
599                                                                 if (wh == (WHOUT *) NULL) /* if error, bail */
600                                                                 {
601                                                                         fprintf(stderr,"Outa memory!!!!\n");
602                                                                         exit(255);
603                                                                 }
604                                                                 /* initialize the queue entry */
605                                                                 memset(wh,0,sizeof(WHOUT));
606                                                                 /* copy the PCM data from the gsm conversion buffer */
607                                                                 memcpy((char *)wh->data,(char *)fr,sizeof(fr));
608                                                                 /* set parameters for data */
609                                                                 wh->w.lpData = (char *) wh->data;
610                                                                 wh->w.dwBufferLength = 320;
611                                                                 
612                                                                 /* prepare buffer for output */
613                                                                 if (waveOutPrepareHeader(wout,&wh->w,sizeof(WAVEHDR)))
614                                                                 {
615                                                                         fprintf(stderr,"Cannot prepare header for audio out\n");
616                                                                         exit(255);
617                                                                 }
618                                                                 /* if not currently transmitting, hold off a couple of packets for 
619                                                                         smooth sounding output */
620                                                                 if ((!n) && (!paused_xmit))
621                                                                 {
622                                                                         /* pause output (before starting) */
623                                                                         waveOutPause(wout);
624                                                                         /* indicate as such */
625                                                                         paused_xmit = 1;
626                                                                 }
627                                                                 /* queue packet for output on audio device */
628                                                                 if (waveOutWrite(wout,&wh->w,sizeof(WAVEHDR)))
629                                                                 {
630                                                                         fprintf(stderr,"Cannot output to wave output device\n");
631                                                                         exit(255);
632                                                                 }
633                                                                 /* if we are paused, and we have enough packets, start audio */
634                                                                 if ((n > OUT_PAUSE_THRESHOLD) && paused_xmit)
635                                                                 {
636                                                                         /* start the output */
637                                                                         waveOutRestart(wout);
638                                                                         /* indicate as such */
639                                                                         paused_xmit = 0;
640                                                                 }
641                                                                 /* insert it onto tail of outqueue */
642                                                                 if (outqueue == NULL) /* if empty queue */
643                                                                         outqueue = wh; /* point queue to new entry */
644                                                                 else /* otherwise is non-empty queue */
645                                                                 {
646                                                                         wh1 = outqueue;
647                                                                         while(wh1->next) wh1 = wh1->next; /* find last entry in queue */
648                                                                         wh1->next = wh; /* point it to new entry */
649                                                                 }
650                                                         } 
651 #ifdef  PRINTCHUCK
652                                                         else printf("Chucking packet!!\n");
653 #endif
654                                                 }
655                                                 len += 33;
656                                         }
657                                         break;
658                                 default :
659                                         fprintf(f, "Don't know how to handle that format %d\n", e->event.voice.format);
660                         }
661                         break;
662                 case IAX_EVENT_RINGA:
663                         break;
664                 default:
665                         fprintf(f, "Unknown event: %d\n", e->etype);
666                         break;
667         }
668 }
669
670 void
671 parse_cmd(FILE *f, int argc, char **argv)
672 {
673         _strupr(argv[0]);
674         if(!strcmp(argv[0], "HELP")) {
675                 if(argc == 1)
676                         dump_array(f, help);
677                 else if(argc == 2) {
678                         if(!strcmp(argv[1], "HELP"))
679                                 fprintf(f, "Help <Command>\t-\tDisplays general help or specific help on command if supplied an arguement\n");
680                         else if(!strcmp(argv[1], "QUIT"))
681                                 fprintf(f, "Quit\t\t-\tShuts down the miniphone\n");
682                         else fprintf(f, "No help available on %s\n", argv[1]);
683                 } else {
684                         fprintf(f, "Too many arguements for command help.\n");
685                 }
686         } else if(!strcmp(argv[0], "STATUS")) {
687                 if(argc == 1) {
688                         int c = 0;
689                         struct peer *peerptr = peers;
690
691                         if(!peerptr)
692                                 fprintf(f, "No session matches found.\n");
693                         else while(peerptr) {
694                                 fprintf(f, "Listing sessions:\n\n");
695                                 fprintf(f, "Session %d\n", ++c);
696                                 fprintf(f, "Session existed for %d seconds\n", (int)time(0)-peerptr->time);
697                                 if(answered_call)
698                                         fprintf(f, "Call answered.\n");
699                                 else fprintf(f, "Call ringing.\n");
700
701                                 peerptr = peerptr->next;
702                         }
703                 } else fprintf(f, "Too many arguments for command status.\n");
704         } else if(!strcmp(argv[0], "ANSWER")) {
705                 if(argc > 1)
706                         fprintf(f, "Too many arguements for command answer\n");
707                 else answer_call();
708         } else if(!strcmp(argv[0], "REJECT")) {
709                 if(argc > 1)
710                         fprintf(f, "Too many arguements for command reject\n");
711                 else {
712                         fprintf(f, "Rejecting current phone call.\n");
713                         reject_call();
714                 }
715         } else if(!strcmp(argv[0], "CALL")) {
716                 if(argc > 2)
717                         fprintf(f, "Too many arguements for command call\n");
718                 else {
719                         call(f, argv[1]);
720                 }
721         } else if(!strcmp(argv[0], "DUMP")) {
722                 if(argc > 1)
723                         fprintf(f, "Too many arguements for command dump\n");
724                 else {
725                         dump_call();
726                 }
727         } else if(!strcmp(argv[0], "DTMF")) {
728                 if(argc > 2)
729                 {
730                         fprintf(f, "Too many arguements for command dtmf\n");
731                         return;
732                 }
733                 if (argc < 1)
734                 {
735                         fprintf(f, "Too many arguements for command dtmf\n");
736                         return;
737                 }
738                 if(most_recent_answer)
739                                 iax_send_dtmf(most_recent_answer->session,*argv[1]);
740         } else if(!strcmp(argv[0], "QUIT")) {
741                 if(argc > 1)
742                         fprintf(f, "Too many arguements for command quit\n");
743                 else {
744                         fprintf(f, "Good bye!\n");
745                         exit(1);
746                 }
747         } else fprintf(f, "Unknown command of %s\n", argv[0]);
748 }
749
750 void
751 issue_prompt(FILE *f)
752 {
753         fprintf(f, "TeleClient> ");
754         fflush(f);
755 }
756
757 void
758 dump_array(FILE *f, char **array) {
759         while(*array)
760                 fprintf(f, "%s\n", *array++);
761 }