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!! */
killem(void)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. */
gettimeofday(struct timeval * tv,struct timezone * tz)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 
find_peer(struct iax_session * session)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
parse_args(FILE * f,unsigned char * cmd)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 */
service_network(int netfd,FILE * f)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
main(int argc,char * argv[])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
do_iax_event(FILE * f)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
call(FILE * f,char * num)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
answer_call(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
dump_call(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
reject_call(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
handle_event(FILE * f,struct iax_event * e,struct peer * p)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
parse_cmd(FILE * f,int argc,char ** argv)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
issue_prompt(FILE * f)751 issue_prompt(FILE *f)
752 {
753 	fprintf(f, "TeleClient> ");
754 	fflush(f);
755 }
756 
757 void
dump_array(FILE * f,char ** array)758 dump_array(FILE *f, char **array) {
759 	while(*array)
760 		fprintf(f, "%s\n", *array++);
761 }
762