More new memory wrapper work.
[asterisk/asterisk.git] / apps / app_rpt.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2002-2005, Jim Dixon, WB6NIL
5  *
6  * Jim Dixon, WB6NIL <jim@lambdatel.com>
7  * Serious contributions by Steve RoDgers, WA6ZFT <hwstar@rodgers.sdcoxmail.com>
8  *
9  * See http://www.asterisk.org for more information about
10  * the Asterisk project. Please do not directly contact
11  * any of the maintainers of this project for assistance;
12  * the project provides a web site, mailing lists and IRC
13  * channels for your use.
14  *
15  * This program is free software, distributed under the terms of
16  * the GNU General Public License Version 2. See the LICENSE file
17  * at the top of the source tree.
18  */
19
20 /*! \file
21  *
22  * \brief Radio Repeater / Remote Base program 
23  *  version 0.39 12/19/05
24  *
25  * \author Jim Dixon, WB6NIL <jim@lambdatel.com>
26  *
27  * \note Serious contributions by Steve RoDgers, WA6ZFT <hwstar@rodgers.sdcoxmail.com>
28  * 
29  * See http://www.zapatatelephony.org/app_rpt.html
30  *
31  *
32  * Repeater / Remote Functions:
33  * "Simple" Mode:  * - autopatch access, # - autopatch hangup
34  * Normal mode:
35  * See the function list in rpt.conf
36  *
37  *  To send an asterisk (*) while dialing or talking on phone,
38  *  use the autopatch acess code.
39  *
40  *
41  * status cmds:
42  *
43  *  1 - Force ID
44  *  2 - Give Time of Day
45  *  3 - Give software Version
46  *
47  * cop (control operator) cmds:
48  *
49  *  1 - System warm boot
50  *  2 - System enable
51  *  3 - System disable
52  *  4 - Test Tone On
53  *  5 - Dump System Variables on Console (debug)
54  *  6 - PTT (phone mode only)
55  *
56  * ilink cmds:
57  *
58  *  1 - Disconnect specified link
59  *  2 - Connect specified link -- monitor only
60  *  3 - Connect specified link -- tranceive
61  *  4 - Enter command mode on specified link
62  *  5 - System status
63  *  6 - Disconnect all links
64  *
65  * remote cmds:
66  *
67  *  1 - Recall Memory MM  (*000-*099) (Gets memory from rpt.conf)
68  *  2 - Set VFO MMMMM*KKK*O   (Mhz digits, Khz digits, Offset)
69  *  3 - Set Rx PL Tone HHH*D*
70  *  4 - Set Tx PL Tone HHH*D* (Not currently implemented with DHE RBI-1)
71  *  5 - Link Status (long)
72  *  6 - Set operating mode M (FM, USB, LSB, AM, etc)
73  *  100 - RX PL off (Default)
74  *  101 - RX PL On
75  *  102 - TX PL Off (Default)
76  *  103 - TX PL On
77  *  104 - Low Power
78  *  105 - Med Power
79  *  106 - Hi Power
80  *  107 - Bump Down 20 Hz
81  *  108 - Bump Down 100 Hz
82  *  109 - Bump Down 500 Hz
83  *  110 - Bump Up 20 Hz
84  *  111 - Bump Up 100 Hz
85  *  112 - Bump Up 500 Hz
86  *  113 - Scan Down Slow
87  *  114 - Scan Down Medium
88  *  115 - Scan Down Fast
89  *  116 - Scan Up Slow
90  *  117 - Scan Up Medium
91  *  118 - Scan Up Fast
92  *  119 - Transmit allowing auto-tune
93  *  140 - Link Status (brief)
94  *
95  *
96 */
97
98 /* The following is JUST GROSS!! There is some soft of underlying problem,
99    probably in channel_iax2.c, that causes an IAX2 connection to sometimes
100    stop transmitting randomly. We have been working for weeks to try to
101    locate it and fix it, but to no avail We finally decided to put our
102    tail between our legs, and just make the radio system re-connect upon
103    network failure. This just shouldnt have to be done. For normal operation,
104    comment-out the following line */
105 #define RECONNECT_KLUDGE 
106
107 /* maximum digits in DTMF buffer, and seconds after * for DTMF command timeout */
108
109 #define MAXDTMF 32
110 #define DTMF_TIMEOUT 3
111
112 #define DISC_TIME 10000  /* report disc after 10 seconds of no connect */
113 #define MAX_RETRIES 5
114
115 #define REDUNDANT_TX_TIME 2000
116
117 #define RETRY_TIMER_MS 5000
118
119 #define MAXREMSTR 15
120
121 #define DELIMCHR ','
122 #define QUOTECHR 34
123
124 #define NODES "nodes"
125 #define MEMORY "memory"
126 #define FUNCTIONS "functions"
127 #define TELEMETRY "telemetry"
128 #define MORSE "morse"
129 #define FUNCCHAR '*'
130 #define ENDCHAR '#'
131
132 #define DEFAULT_IOBASE 0x378
133
134 #define MAXCONNECTTIME 5000
135
136 #define MAXNODESTR 300
137
138 #define ACTIONSIZE 32
139
140 #define TELEPARAMSIZE 256
141
142 #define REM_SCANTIME 100
143
144
145 enum {REM_OFF,REM_MONITOR,REM_TX};
146
147 enum{ID,PROC,TERM,COMPLETE,UNKEY,REMDISC,REMALREADY,REMNOTFOUND,REMGO,
148         CONNECTED,CONNFAIL,STATUS,TIMEOUT,ID1, STATS_TIME,
149         STATS_VERSION, IDTALKOVER, ARB_ALPHA, TEST_TONE, REV_PATCH,
150         TAILMSG};
151
152 enum {REM_SIMPLEX,REM_MINUS,REM_PLUS};
153
154 enum {REM_LOWPWR,REM_MEDPWR,REM_HIPWR};
155
156 enum {DC_INDETERMINATE, DC_REQ_FLUSH, DC_ERROR, DC_COMPLETE, DC_DOKEY};
157
158 enum {SOURCE_RPT, SOURCE_LNK, SOURCE_RMT, SOURCE_PHONE, SOURCE_DPHONE};
159
160 enum {DLY_TELEM, DLY_ID, DLY_UNKEY, DLY_CALLTERM};
161
162 enum {REM_MODE_FM,REM_MODE_USB,REM_MODE_LSB,REM_MODE_AM};
163
164 enum {HF_SCAN_OFF,HF_SCAN_DOWN_SLOW,HF_SCAN_DOWN_QUICK,
165       HF_SCAN_DOWN_FAST,HF_SCAN_UP_SLOW,HF_SCAN_UP_QUICK,HF_SCAN_UP_FAST};
166
167 #include "asterisk.h"
168
169 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
170
171 #include <signal.h>
172 #include <stdio.h>
173 #include <unistd.h>
174 #include <string.h>
175 #include <stdlib.h>
176 #include <search.h>
177 #include <sys/types.h>
178 #include <sys/stat.h>
179 #include <errno.h>
180 #include <dirent.h>
181 #include <ctype.h>
182 #include <sys/stat.h>
183 #include <sys/time.h>
184 #include <sys/file.h>
185 #include <sys/ioctl.h>
186 #include <sys/io.h>
187 #include <math.h>
188 #include <tonezone.h>
189 #include <linux/zaptel.h>
190 #include <netinet/in.h>
191 #include <arpa/inet.h>
192
193 #include "asterisk/utils.h"
194 #include "asterisk/lock.h"
195 #include "asterisk/file.h"
196 #include "asterisk/logger.h"
197 #include "asterisk/channel.h"
198 #include "asterisk/callerid.h"
199 #include "asterisk/pbx.h"
200 #include "asterisk/module.h"
201 #include "asterisk/translate.h"
202 #include "asterisk/features.h"
203 #include "asterisk/options.h"
204 #include "asterisk/cli.h"
205 #include "asterisk/config.h"
206 #include "asterisk/say.h"
207 #include "asterisk/localtime.h"
208
209 static  char *tdesc = "Radio Repeater / Remote Base  version 0.39  12/19/2005";
210
211 static char *app = "Rpt";
212
213 static char *synopsis = "Radio Repeater/Remote Base Control System";
214
215 static char *descrip = 
216 "  Rpt(nodename[|options]):  Radio Remote Link or Remote Base Link Endpoint Process.\n"
217 "\n"
218 "    Not specifying an option puts it in normal endpoint mode (where source\n"
219 "    IP and nodename are verified).\n"
220 "\n"
221 "    Options are as follows:\n"
222 "\n"
223 "        X - Normal endpoint mode WITHOUT security check. Only specify\n"
224 "            this if you have checked security already (like with an IAX2\n"
225 "            user/password or something).\n"
226 "\n"
227 "        Rannounce-string[|timeout[|timeout-destination]] - Amateur Radio\n"
228 "            Reverse Autopatch. Caller is put on hold, and announcement (as\n"
229 "            specified by the 'announce-string') is played on radio system.\n"
230 "            Users of radio system can access autopatch, dial specified\n"
231 "            code, and pick up call. Announce-string is list of names of\n"
232 "            recordings, or \"PARKED\" to substitute code for un-parking,\n"
233 "            or \"NODE\" to substitute node number.\n"
234 "\n"
235 "        P - Phone Control mode. This allows a regular phone user to have\n"
236 "            full control and audio access to the radio system. For the\n"
237 "            user to have DTMF control, the 'phone_functions' parameter\n"
238 "            must be specified for the node in 'rpt.conf'. An additional\n"
239 "            function (cop,6) must be listed so that PTT control is available.\n"
240 "\n"
241 "        D - Dumb Phone Control mode. This allows a regular phone user to\n"
242 "            have full control and audio access to the radio system. In this\n"
243 "            mode, the PTT is activated for the entire length of the call.\n"
244 "            For the user to have DTMF control (not generally recomended in\n"
245 "            this mode), the 'dphone_functions' parameter must be specified\n"
246 "            for the node in 'rpt.conf'. Otherwise no DTMF control will be\n"
247 "            available to the phone user.\n"
248 "\n";
249
250 static int debug = 0;  /* Set this >0 for extra debug output */
251 static int nrpts = 0;
252
253 char *discstr = "!!DISCONNECT!!";
254 static char *remote_rig_ft897="ft897";
255 static char *remote_rig_rbi="rbi";
256
257 struct  ast_config *cfg;
258
259 STANDARD_LOCAL_USER;
260 LOCAL_USER_DECL;
261
262 #define MSWAIT 200
263 #define HANGTIME 5000
264 #define TOTIME 180000
265 #define IDTIME 300000
266 #define MAXRPTS 20
267 #define POLITEID 30000
268 #define FUNCTDELAY 1500
269
270 static  pthread_t rpt_master_thread;
271
272 struct rpt;
273
274 struct rpt_link
275 {
276         struct rpt_link *next;
277         struct rpt_link *prev;
278         char    mode;                   /* 1 if in tx mode */
279         char    isremote;
280         char    phonemode;
281         char    name[MAXNODESTR];       /* identifier (routing) string */
282         char    lasttx;
283         char    lastrx;
284         char    connected;
285         char    hasconnected;
286         char    outbound;
287         char    disced;
288         char    killme;
289         long    elaptime;
290         long    disctime;
291         long    retrytimer;
292         long    retxtimer;
293         int     retries;
294         struct ast_channel *chan;       
295         struct ast_channel *pchan;      
296 } ;
297
298 struct rpt_tele
299 {
300         struct rpt_tele *next;
301         struct rpt_tele *prev;
302         struct rpt *rpt;
303         struct ast_channel *chan;
304         int     mode;
305         struct rpt_link mylink;
306         char param[TELEPARAMSIZE];
307         pthread_t threadid;
308 } ;
309
310 struct function_table_tag
311 {
312         char action[ACTIONSIZE];
313         int (*function)(struct rpt *myrpt, char *param, char *digitbuf, 
314                 int command_source, struct rpt_link *mylink);
315 } ;
316
317 /* Used to store the morse code patterns */
318
319 struct morse_bits
320 {                 
321         int len;
322         int ddcomb;
323 } ;
324
325 struct telem_defaults
326 {
327         char name[20];
328         char value[80];
329 } ;
330
331
332 static struct rpt
333 {
334         char *name;
335         ast_mutex_t lock;
336         char *rxchanname;
337         char *txchanname;
338         char *ourcontext;
339         char *ourcallerid;
340         char *acctcode;
341         char *ident;
342         char *tonezone;
343         char *functions;
344         char *link_functions;
345         char *phone_functions;
346         char *dphone_functions;
347         char *nodes;
348         struct rpt_link links;
349         int hangtime;
350         int totime;
351         int idtime;
352         int unkeytocttimer;
353         int duplex;
354         char keyed;
355         char exttx;
356         char localtx;
357         char remoterx;
358         char remotetx;
359         char remoteon;
360         char simple;
361         char *remote;
362         char tounkeyed;
363         char tonotify;
364         char enable;
365         char dtmfbuf[MAXDTMF];
366         char rem_dtmfbuf[MAXDTMF];
367         char cmdnode[50];
368         struct ast_channel *rxchannel,*txchannel;
369         struct ast_channel *pchannel,*txpchannel, *remchannel;
370         struct rpt_tele tele;
371         pthread_t rpt_call_thread,rpt_thread;
372         time_t rem_dtmf_time,dtmf_time_rem;
373         int tailtimer,totimer,idtimer,txconf,conf,callmode,cidx,scantimer,tmsgtimer;
374         int mustid;
375         int politeid;
376         int dtmfidx,rem_dtmfidx;
377         long    retxtimer;
378         char mydtmf;
379         int iobase;
380         char exten[AST_MAX_EXTENSION];
381         char freq[MAXREMSTR],rxpl[MAXREMSTR],txpl[MAXREMSTR];
382         char offset;
383         char powerlevel;
384         char txplon;
385         char rxplon;
386         char remmode;
387         char tunerequest;
388         char hfscanmode;
389         int hfscanstatus;
390         char lastlinknode[MAXNODESTR];
391         char funcchar;
392         char endchar;
393         char stopgen;
394         int phone_longestfunc;
395         int dphone_longestfunc;
396         int link_longestfunc;
397         int longestfunc;
398         int longestnode;
399         int threadrestarts;             
400         int tailmessagetime;
401         int tailsquashedtime;
402         char *tailmessages[500];
403         int tailmessagemax;
404         int tailmessagen;
405         time_t disgorgetime;
406         time_t lastthreadrestarttime;
407         char    nobusyout;
408 } rpt_vars[MAXRPTS];    
409
410 /*
411 * CLI extensions
412 */
413
414 /* Debug mode */
415 static int rpt_do_debug(int fd, int argc, char *argv[]);
416
417 static char debug_usage[] =
418 "Usage: rpt debug level {0-7}\n"
419 "       Enables debug messages in app_rpt\n";
420                                                                                                                                 
421 static struct ast_cli_entry  cli_debug =
422         { { "rpt", "debug", "level" }, rpt_do_debug, "Enable app_rpt debugging", debug_usage };
423
424
425
426 /*
427 * Telemetry defaults
428 */
429
430
431 static struct telem_defaults tele_defs[] = {
432         {"ct1","|t(350,0,100,3072)(500,0,100,3072)(660,0,100,3072)"},
433         {"ct2","|t(660,880,150,3072)"},
434         {"ct3","|t(440,0,150,3072)"},
435         {"ct4","|t(550,0,150,3072)"},
436         {"ct5","|t(660,0,150,3072)"},
437         {"ct6","|t(880,0,150,3072)"},
438         {"ct7","|t(660,440,150,3072)"},
439         {"ct8","|t(700,1100,150,3072)"},
440         {"remotemon","|t(1600,0,75,2048)"},
441         {"remotetx","|t(2000,0,75,2048)(0,0,75,0)(1600,0,75,2048)"},
442         {"cmdmode","|t(900,904,200,2048)"},
443         {"functcomplete","|t(1000,0,100,2048)(0,0,100,0)(1000,0,100,2048)"}
444 } ;
445
446 /*
447 * Forward decl's - these suppress compiler warnings when funcs coded further down the file than thier invokation
448 */
449
450 static int setrbi(struct rpt *myrpt);
451
452
453
454 /*
455 * Define function protos for function table here
456 */
457
458 static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
459 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
460 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
461 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
462 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
463 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
464 /*
465 * Function table
466 */
467
468 static struct function_table_tag function_table[] = {
469         {"cop", function_cop},
470         {"autopatchup", function_autopatchup},
471         {"autopatchdn", function_autopatchdn},
472         {"ilink", function_ilink},
473         {"status", function_status},
474         {"remote", function_remote}
475 } ;
476         
477 static int finddelim(char *str,char *strp[])
478 {
479 int     i,inquo;
480
481         inquo = 0;
482         i = 0;
483         strp[i++] = str;
484         if (!*str)
485            {
486                 strp[0] = 0;
487                 return(0);
488            }
489         for(; *str; str++)
490            {
491                 if (*str == QUOTECHR)
492                    {
493                         if (inquo)
494                            {
495                                 *str = 0;
496                                 inquo = 0;
497                            }
498                         else
499                            {
500                                 strp[i - 1] = str + 1;
501                                 inquo = 1;
502                            }
503                 }
504                 if ((*str == DELIMCHR) && (!inquo))
505                 {
506                         *str = 0;
507                         strp[i++] = str + 1;
508                 }
509            }
510         strp[i] = 0;
511         return(i);
512
513 }
514
515 static int myatoi(char *str)
516 {
517 int     ret;
518
519         if (str == NULL) return -1;
520         /* leave this %i alone, non-base-10 input is useful here */
521         if (sscanf(str,"%i",&ret) != 1) return -1;
522         return ret;
523 }
524
525 /*
526 * Enable or disable debug output at a given level at the console
527 */
528                                                                                                                                  
529 static int rpt_do_debug(int fd, int argc, char *argv[])
530 {
531         int newlevel;
532
533         if (argc != 4)
534                 return RESULT_SHOWUSAGE;
535         newlevel = myatoi(argv[3]);
536         if((newlevel < 0) || (newlevel > 7))
537                 return RESULT_SHOWUSAGE;
538         if(newlevel)
539                 ast_cli(fd, "app_rpt Debugging enabled, previous level: %d, new level: %d\n", debug, newlevel);
540         else
541                 ast_cli(fd, "app_rpt Debugging disabled\n");
542
543         debug = newlevel;                                                                                                                          
544         return RESULT_SUCCESS;
545 }
546                                                                                                                                  
547
548
549 static int play_tone_pair(struct ast_channel *chan, int f1, int f2, int duration, int amplitude)
550 {
551         int res;
552
553         if ((res = ast_tonepair_start(chan, f1, f2, duration, amplitude)))
554                 return res;
555                                                                                                                                             
556         while(chan->generatordata) {
557                 if (ast_safe_sleep(chan,1)) return -1;
558         }
559
560         return 0;
561 }
562
563 static int play_tone(struct ast_channel *chan, int freq, int duration, int amplitude)
564 {
565         return play_tone_pair(chan, freq, 0, duration, amplitude);
566 }
567
568 static int play_silence(struct ast_channel *chan, int duration)
569 {
570         return play_tone_pair(chan, 0, 0, duration, 0);
571 }
572
573
574 static int send_morse(struct ast_channel *chan, char *string, int speed, int freq, int amplitude)
575 {
576
577 static struct morse_bits mbits[] = {
578                 {0, 0}, /* SPACE */
579                 {0, 0}, 
580                 {6, 18},/* " */
581                 {0, 0},
582                 {7, 72},/* $ */
583                 {0, 0},
584                 {0, 0},
585                 {6, 30},/* ' */
586                 {5, 13},/* ( */
587                 {6, 29},/* ) */
588                 {0, 0},
589                 {5, 10},/* + */
590                 {6, 51},/* , */
591                 {6, 33},/* - */
592                 {6, 42},/* . */
593                 {5, 9}, /* / */
594                 {5, 31},/* 0 */
595                 {5, 30},/* 1 */
596                 {5, 28},/* 2 */
597                 {5, 24},/* 3 */
598                 {5, 16},/* 4 */
599                 {5, 0}, /* 5 */
600                 {5, 1}, /* 6 */
601                 {5, 3}, /* 7 */
602                 {5, 7}, /* 8 */
603                 {5, 15},/* 9 */
604                 {6, 7}, /* : */
605                 {6, 21},/* ; */
606                 {0, 0},
607                 {5, 33},/* = */
608                 {0, 0},
609                 {6, 12},/* ? */
610                 {0, 0},
611                 {2, 2}, /* A */
612                 {4, 1}, /* B */
613                 {4, 5}, /* C */
614                 {3, 1}, /* D */
615                 {1, 0}, /* E */
616                 {4, 4}, /* F */
617                 {3, 3}, /* G */
618                 {4, 0}, /* H */
619                 {2, 0}, /* I */
620                 {4, 14},/* J */
621                 {3, 5}, /* K */
622                 {4, 2}, /* L */
623                 {2, 3}, /* M */
624                 {2, 1}, /* N */
625                 {3, 7}, /* O */
626                 {4, 6}, /* P */
627                 {4, 11},/* Q */
628                 {3, 2}, /* R */
629                 {3, 0}, /* S */
630                 {1, 1}, /* T */
631                 {3, 4}, /* U */
632                 {4, 8}, /* V */
633                 {3, 6}, /* W */
634                 {4, 9}, /* X */
635                 {4, 13},/* Y */
636                 {4, 3}  /* Z */
637         };
638
639
640         int dottime;
641         int dashtime;
642         int intralettertime;
643         int interlettertime;
644         int interwordtime;
645         int len, ddcomb;
646         int res;
647         int c;
648         int i;
649         int flags;
650                         
651         res = 0;
652         
653         /* Approximate the dot time from the speed arg. */
654         
655         dottime = 900/speed;
656         
657         /* Establish timing releationships */
658         
659         dashtime = 3 * dottime;
660         intralettertime = dottime;
661         interlettertime = dottime * 4 ;
662         interwordtime = dottime * 7;
663         
664         for(;(*string) && (!res); string++){
665         
666                 c = *string;
667                 
668                 /* Convert lower case to upper case */
669                 
670                 if((c >= 'a') && (c <= 'z'))
671                         c -= 0x20;
672                 
673                 /* Can't deal with any char code greater than Z, skip it */
674                 
675                 if(c  > 'Z')
676                         continue;
677                 
678                 /* If space char, wait the inter word time */
679                                         
680                 if(c == ' '){
681                         if(!res)
682                                 res = play_silence(chan, interwordtime);
683                         continue;
684                 }
685                 
686                 /* Subtract out control char offset to match our table */
687                 
688                 c -= 0x20;
689                 
690                 /* Get the character data */
691                 
692                 len = mbits[c].len;
693                 ddcomb = mbits[c].ddcomb;
694                 
695                 /* Send the character */
696                 
697                 for(; len ; len--){
698                         if(!res)
699                                 res = play_tone(chan, freq, (ddcomb & 1) ? dashtime : dottime, amplitude);
700                         if(!res)
701                                 res = play_silence(chan, intralettertime);
702                         ddcomb >>= 1;
703                 }
704                 
705                 /* Wait the interletter time */
706                 
707                 if(!res)
708                         res = play_silence(chan, interlettertime - intralettertime);
709         }
710         
711         /* Wait for all the frames to be sent */
712         
713         if (!res) 
714                 res = ast_waitstream(chan, "");
715         ast_stopstream(chan);
716         
717         /*
718         * Wait for the zaptel driver to physically write the tone blocks to the hardware
719         */
720
721         for(i = 0; i < 20 ; i++){
722                 flags =  ZT_IOMUX_WRITEEMPTY | ZT_IOMUX_NOWAIT; 
723                 res = ioctl(chan->fds[0], ZT_IOMUX, &flags);
724                 if(flags & ZT_IOMUX_WRITEEMPTY)
725                         break;
726                 if( ast_safe_sleep(chan, 50)){
727                         res = -1;
728                         break;
729                 }
730         }
731
732         
733         return res;
734 }
735
736 static int send_tone_telemetry(struct ast_channel *chan, char *tonestring)
737 {
738         char *stringp;
739         char *tonesubset;
740         int f1,f2;
741         int duration;
742         int amplitude;
743         int res;
744         int i;
745         int flags;
746         
747         res = 0;
748         
749         stringp = ast_strdupa(tonestring);
750
751         for(;tonestring;){
752                 tonesubset = strsep(&stringp,")");
753                 if(!tonesubset)
754                         break;
755                 if(sscanf(tonesubset,"(%d,%d,%d,%d", &f1, &f2, &duration, &amplitude) != 4)
756                         break;
757                 res = play_tone_pair(chan, f1, f2, duration, amplitude);
758                 if(res)
759                         break;
760         }
761         if(!res)
762                 res = play_tone_pair(chan, 0, 0, 100, 0); /* This is needed to ensure the last tone segment is timed correctly */
763         
764         if (!res) 
765                 res = ast_waitstream(chan, "");
766         ast_stopstream(chan);
767
768         /*
769         * Wait for the zaptel driver to physically write the tone blocks to the hardware
770         */
771
772         for(i = 0; i < 20 ; i++){
773                 flags =  ZT_IOMUX_WRITEEMPTY | ZT_IOMUX_NOWAIT; 
774                 res = ioctl(chan->fds[0], ZT_IOMUX, &flags);
775                 if(flags & ZT_IOMUX_WRITEEMPTY)
776                         break;
777                 if( ast_safe_sleep(chan, 50)){
778                         res = -1;
779                         break;
780                 }
781         }
782                 
783         return res;
784                 
785 }
786         
787
788 static int sayfile(struct ast_channel *mychannel,char *fname)
789 {
790 int     res;
791
792         res = ast_streamfile(mychannel, fname, mychannel->language);
793         if (!res) 
794                 res = ast_waitstream(mychannel, "");
795         else
796                  ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
797         ast_stopstream(mychannel);
798         return res;
799 }
800
801 static int saycharstr(struct ast_channel *mychannel,char *str)
802 {
803 int     res;
804
805         res = ast_say_character_str(mychannel,str,NULL,mychannel->language);
806         if (!res) 
807                 res = ast_waitstream(mychannel, "");
808         else
809                  ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
810         ast_stopstream(mychannel);
811         return res;
812 }
813
814 static int saynum(struct ast_channel *mychannel, int num)
815 {
816         int res;
817         res = ast_say_number(mychannel, num, NULL, mychannel->language, NULL);
818         if(!res)
819                 res = ast_waitstream(mychannel, "");
820         else
821                 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
822         ast_stopstream(mychannel);
823         return res;
824 }
825
826
827 /* Retrieve an int from a config file */
828                                                                                 
829 static int retrieve_astcfgint(char *category, char *name, int min, int max, int defl)
830 {
831         char *var;
832         int ret;
833                                                                                 
834         var = ast_variable_retrieve(cfg, category, name);
835         if(var){
836                 ret = myatoi(var);
837                 if(ret < min)
838                         ret = min;
839                 if(ret > max)
840                         ret = max;
841         }
842         else
843                 ret = defl;
844         return ret;
845 }
846
847 static int telem_any(struct ast_channel *chan, char *entry)
848 {
849         int res;
850         char c;
851         
852         static int morsespeed;
853         static int morsefreq;
854         static int morseampl;
855         static int morseidfreq = 0;
856         static int morseidampl;
857         static char mcat[] = MORSE;
858         
859         res = 0;
860         
861         if(!morseidfreq){ /* Get the morse parameters if not already loaded */
862                 morsespeed = retrieve_astcfgint( mcat, "speed", 5, 20, 20);
863                 morsefreq = retrieve_astcfgint( mcat, "frequency", 300, 3000, 800);
864                 morseampl = retrieve_astcfgint( mcat, "amplitude", 200, 8192, 4096);
865                 morseidampl = retrieve_astcfgint( mcat, "idamplitude", 200, 8192, 2048);
866                 morseidfreq = retrieve_astcfgint( mcat, "idfrequency", 300, 3000, 330); 
867         }
868         
869         /* Is it a file, or a tone sequence? */
870                         
871         if(entry[0] == '|'){
872                 c = entry[1];
873                 if((c >= 'a')&&(c <= 'z'))
874                         c -= 0x20;
875         
876                 switch(c){
877                         case 'I': /* Morse ID */
878                                 res = send_morse(chan, entry + 2, morsespeed, morseidfreq, morseidampl);
879                                 break;
880                         
881                         case 'M': /* Morse Message */
882                                 res = send_morse(chan, entry + 2, morsespeed, morsefreq, morseampl);
883                                 break;
884                         
885                         case 'T': /* Tone sequence */
886                                 res = send_tone_telemetry(chan, entry + 2);
887                                 break;
888                         default:
889                                 res = -1;
890                 }
891         }
892         else
893                 res = sayfile(chan, entry); /* File */
894         return res;
895 }
896
897 /*
898 * This function looks up a telemetry name in the config file, and does a telemetry response as configured.
899 *
900 * 4 types of telemtry are handled: Morse ID, Morse Message, Tone Sequence, and a File containing a recording.
901 */
902
903 static int telem_lookup(struct ast_channel *chan, char *node, char *name)
904 {
905         
906         int res;
907         int i;
908         char *entry;
909         char *telemetry;
910         char *telemetry_save;
911
912         res = 0;
913         telemetry_save = NULL;
914         entry = NULL;
915         
916         
917         /* Retrieve the section name for telemetry from the node section */
918         
919         telemetry = ast_variable_retrieve(cfg, node, TELEMETRY);
920         if(telemetry){
921                 telemetry_save = ast_strdupa(telemetry);
922                 if(!telemetry_save){
923                         ast_log(LOG_WARNING,"ast_strdupa() failed in telem_lookup()\n");
924                         return res;
925                 }
926                 entry = ast_variable_retrieve(cfg, telemetry_save, name);
927         }
928         
929         /* Try to look up the telemetry name */
930         
931         if(!entry){
932                 /* Telemetry name wasn't found in the config file, use the default */
933                 for(i = 0; i < sizeof(tele_defs)/sizeof(struct telem_defaults) ; i++){
934                         if(!strcasecmp(tele_defs[i].name, name))
935                                 entry = tele_defs[i].value;
936                 }
937         }
938         if(entry)       
939                 telem_any(chan, entry);
940         else{
941                 ast_log(LOG_WARNING, "Telemetry name not found: %s\n", name);
942                 res = -1;
943         }
944         return res;
945 }
946
947 /*
948 * Retrieve a wait interval
949 */
950
951 static int get_wait_interval(struct rpt *myrpt, int type)
952 {
953         int interval;
954         char *wait_times;
955         char *wait_times_save;
956                                                                                                                   
957         wait_times_save = NULL;
958         wait_times = ast_variable_retrieve(cfg, myrpt->name, "wait_times");
959                                                                                                                   
960         if(wait_times){
961                 wait_times_save = ast_strdupa(wait_times);
962                 if(!wait_times_save){
963                         ast_log(LOG_WARNING, "Out of memory in wait_interval()\n");
964                         wait_times = NULL;
965                 }
966         }
967                                                                                                                   
968         switch(type){
969                 case DLY_TELEM:
970                         if(wait_times)
971                                 interval = retrieve_astcfgint(wait_times_save, "telemwait", 500, 5000, 1000);
972                         else
973                                 interval = 1000;
974                         break;
975                                                                                                                   
976                 case DLY_ID:
977                         if(wait_times)
978                                 interval = retrieve_astcfgint(wait_times_save, "idwait",250,5000,500);
979                         else
980                                 interval = 500;
981                         break;
982                                                                                                                   
983                 case DLY_UNKEY:
984                         if(wait_times)
985                                 interval = retrieve_astcfgint(wait_times_save, "unkeywait",500,5000,1000);
986                         else
987                                 interval = 1000;
988                         break;
989                                                                                                                   
990                 case DLY_CALLTERM:
991                         if(wait_times)
992                                 interval = retrieve_astcfgint(wait_times_save, "calltermwait",500,5000,1500);
993                         else
994                                 interval = 1500;
995                         break;
996                                                                                                                   
997                 default:
998                         return 0;
999         }
1000         return interval;
1001 }                                                                                                                  
1002
1003
1004 /*
1005 * Wait a configurable interval of time 
1006 */
1007
1008
1009 static void wait_interval(struct rpt *myrpt, int type, struct ast_channel *chan)
1010 {
1011         int interval;
1012         if((interval = get_wait_interval(myrpt, type)))
1013                 ast_safe_sleep(chan,interval);
1014         return;
1015 }
1016
1017
1018 static void *rpt_tele_thread(void *this)
1019 {
1020 ZT_CONFINFO ci;  /* conference info */
1021 int     res = 0,haslink,hastx,hasremote,imdone = 0, unkeys_queued, x;
1022 struct  rpt_tele *mytele = (struct rpt_tele *)this;
1023 struct  rpt_tele *tlist;
1024 struct  rpt *myrpt;
1025 struct  rpt_link *l,*m,linkbase;
1026 struct  ast_channel *mychannel;
1027 int vmajor, vminor;
1028 char *p,*ct,*ct_copy,*ident, *nodename;
1029 time_t t;
1030 struct tm localtm;
1031
1032
1033         /* get a pointer to myrpt */
1034         myrpt = mytele->rpt;
1035
1036         /* Snag copies of a few key myrpt variables */
1037         ast_mutex_lock(&myrpt->lock);
1038         nodename = ast_strdupa(myrpt->name);
1039         ident = ast_strdupa(myrpt->ident);
1040         ast_mutex_unlock(&myrpt->lock);
1041         
1042         
1043         /* allocate a pseudo-channel thru asterisk */
1044         mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
1045         if (!mychannel)
1046         {
1047                 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
1048                 ast_mutex_lock(&myrpt->lock);
1049                 remque((struct qelem *)mytele);
1050                 ast_mutex_unlock(&myrpt->lock);
1051                 free(mytele);           
1052                 pthread_exit(NULL);
1053         }
1054         ast_mutex_lock(&myrpt->lock);
1055         mytele->chan = mychannel; /* Save a copy of the channel so we can access it externally if need be */
1056         ast_mutex_unlock(&myrpt->lock);
1057         
1058         /* make a conference for the tx */
1059         ci.chan = 0;
1060         /* If there's an ID queued, only connect the ID audio to the local tx conference so 
1061                 linked systems can't hear it */
1062         ci.confno = (((mytele->mode == ID) || (mytele->mode == IDTALKOVER) || (mytele->mode == UNKEY) || 
1063                 (mytele->mode == TAILMSG)) ?
1064                         myrpt->txconf : myrpt->conf);
1065         ci.confmode = ZT_CONF_CONFANN;
1066         /* first put the channel on the conference in announce mode */
1067         if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
1068         {
1069                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
1070                 ast_mutex_lock(&myrpt->lock);
1071                 remque((struct qelem *)mytele);
1072                 ast_mutex_unlock(&myrpt->lock);
1073                 free(mytele);           
1074                 ast_hangup(mychannel);
1075                 pthread_exit(NULL);
1076         }
1077         ast_stopstream(mychannel);
1078         switch(mytele->mode)
1079         {
1080
1081             case ID:
1082             case ID1:
1083                 /* wait a bit */
1084                 wait_interval(myrpt, (mytele->mode == ID) ? DLY_ID : DLY_TELEM,mychannel);
1085                 res = telem_any(mychannel, ident); 
1086                 imdone=1;       
1087                 break;
1088                 
1089             case TAILMSG:
1090                 res = ast_streamfile(mychannel, myrpt->tailmessages[myrpt->tailmessagen], mychannel->language); 
1091                 break;
1092                 
1093             case IDTALKOVER:
1094                 p = ast_variable_retrieve(cfg, nodename, "idtalkover");
1095                 if(p)
1096                         res = telem_any(mychannel, p); 
1097                 imdone=1;       
1098                 break;
1099                         
1100             case PROC:
1101                 /* wait a little bit longer */
1102                 wait_interval(myrpt, DLY_TELEM, mychannel);
1103                 res = ast_streamfile(mychannel, "rpt/callproceeding", mychannel->language);
1104                 break;
1105             case TERM:
1106                 /* wait a little bit longer */
1107                 wait_interval(myrpt, DLY_CALLTERM, mychannel);
1108                 res = ast_streamfile(mychannel, "rpt/callterminated", mychannel->language);
1109                 break;
1110             case COMPLETE:
1111                 /* wait a little bit */
1112                 wait_interval(myrpt, DLY_TELEM, mychannel);
1113                 res = telem_lookup(mychannel, myrpt->name, "functcomplete");
1114                 break;
1115             case UNKEY:
1116
1117                 /*
1118                 * Reset the Unkey to CT timer
1119                 */
1120
1121                 x = get_wait_interval(myrpt, DLY_UNKEY);
1122                 ast_mutex_lock(&myrpt->lock);
1123                 myrpt->unkeytocttimer = x; /* Must be protected as it is changed below */
1124                 ast_mutex_unlock(&myrpt->lock);
1125
1126                 /*
1127                 * If there's one already queued, don't do another
1128                 */
1129
1130                 tlist = myrpt->tele.next;
1131                 unkeys_queued = 0;
1132                 if (tlist != &myrpt->tele)
1133                 {
1134                         ast_mutex_lock(&myrpt->lock);
1135                         while(tlist != &myrpt->tele){
1136                                 if (tlist->mode == UNKEY) unkeys_queued++;
1137                                 tlist = tlist->next;
1138                         }
1139                         ast_mutex_unlock(&myrpt->lock);
1140                 }
1141                 if( unkeys_queued > 1){
1142                         imdone = 1;
1143                         break;
1144                 }
1145
1146                 /* Wait for the telemetry timer to expire */
1147                 /* Periodically check the timer since it can be re-initialized above */
1148
1149                 while(myrpt->unkeytocttimer)
1150                 {
1151                         int ctint;
1152                         if(myrpt->unkeytocttimer > 100)
1153                                 ctint = 100;
1154                         else
1155                                 ctint = myrpt->unkeytocttimer;
1156                         ast_safe_sleep(mychannel, ctint);
1157                         ast_mutex_lock(&myrpt->lock);
1158                         if(myrpt->unkeytocttimer < ctint)
1159                                 myrpt->unkeytocttimer = 0;
1160                         else
1161                                 myrpt->unkeytocttimer -= ctint;
1162                         ast_mutex_unlock(&myrpt->lock);
1163                 }
1164         
1165
1166                 /*
1167                 * Now, the carrier on the rptr rx should be gone. 
1168                 * If it re-appeared, then forget about sending the CT
1169                 */
1170                 if(myrpt->keyed){
1171                         imdone = 1;
1172                         break;
1173                 }
1174                         
1175                 haslink = 0;
1176                 hastx = 0;
1177                 hasremote = 0;          
1178                 l = myrpt->links.next;
1179                 if (l != &myrpt->links)
1180                 {
1181                         ast_mutex_lock(&myrpt->lock);
1182                         while(l != &myrpt->links)
1183                         {
1184                                 if (l->name[0] == '0')
1185                                 {
1186                                         l = l->next;
1187                                         continue;
1188                                 }
1189                                 haslink = 1;
1190                                 if (l->mode) {
1191                                         hastx++;
1192                                         if (l->isremote) hasremote++;
1193                                 }
1194                                 l = l->next;
1195                         }
1196                         ast_mutex_unlock(&myrpt->lock);
1197                 }
1198                 if (haslink)
1199                 {
1200
1201                         res = telem_lookup(mychannel, myrpt->name, (!hastx) ? "remotemon" : "remotetx");
1202                         if(res)
1203                                 ast_log(LOG_WARNING, "telem_lookup:remotexx failed on %s\n", mychannel->name);
1204                         
1205                 
1206                         /* if in remote cmd mode, indicate it */
1207                         if (myrpt->cmdnode[0])
1208                         {
1209                                 ast_safe_sleep(mychannel,200);
1210                                 res = telem_lookup(mychannel, myrpt->name, "cmdmode");
1211                                 if(res)
1212                                         ast_log(LOG_WARNING, "telem_lookup:cmdmode failed on %s\n", mychannel->name);
1213                                 ast_stopstream(mychannel);
1214                         }
1215                 }
1216                 else if((ct = ast_variable_retrieve(cfg, nodename, "unlinkedct"))){ /* Unlinked Courtesy Tone */
1217                         ct_copy = ast_strdupa(ct);
1218                         res = telem_lookup(mychannel, myrpt->name, ct_copy);
1219                         if(res)
1220                                 ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);               
1221                 }       
1222                         
1223                 if (hasremote && (!myrpt->cmdnode[0]))
1224                 {
1225                         /* set for all to hear */
1226                         ci.chan = 0;
1227                         ci.confno = myrpt->conf;
1228                         ci.confmode = ZT_CONF_CONFANN;
1229                         /* first put the channel on the conference in announce mode */
1230                         if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
1231                         {
1232                                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
1233                                 ast_mutex_lock(&myrpt->lock);
1234                                 remque((struct qelem *)mytele);
1235                                 ast_mutex_unlock(&myrpt->lock);
1236                                 free(mytele);           
1237                                 ast_hangup(mychannel);
1238                                 pthread_exit(NULL);
1239                         }
1240                         if((ct = ast_variable_retrieve(cfg, nodename, "remotect"))){ /* Unlinked Courtesy Tone */
1241                                 ast_safe_sleep(mychannel,200);
1242                                 ct_copy = ast_strdupa(ct);
1243                                 res = telem_lookup(mychannel, myrpt->name, ct_copy);
1244                                 if(res)
1245                                         ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);               
1246                         }       
1247                 }
1248                 imdone = 1;
1249                 break;
1250             case REMDISC:
1251                 /* wait a little bit */
1252                 wait_interval(myrpt, DLY_TELEM, mychannel);
1253                 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
1254                 if (!res) 
1255                         res = ast_waitstream(mychannel, "");
1256                 else
1257                          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1258                 ast_stopstream(mychannel);
1259                 ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
1260                 res = ast_streamfile(mychannel, ((mytele->mylink.connected) ? 
1261                         "rpt/remote_disc" : "rpt/remote_busy"), mychannel->language);
1262                 break;
1263             case REMALREADY:
1264                 /* wait a little bit */
1265                 wait_interval(myrpt, DLY_TELEM, mychannel);
1266                 res = ast_streamfile(mychannel, "rpt/remote_already", mychannel->language);
1267                 break;
1268             case REMNOTFOUND:
1269                 /* wait a little bit */
1270                 wait_interval(myrpt, DLY_TELEM, mychannel);
1271                 res = ast_streamfile(mychannel, "rpt/remote_notfound", mychannel->language);
1272                 break;
1273             case REMGO:
1274                 /* wait a little bit */
1275                 wait_interval(myrpt, DLY_TELEM, mychannel);
1276                 res = ast_streamfile(mychannel, "rpt/remote_go", mychannel->language);
1277                 break;
1278             case CONNECTED:
1279                 /* wait a little bit */
1280                 wait_interval(myrpt, DLY_TELEM,  mychannel);
1281                 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
1282                 if (!res) 
1283                         res = ast_waitstream(mychannel, "");
1284                 else
1285                          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1286                 ast_stopstream(mychannel);
1287                 ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
1288                 res = ast_streamfile(mychannel, "rpt/connected", mychannel->language);
1289                 break;
1290             case CONNFAIL:
1291                 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
1292                 if (!res) 
1293                         res = ast_waitstream(mychannel, "");
1294                 else
1295                          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1296                 ast_stopstream(mychannel);
1297                 ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
1298                 res = ast_streamfile(mychannel, "rpt/connection_failed", mychannel->language);
1299                 break;
1300             case STATUS:
1301                 /* wait a little bit */
1302                 wait_interval(myrpt, DLY_TELEM, mychannel);
1303                 hastx = 0;
1304                 linkbase.next = &linkbase;
1305                 linkbase.prev = &linkbase;
1306                 ast_mutex_lock(&myrpt->lock);
1307                 /* make our own list of links */
1308                 l = myrpt->links.next;
1309                 while(l != &myrpt->links)
1310                 {
1311                         if (l->name[0] == '0')
1312                         {
1313                                 l = l->next;
1314                                 continue;
1315                         }
1316                         m = ast_malloc(sizeof(*m));
1317                         if (!m)
1318                         {
1319                                 ast_log(LOG_WARNING, "Cannot alloc memory on %s\n", mychannel->name);
1320                                 ast_mutex_lock(&myrpt->lock);
1321                                 remque((struct qelem *)mytele);
1322                                 ast_mutex_unlock(&myrpt->lock);
1323                                 free(mytele);           
1324                                 ast_hangup(mychannel);
1325                                 pthread_exit(NULL);
1326                         }
1327                         memcpy(m,l,sizeof(struct rpt_link));
1328                         m->next = m->prev = NULL;
1329                         insque((struct qelem *)m,(struct qelem *)linkbase.next);
1330                         l = l->next;
1331                 }
1332                 ast_mutex_unlock(&myrpt->lock);
1333                 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
1334                 if (!res) 
1335                         res = ast_waitstream(mychannel, "");
1336                 else
1337                          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1338                 ast_stopstream(mychannel);
1339                 ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
1340                 if (!res) 
1341                         res = ast_waitstream(mychannel, "");
1342                 else
1343                          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1344                 ast_stopstream(mychannel);
1345                 if (myrpt->callmode)
1346                 {
1347                         hastx = 1;
1348                         res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
1349                         if (!res) 
1350                                 res = ast_waitstream(mychannel, "");
1351                         else
1352                                  ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1353                         ast_stopstream(mychannel);
1354                 }
1355                 l = linkbase.next;
1356                 while(l != &linkbase)
1357                 {
1358                         hastx = 1;
1359                         res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
1360                         if (!res) 
1361                                 res = ast_waitstream(mychannel, "");
1362                         else
1363                                 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1364                         ast_stopstream(mychannel);
1365                         ast_say_character_str(mychannel,l->name,NULL,mychannel->language);
1366                         if (!res) 
1367                                 res = ast_waitstream(mychannel, "");
1368                         else
1369                                  ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1370                         ast_stopstream(mychannel);
1371                         res = ast_streamfile(mychannel, ((l->mode) ? 
1372                                 "rpt/tranceive" : "rpt/monitor"), mychannel->language);
1373                         if (!res) 
1374                                 res = ast_waitstream(mychannel, "");
1375                         else
1376                                 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1377                         ast_stopstream(mychannel);
1378                         l = l->next;
1379                 }                       
1380                 if (!hastx)
1381                 {
1382                         res = ast_streamfile(mychannel, "rpt/repeat_only", mychannel->language);
1383                         if (!res) 
1384                                 res = ast_waitstream(mychannel, "");
1385                         else
1386                                  ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1387                         ast_stopstream(mychannel);
1388                 }
1389                 /* destroy our local link queue */
1390                 l = linkbase.next;
1391                 while(l != &linkbase)
1392                 {
1393                         m = l;
1394                         l = l->next;
1395                         remque((struct qelem *)m);
1396                         free(m);
1397                 }                       
1398                 imdone = 1;
1399                 break;
1400             case TIMEOUT:
1401                 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
1402                 if (!res) 
1403                         res = ast_waitstream(mychannel, "");
1404                 else
1405                          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1406                 ast_stopstream(mychannel);
1407                 ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
1408                 res = ast_streamfile(mychannel, "rpt/timeout", mychannel->language);
1409                 break;
1410                 
1411             case STATS_TIME:
1412                 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
1413                 t = time(NULL);
1414                 localtime_r(&t, &localtm);
1415                 /* Say the phase of the day is before the time */
1416                 if((localtm.tm_hour >= 0) && (localtm.tm_hour < 12))
1417                         p = "rpt/goodmorning";
1418                 else if((localtm.tm_hour >= 12) && (localtm.tm_hour < 18))
1419                         p = "rpt/goodafternoon";
1420                 else
1421                         p = "rpt/goodevening";
1422                 if (sayfile(mychannel,p) == -1)
1423                 {
1424                         imdone = 1;
1425                         break;
1426                 }
1427                 /* Say the time is ... */               
1428                 if (sayfile(mychannel,"rpt/thetimeis") == -1)
1429                 {
1430                         imdone = 1;
1431                         break;
1432                 }
1433                 /* Say the time */                              
1434                 res = ast_say_time(mychannel, t, "", mychannel->language);
1435                 if (!res) 
1436                         res = ast_waitstream(mychannel, "");
1437                 ast_stopstream(mychannel);              
1438                 imdone = 1;
1439                 break;
1440             case STATS_VERSION:
1441                 p = strstr(tdesc, "version");   
1442                 if(!p)
1443                         break;  
1444                 if(sscanf(p, "version %d.%d", &vmajor, &vminor) != 2)
1445                         break;
1446                 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
1447                 /* Say "version" */
1448                 if (sayfile(mychannel,"rpt/version") == -1)
1449                 {
1450                         imdone = 1;
1451                         break;
1452                 }
1453                 if(!res) /* Say "X" */
1454                         ast_say_number(mychannel, vmajor, "", mychannel->language, (char *) NULL);
1455                 if (!res) 
1456                         res = ast_waitstream(mychannel, "");
1457                 ast_stopstream(mychannel);      
1458                 if (saycharstr(mychannel,".") == -1)
1459                 {
1460                         imdone = 1;
1461                         break;
1462                 }
1463                 if(!res) /* Say "Y" */
1464                         ast_say_number(mychannel, vminor, "", mychannel->language, (char *) NULL);
1465                 if (!res){
1466                         res = ast_waitstream(mychannel, "");
1467                         ast_stopstream(mychannel);
1468                 }       
1469                 else
1470                          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1471                 imdone = 1;
1472                 break;
1473             case ARB_ALPHA:
1474                 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
1475                 if(mytele->param)
1476                         saycharstr(mychannel, mytele->param);
1477                 imdone = 1;
1478                 break;
1479             case REV_PATCH:
1480                 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
1481                 if(mytele->param) {
1482
1483                         /* Parts of this section taken from app_parkandannounce */
1484                         char *tpl_working, *tpl_current;
1485                         char *tmp[100], *myparm;
1486                         int looptemp=0,i=0, dres = 0;
1487         
1488
1489                         tpl_working = strdupa(mytele->param);
1490                         myparm = strsep(&tpl_working,",");
1491                         tpl_current=strsep(&tpl_working, ":");
1492
1493                         while(tpl_current && looptemp < sizeof(tmp)) {
1494                                 tmp[looptemp]=tpl_current;
1495                                 looptemp++;
1496                                 tpl_current=strsep(&tpl_working,":");
1497                         }
1498
1499                         for(i=0; i<looptemp; i++) {
1500                                 if(!strcmp(tmp[i], "PARKED")) {
1501                                         ast_say_digits(mychannel, atoi(myparm), "", mychannel->language);
1502                                 } else if(!strcmp(tmp[i], "NODE")) {
1503                                         ast_say_digits(mychannel, atoi(myrpt->name), "", mychannel->language);
1504                                 } else {
1505                                         dres = ast_streamfile(mychannel, tmp[i], mychannel->language);
1506                                         if(!dres) {
1507                                                 dres = ast_waitstream(mychannel, "");
1508                                         } else {
1509                                                 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", tmp[i], mychannel->name);
1510                                                 dres = 0;
1511                                         }
1512                                 }
1513                         }
1514                 }
1515                 imdone = 1;
1516                 break;
1517             case TEST_TONE:
1518                 imdone = 1;
1519                 myrpt->stopgen = 0;
1520                 if ((res = ast_tonepair_start(mychannel, 1004.0, 0, 99999999, 7200.0))) 
1521                         break;
1522                 while(mychannel->generatordata && (!myrpt->stopgen)) {
1523                         if (ast_safe_sleep(mychannel,1)) break;
1524                         imdone = 1;
1525                         }
1526                 break;
1527             default:
1528                 break;
1529         }
1530         myrpt->stopgen = 0;
1531         if (!imdone)
1532         {
1533                 if (!res) 
1534                         res = ast_waitstream(mychannel, "");
1535                 else {
1536                         ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1537                         res = 0;
1538                 }
1539         }
1540         ast_stopstream(mychannel);
1541         ast_mutex_lock(&myrpt->lock);
1542         if (mytele->mode == TAILMSG)
1543         {
1544                 if (!res)
1545                 {
1546                         myrpt->tailmessagen++;
1547                         if(myrpt->tailmessagen >= myrpt->tailmessagemax) myrpt->tailmessagen = 0;
1548                 }
1549                 else
1550                 {
1551                         myrpt->tmsgtimer = myrpt->tailsquashedtime;
1552                 }
1553         }
1554         remque((struct qelem *)mytele);
1555         ast_mutex_unlock(&myrpt->lock);
1556         free(mytele);           
1557         ast_hangup(mychannel);
1558         pthread_exit(NULL);
1559 }
1560
1561 static void rpt_telemetry(struct rpt *myrpt,int mode, void *data)
1562 {
1563 struct rpt_tele *tele;
1564 struct rpt_link *mylink = (struct rpt_link *) data;
1565 pthread_attr_t attr;
1566
1567         tele = ast_malloc(sizeof(*tele));
1568         if (!tele)
1569         {
1570                 ast_log(LOG_WARNING, "Unable to allocate memory\n");
1571                 pthread_exit(NULL);
1572                 return;
1573         }
1574         /* zero it out */
1575         memset((char *)tele,0,sizeof(struct rpt_tele));
1576         tele->rpt = myrpt;
1577         tele->mode = mode;
1578         ast_mutex_lock(&myrpt->lock);
1579         if((mode == CONNFAIL) || (mode == REMDISC) || (mode == CONNECTED)){
1580                 memset(&tele->mylink,0,sizeof(struct rpt_link));
1581                 if (mylink){
1582                         memcpy(&tele->mylink,mylink,sizeof(struct rpt_link));
1583                 }
1584         }
1585         else if ((mode == ARB_ALPHA) || (mode == REV_PATCH)) {
1586                 strncpy(tele->param, (char *) data, TELEPARAMSIZE - 1);
1587                 tele->param[TELEPARAMSIZE - 1] = 0;
1588         }
1589         insque((struct qelem *)tele,(struct qelem *)myrpt->tele.next); 
1590         ast_mutex_unlock(&myrpt->lock);
1591         pthread_attr_init(&attr);
1592         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1593         ast_pthread_create(&tele->threadid,&attr,rpt_tele_thread,(void *) tele);
1594         return;
1595 }
1596
1597 static void *rpt_call(void *this)
1598 {
1599 ZT_CONFINFO ci;  /* conference info */
1600 struct  rpt *myrpt = (struct rpt *)this;
1601 int     res;
1602 struct  ast_frame wf;
1603 int stopped,congstarted;
1604 struct ast_channel *mychannel,*genchannel;
1605
1606         myrpt->mydtmf = 0;
1607         /* allocate a pseudo-channel thru asterisk */
1608         mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
1609         if (!mychannel)
1610         {
1611                 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
1612                 pthread_exit(NULL);
1613         }
1614         ci.chan = 0;
1615         ci.confno = myrpt->conf; /* use the pseudo conference */
1616         ci.confmode = ZT_CONF_REALANDPSEUDO | ZT_CONF_TALKER | ZT_CONF_LISTENER
1617                 | ZT_CONF_PSEUDO_TALKER | ZT_CONF_PSEUDO_LISTENER; 
1618         /* first put the channel on the conference */
1619         if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
1620         {
1621                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
1622                 ast_hangup(mychannel);
1623                 myrpt->callmode = 0;
1624                 pthread_exit(NULL);
1625         }
1626         /* allocate a pseudo-channel thru asterisk */
1627         genchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
1628         if (!genchannel)
1629         {
1630                 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
1631                 ast_hangup(mychannel);
1632                 pthread_exit(NULL);
1633         }
1634         ci.chan = 0;
1635         ci.confno = myrpt->conf;
1636         ci.confmode = ZT_CONF_REALANDPSEUDO | ZT_CONF_TALKER | ZT_CONF_LISTENER
1637                 | ZT_CONF_PSEUDO_TALKER | ZT_CONF_PSEUDO_LISTENER; 
1638         /* first put the channel on the conference */
1639         if (ioctl(genchannel->fds[0],ZT_SETCONF,&ci) == -1)
1640         {
1641                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
1642                 ast_hangup(mychannel);
1643                 ast_hangup(genchannel);
1644                 myrpt->callmode = 0;
1645                 pthread_exit(NULL);
1646         }
1647         if (myrpt->tonezone && (tone_zone_set_zone(mychannel->fds[0],myrpt->tonezone) == -1))
1648         {
1649                 ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->tonezone);
1650                 ast_hangup(mychannel);
1651                 ast_hangup(genchannel);
1652                 myrpt->callmode = 0;
1653                 pthread_exit(NULL);
1654         }
1655         if (myrpt->tonezone && (tone_zone_set_zone(genchannel->fds[0],myrpt->tonezone) == -1))
1656         {
1657                 ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->tonezone);
1658                 ast_hangup(mychannel);
1659                 ast_hangup(genchannel);
1660                 myrpt->callmode = 0;
1661                 pthread_exit(NULL);
1662         }
1663         /* start dialtone */
1664         if (tone_zone_play_tone(mychannel->fds[0],ZT_TONE_DIALTONE) < 0)
1665         {
1666                 ast_log(LOG_WARNING, "Cannot start dialtone\n");
1667                 ast_hangup(mychannel);
1668                 ast_hangup(genchannel);
1669                 myrpt->callmode = 0;
1670                 pthread_exit(NULL);
1671         }
1672         stopped = 0;
1673         congstarted = 0;
1674         while ((myrpt->callmode == 1) || (myrpt->callmode == 4))
1675         {
1676
1677                 if ((myrpt->callmode == 1) && (myrpt->cidx > 0) && (!stopped))
1678                 {
1679                         stopped = 1;
1680                         /* stop dial tone */
1681                         tone_zone_play_tone(mychannel->fds[0],-1);
1682                 }
1683                 if ((myrpt->callmode == 4) && (!congstarted))
1684                 {
1685                         congstarted = 1;
1686                         /* start congestion tone */
1687                         tone_zone_play_tone(mychannel->fds[0],ZT_TONE_CONGESTION);
1688                 }
1689                 res = ast_safe_sleep(mychannel, MSWAIT);
1690                 if (res < 0)
1691                 {
1692                         ast_hangup(mychannel);
1693                         ast_hangup(genchannel);
1694                         ast_mutex_lock(&myrpt->lock);
1695                         myrpt->callmode = 0;
1696                         ast_mutex_unlock(&myrpt->lock);
1697                         pthread_exit(NULL);
1698                 }
1699         }
1700         /* stop any tone generation */
1701         tone_zone_play_tone(mychannel->fds[0],-1);
1702         /* end if done */
1703         if (!myrpt->callmode)
1704         {
1705                 ast_hangup(mychannel);
1706                 ast_hangup(genchannel);
1707                 ast_mutex_lock(&myrpt->lock);
1708                 myrpt->callmode = 0;
1709                 ast_mutex_unlock(&myrpt->lock);
1710                 pthread_exit(NULL);                     
1711         }
1712
1713         if (myrpt->ourcallerid && *myrpt->ourcallerid){
1714                 char *name, *loc, *instr;
1715                 instr = strdup(myrpt->ourcallerid);
1716                 if(instr){
1717                         ast_callerid_parse(instr, &name, &loc);
1718                         if(loc){
1719                                 if(mychannel->cid.cid_num)
1720                                         free(mychannel->cid.cid_num);
1721                                 mychannel->cid.cid_num = strdup(loc);
1722                         }
1723                         if(name){
1724                                 if(mychannel->cid.cid_name)
1725                                         free(mychannel->cid.cid_name);
1726                                 mychannel->cid.cid_name = strdup(name);
1727                         }
1728                         free(instr);
1729                 }
1730         }
1731
1732         strncpy(mychannel->exten, myrpt->exten, sizeof(mychannel->exten) - 1);
1733         strncpy(mychannel->context, myrpt->ourcontext, sizeof(mychannel->context) - 1);
1734         if (myrpt->acctcode)
1735                 strncpy(mychannel->accountcode, myrpt->acctcode, sizeof(mychannel->accountcode) - 1);
1736         mychannel->priority = 1;
1737         ast_channel_undefer_dtmf(mychannel);
1738         if (ast_pbx_start(mychannel) < 0)
1739         {
1740                 ast_log(LOG_WARNING, "Unable to start PBX!!\n");
1741                 ast_hangup(mychannel);
1742                 ast_hangup(genchannel);
1743                 ast_mutex_lock(&myrpt->lock);
1744                 myrpt->callmode = 0;
1745                 ast_mutex_unlock(&myrpt->lock);
1746                 pthread_exit(NULL);
1747         }
1748         usleep(10000);
1749         ast_mutex_lock(&myrpt->lock);
1750         myrpt->callmode = 3;
1751         while(myrpt->callmode)
1752         {
1753                 if ((!mychannel->pbx) && (myrpt->callmode != 4))
1754                 {
1755                         myrpt->callmode = 4;
1756                         ast_mutex_unlock(&myrpt->lock);
1757                         /* start congestion tone */
1758                         tone_zone_play_tone(genchannel->fds[0],ZT_TONE_CONGESTION);
1759                         ast_mutex_lock(&myrpt->lock);
1760                 }
1761                 if (myrpt->mydtmf)
1762                 {
1763                         wf.frametype = AST_FRAME_DTMF;
1764                         wf.subclass = myrpt->mydtmf;
1765                         wf.offset = 0;
1766                         wf.mallocd = 0;
1767                         wf.data = NULL;
1768                         wf.datalen = 0;
1769                         wf.samples = 0;
1770                         ast_mutex_unlock(&myrpt->lock);
1771                         ast_write(genchannel,&wf); 
1772                         ast_mutex_lock(&myrpt->lock);
1773                         myrpt->mydtmf = 0;
1774                 }
1775                 ast_mutex_unlock(&myrpt->lock);
1776                 usleep(MSWAIT * 1000);
1777                 ast_mutex_lock(&myrpt->lock);
1778         }
1779         ast_mutex_unlock(&myrpt->lock);
1780         tone_zone_play_tone(genchannel->fds[0],-1);
1781         if (mychannel->pbx) ast_softhangup(mychannel,AST_SOFTHANGUP_DEV);
1782         ast_hangup(genchannel);
1783         ast_mutex_lock(&myrpt->lock);
1784         myrpt->callmode = 0;
1785         ast_mutex_unlock(&myrpt->lock);
1786         pthread_exit(NULL);
1787 }
1788
1789 static void send_link_dtmf(struct rpt *myrpt,char c)
1790 {
1791 char    str[300];
1792 struct  ast_frame wf;
1793 struct  rpt_link *l;
1794
1795         snprintf(str, sizeof(str), "D %s %s %d %c", myrpt->cmdnode, myrpt->name, ++(myrpt->dtmfidx), c);
1796         wf.frametype = AST_FRAME_TEXT;
1797         wf.subclass = 0;
1798         wf.offset = 0;
1799         wf.mallocd = 1;
1800         wf.datalen = strlen(str) + 1;
1801         wf.samples = 0;
1802         l = myrpt->links.next;
1803         /* first, see if our dude is there */
1804         while(l != &myrpt->links)
1805         {
1806                 if (l->name[0] == '0') 
1807                 {
1808                         l = l->next;
1809                         continue;
1810                 }
1811                 /* if we found it, write it and were done */
1812                 if (!strcmp(l->name,myrpt->cmdnode))
1813                 {
1814                         wf.data = strdup(str);
1815                         if (l->chan) ast_write(l->chan,&wf);
1816                         return;
1817                 }
1818                 l = l->next;
1819         }
1820         l = myrpt->links.next;
1821         /* if not, give it to everyone */
1822         while(l != &myrpt->links)
1823         {
1824                 wf.data = strdup(str);
1825                 if (l->chan) ast_write(l->chan,&wf);
1826                 l = l->next;
1827         }
1828         return;
1829 }
1830
1831 /*
1832 * Internet linking function 
1833 */
1834
1835 static int function_ilink(struct rpt *myrpt, char *param, char *digits, int command_source, struct rpt_link *mylink)
1836 {
1837
1838         char *val, *s, *s1, *s2, *tele;
1839         char tmp[300], deststr[300] = "",modechange = 0;
1840         char digitbuf[MAXNODESTR];
1841         struct rpt_link *l;
1842         ZT_CONFINFO ci;  /* conference info */
1843
1844         if(!param)
1845                 return DC_ERROR;
1846                 
1847                         
1848         if (!myrpt->enable)
1849                 return DC_ERROR;
1850
1851         strncpy(digitbuf,digits,MAXNODESTR - 1);
1852
1853         if(debug)
1854                 printf("@@@@ ilink param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
1855                 
1856         switch(myatoi(param)){
1857                 case 1: /* Link off */
1858                         if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
1859                                 strcpy(digitbuf,myrpt->lastlinknode);
1860                         val = ast_variable_retrieve(cfg, myrpt->nodes, digitbuf);
1861                         if (!val){
1862                                 if(strlen(digitbuf) >= myrpt->longestnode)
1863                                         return DC_ERROR;
1864                                 break;
1865                         }
1866                         strncpy(tmp,val,sizeof(tmp) - 1);
1867                         s = tmp;
1868                         s1 = strsep(&s,",");
1869                         s2 = strsep(&s,",");
1870                         ast_mutex_lock(&myrpt->lock);
1871                         l = myrpt->links.next;
1872                         /* try to find this one in queue */
1873                         while(l != &myrpt->links){
1874                                 if (l->name[0] == '0') 
1875                                 {
1876                                         l = l->next;
1877                                         continue;
1878                                 }
1879                                 /* if found matching string */
1880                                 if (!strcmp(l->name, digitbuf))
1881                                         break;
1882                                 l = l->next;
1883                         }
1884                         if (l != &myrpt->links){ /* if found */
1885                                 struct  ast_frame wf;
1886
1887                                 strncpy(myrpt->lastlinknode,digitbuf,MAXNODESTR - 1);
1888                                 l->retries = MAX_RETRIES + 1;
1889                                 l->disced = 1;
1890                                 ast_mutex_unlock(&myrpt->lock);
1891                                 wf.frametype = AST_FRAME_TEXT;
1892                                 wf.subclass = 0;
1893                                 wf.offset = 0;
1894                                 wf.mallocd = 1;
1895                                 wf.datalen = strlen(discstr) + 1;
1896                                 wf.samples = 0;
1897                                 wf.data = strdup(discstr);
1898                                 if (l->chan)
1899                                 {
1900                                         ast_write(l->chan,&wf);
1901                                         if (ast_safe_sleep(l->chan,250) == -1) return DC_ERROR;
1902                                         ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
1903                                 }
1904                                 rpt_telemetry(myrpt, COMPLETE, NULL);
1905                                 return DC_COMPLETE;
1906                         }
1907                         ast_mutex_unlock(&myrpt->lock); 
1908                         return DC_COMPLETE;
1909                 case 2: /* Link Monitor */
1910                         if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
1911                                 strcpy(digitbuf,myrpt->lastlinknode);
1912                         val = ast_variable_retrieve(cfg, myrpt->nodes, digitbuf);
1913                         if (!val){
1914                                 if(strlen(digitbuf) >= myrpt->longestnode)
1915                                         return DC_ERROR;
1916                                 break;
1917                         }
1918                         strncpy(tmp,val,sizeof(tmp) - 1);
1919                         s = tmp;
1920                         s1 = strsep(&s,",");
1921                         s2 = strsep(&s,",");
1922                         ast_mutex_lock(&myrpt->lock);
1923                         l = myrpt->links.next;
1924                         /* try to find this one in queue */
1925                         while(l != &myrpt->links){
1926                                 if (l->name[0] == '0') 
1927                                 {
1928                                         l = l->next;
1929                                         continue;
1930                                 }
1931                                 /* if found matching string */
1932                                 if (!strcmp(l->name, digitbuf))
1933                                         break;
1934                                 l = l->next;
1935                         }
1936                         /* if found */
1937                         if (l != &myrpt->links) 
1938                         {
1939                                 /* if already in this mode, just ignore */
1940                                 if ((!l->mode) || (!l->chan)) {
1941                                         ast_mutex_unlock(&myrpt->lock);
1942                                         rpt_telemetry(myrpt,REMALREADY,NULL);
1943                                         return DC_COMPLETE;
1944                                         
1945                                 }
1946                                 ast_mutex_unlock(&myrpt->lock);
1947                                 if (l->chan) ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
1948                                 l->retries = MAX_RETRIES + 1;
1949                                 l->disced = 2;
1950                                 modechange = 1;
1951                         } else
1952                                 ast_mutex_unlock(&myrpt->lock);
1953                         strncpy(myrpt->lastlinknode,digitbuf,MAXNODESTR - 1);
1954                         /* establish call in monitor mode */
1955                         l = ast_calloc(1, sizeof(*l));
1956                         if (!l){
1957                                 ast_log(LOG_WARNING, "Unable to malloc\n");
1958                                 return DC_ERROR;
1959                         }
1960                         /* zero the silly thing */
1961                         snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
1962                         tele = strchr(deststr,'/');
1963                         if (!tele){
1964                                 fprintf(stderr,"link2:Dial number (%s) must be in format tech/number\n",deststr);
1965                                 return DC_ERROR;
1966                         }
1967                         *tele++ = 0;
1968                         l->isremote = (s && ast_true(s));
1969                         strncpy(l->name, digitbuf, MAXNODESTR - 1);
1970                         l->chan = ast_request(deststr,AST_FORMAT_SLINEAR,tele,NULL);
1971                         if (modechange) l->connected = 1;
1972                         if (l->chan){
1973                                 ast_set_read_format(l->chan,AST_FORMAT_SLINEAR);
1974                                 ast_set_write_format(l->chan,AST_FORMAT_SLINEAR);
1975                                 l->chan->whentohangup = 0;
1976                                 l->chan->appl = "Apprpt";
1977                                 l->chan->data = "(Remote Rx)";
1978                                 if (option_verbose > 2)
1979                                         ast_verbose(VERBOSE_PREFIX_3 "rpt (remote) initiating call to %s/%s on %s\n",
1980                                                 deststr,tele,l->chan->name);
1981                                 if(l->chan->cid.cid_num)
1982                                         free(l->chan->cid.cid_num);
1983                                 l->chan->cid.cid_num = strdup(myrpt->name);
1984                                 ast_call(l->chan,tele,0);
1985                         }
1986                         else
1987                         {
1988                                 rpt_telemetry(myrpt,CONNFAIL,l);
1989                                 free(l);
1990                                 if (option_verbose > 2)
1991                                         ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
1992                                                 deststr,tele,l->chan->name);
1993                                 return DC_ERROR;
1994                         }
1995                         /* allocate a pseudo-channel thru asterisk */
1996                         l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
1997                         if (!l->pchan){
1998                                 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
1999                                 ast_hangup(l->chan);
2000                                 free(l);
2001                                 return DC_ERROR;
2002                         }
2003                         ast_set_read_format(l->pchan,AST_FORMAT_SLINEAR);
2004                         ast_set_write_format(l->pchan,AST_FORMAT_SLINEAR);
2005                         /* make a conference for the pseudo-one */
2006                         ci.chan = 0;
2007                         ci.confno = myrpt->conf;
2008                         ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER;
2009                         /* first put the channel on the conference in proper mode */
2010                         if (ioctl(l->pchan->fds[0],ZT_SETCONF,&ci) == -1)
2011                         {
2012                                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2013                                 ast_hangup(l->chan);
2014                                 ast_hangup(l->pchan);
2015                                 free(l);
2016                                 return DC_ERROR;
2017                         }
2018                         ast_mutex_lock(&myrpt->lock);
2019                         /* insert at end of queue */
2020                         insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
2021                         ast_mutex_unlock(&myrpt->lock);
2022                         rpt_telemetry(myrpt,COMPLETE,NULL);
2023                         return DC_COMPLETE;
2024                 case 3: /* Link transceive */
2025                         if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
2026                                 strcpy(digitbuf,myrpt->lastlinknode);
2027                         val = ast_variable_retrieve(cfg, myrpt->nodes, digitbuf);
2028                         if (!val){
2029                                 if(strlen(digitbuf) >= myrpt->longestnode)
2030                                         return DC_ERROR;
2031                                 break;
2032                         }
2033                         strncpy(tmp,val,sizeof(tmp) - 1);
2034                         s = tmp;
2035                         s1 = strsep(&s,",");
2036                         s2 = strsep(&s,",");
2037                         ast_mutex_lock(&myrpt->lock);
2038                         l = myrpt->links.next;
2039                         /* try to find this one in queue */
2040                         while(l != &myrpt->links){
2041                                 if (l->name[0] == '0') 
2042                                 {
2043                                         l = l->next;
2044                                         continue;
2045                                 }
2046                                 /* if found matching string */
2047                                 if (!strcmp(l->name, digitbuf))
2048                                         break;
2049                                 l = l->next;
2050                         }
2051                         /* if found */
2052                         if (l != &myrpt->links){ 
2053                                 /* if already in this mode, just ignore */
2054                                 if ((l->mode) || (!l->chan)) {
2055                                         ast_mutex_unlock(&myrpt->lock);
2056                                         rpt_telemetry(myrpt, REMALREADY, NULL);
2057                                         return DC_COMPLETE;
2058                                 }
2059                                 ast_mutex_unlock(&myrpt->lock);
2060                                 if (l->chan) ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
2061                                 l->retries = MAX_RETRIES + 1;
2062                                 l->disced = 2;
2063                                 modechange = 1;
2064                         } else
2065                                 ast_mutex_unlock(&myrpt->lock);
2066                         strncpy(myrpt->lastlinknode,digitbuf,MAXNODESTR - 1);
2067                         /* establish call in tranceive mode */
2068                         l = ast_calloc(1, sizeof(*l));
2069                         if (!l){
2070                                 ast_log(LOG_WARNING, "Unable to malloc\n");
2071                                 return(DC_ERROR);
2072                         }
2073                         l->mode = 1;
2074                         l->outbound = 1;
2075                         strncpy(l->name, digitbuf, MAXNODESTR - 1);
2076                         l->isremote = (s && ast_true(s));
2077                         if (modechange) l->connected = 1;
2078                         snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
2079                         tele = strchr(deststr, '/');
2080                         if (!tele){
2081                                 fprintf(stderr,"link3:Dial number (%s) must be in format tech/number\n",deststr);
2082                                 free(l);
2083                                 return DC_ERROR;
2084                         }
2085                         *tele++ = 0;
2086                         l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele,NULL);
2087                         if (l->chan){
2088                                 ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
2089                                 ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
2090                                 l->chan->whentohangup = 0;
2091                                 l->chan->appl = "Apprpt";
2092                                 l->chan->data = "(Remote Rx)";
2093                                 if (option_verbose > 2)
2094                                         ast_verbose(VERBOSE_PREFIX_3 "rpt (remote) initiating call to %s/%s on %s\n",
2095                                                 deststr, tele, l->chan->name);
2096                                 if(l->chan->cid.cid_num)
2097                                         free(l->chan->cid.cid_num);
2098                                 l->chan->cid.cid_num = strdup(myrpt->name);
2099                                 ast_call(l->chan,tele,999);
2100                         }
2101                         else{
2102                                 rpt_telemetry(myrpt,CONNFAIL,l);
2103                                 free(l);
2104                                 if (option_verbose > 2)
2105                                         ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
2106                                                 deststr,tele,l->chan->name);
2107                                 return DC_ERROR;
2108                         }
2109                         /* allocate a pseudo-channel thru asterisk */
2110                         l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
2111                         if (!l->pchan){
2112                                 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
2113                                 ast_hangup(l->chan);
2114                                 free(l);
2115                                 return DC_ERROR;
2116                         }
2117                         ast_set_read_format(l->pchan, AST_FORMAT_SLINEAR);
2118                         ast_set_write_format(l->pchan, AST_FORMAT_SLINEAR);
2119                         /* make a conference for the tx */
2120                         ci.chan = 0;
2121                         ci.confno = myrpt->conf;
2122                         ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER;
2123                         /* first put the channel on the conference in proper mode */
2124                         if (ioctl(l->pchan->fds[0], ZT_SETCONF, &ci) == -1)
2125                         {
2126                                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2127                                 ast_hangup(l->chan);
2128                                 ast_hangup(l->pchan);
2129                                 free(l);
2130                                 return DC_ERROR;
2131                         }
2132                         ast_mutex_lock(&myrpt->lock);
2133                         /* insert at end of queue */
2134                         insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
2135                         ast_mutex_unlock(&myrpt->lock);
2136                         rpt_telemetry(myrpt,COMPLETE,NULL);
2137                         return DC_COMPLETE;
2138                 case 4: /* Enter Command Mode */
2139                 
2140                         /* if doesnt allow link cmd, or no links active, return */
2141                         if (((command_source != SOURCE_RPT) && (command_source != SOURCE_PHONE) && (command_source != SOURCE_DPHONE)) || (myrpt->links.next == &myrpt->links))
2142                                 return DC_COMPLETE;
2143                         
2144                         /* if already in cmd mode, or selected self, fughetabahtit */
2145                         if ((myrpt->cmdnode[0]) || (!strcmp(myrpt->name, digitbuf))){
2146                         
2147                                 rpt_telemetry(myrpt, REMALREADY, NULL);
2148                                 return DC_COMPLETE;
2149                         }
2150                         if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
2151                                 strcpy(digitbuf,myrpt->lastlinknode);
2152                         /* node must at least exist in list */
2153                         val = ast_variable_retrieve(cfg, myrpt->nodes, digitbuf);
2154                         if (!val){
2155                                 if(strlen(digitbuf) >= myrpt->longestnode)
2156                                         return DC_ERROR;
2157                                 break;
2158                         
2159                         }
2160                         ast_mutex_lock(&myrpt->lock);
2161                         strcpy(myrpt->lastlinknode,digitbuf);
2162                         strncpy(myrpt->cmdnode, digitbuf, sizeof(myrpt->cmdnode) - 1);
2163                         ast_mutex_unlock(&myrpt->lock);
2164                         rpt_telemetry(myrpt, REMGO, NULL);      
2165                         return DC_COMPLETE;
2166                         
2167                 case 5: /* Status */
2168                         rpt_telemetry(myrpt, STATUS, NULL);
2169                         return DC_COMPLETE;
2170                         
2171                         
2172                 case 6: /* All Links Off */
2173                         l = myrpt->links.next;
2174                         
2175                         while(l != &myrpt->links){
2176                                 if (l->chan) ast_softhangup(l->chan, AST_SOFTHANGUP_DEV); /* Hang 'em up */
2177                                 l = l->next;
2178                         }
2179                         rpt_telemetry(myrpt, COMPLETE, NULL);
2180                         break;
2181         
2182                 default:
2183                         return DC_ERROR;
2184                         
2185         }
2186         
2187         return DC_INDETERMINATE;
2188 }       
2189
2190 /*
2191 * Autopatch up
2192 */
2193
2194 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
2195 {
2196         pthread_attr_t attr;
2197         
2198                 
2199         if (!myrpt->enable)
2200                 return DC_ERROR;
2201                 
2202         if(debug)
2203                 printf("@@@@ Autopatch up\n");
2204
2205         ast_mutex_lock(&myrpt->lock);
2206         
2207         /* if on call, force * into current audio stream */
2208         
2209         if ((myrpt->callmode == 2) || (myrpt->callmode == 3)){
2210                 myrpt->mydtmf = myrpt->funcchar;
2211         }
2212         if (myrpt->callmode){
2213                 ast_mutex_unlock(&myrpt->lock);
2214                 return DC_COMPLETE;
2215         }
2216         myrpt->callmode = 1;
2217         myrpt->cidx = 0;
2218         myrpt->exten[myrpt->cidx] = 0;
2219         ast_mutex_unlock(&myrpt->lock);
2220         pthread_attr_init(&attr);
2221         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2222         ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *) myrpt);
2223         return DC_COMPLETE;
2224 }
2225
2226 /*
2227 * Autopatch down
2228 */
2229
2230 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
2231 {
2232         if (!myrpt->enable)
2233                 return DC_ERROR;
2234         
2235         if(debug)
2236                 printf("@@@@ Autopatch down\n");
2237                 
2238         ast_mutex_lock(&myrpt->lock);
2239         
2240         if (!myrpt->callmode){
2241                 ast_mutex_unlock(&myrpt->lock);
2242                 return DC_COMPLETE;
2243         }
2244         
2245         myrpt->callmode = 0;
2246         ast_mutex_unlock(&myrpt->lock);
2247         rpt_telemetry(myrpt, TERM, NULL);
2248         return DC_COMPLETE;
2249 }
2250
2251 /*
2252 * Status
2253 */
2254
2255 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
2256 {
2257
2258         if(!param)
2259                 return DC_ERROR;
2260                 
2261                         
2262         if (!myrpt->enable)
2263                 return DC_ERROR;
2264
2265         if(debug)
2266                 printf("@@@@ status param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
2267         
2268         switch(myatoi(param)){
2269                 case 1: /* System ID */
2270                         rpt_telemetry(myrpt, ID1, NULL);
2271                         return DC_COMPLETE;
2272                 case 2: /* System Time */
2273                         rpt_telemetry(myrpt, STATS_TIME, NULL);
2274                         return DC_COMPLETE;
2275                 case 3: /* app_rpt.c version */
2276                         rpt_telemetry(myrpt, STATS_VERSION, NULL);
2277                 default:
2278                         return DC_ERROR;
2279         }
2280         return DC_INDETERMINATE;
2281 }
2282
2283 /*
2284 * COP - Control operator
2285 */
2286
2287 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
2288 {
2289         if(!param)
2290                 return DC_ERROR;
2291         
2292         switch(myatoi(param)){
2293                 case 1: /* System reset */
2294                         system("killall -9 asterisk"); /* FIXME to drastic? */
2295                         return DC_COMPLETE;
2296
2297                 case 2:
2298                         myrpt->enable = 1;
2299                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "RPTENA");
2300                         return DC_COMPLETE;
2301                         
2302                 case 3:
2303                         myrpt->enable = 0;
2304                         return DC_COMPLETE;
2305                         
2306                 case 4: /* test tone on */
2307                         rpt_telemetry(myrpt, TEST_TONE, NULL);
2308                         return DC_COMPLETE;
2309
2310                 case 5: /* Disgorge variables to log for debug purposes */
2311                         myrpt->disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
2312                         return DC_COMPLETE;
2313
2314                 case 6: /* Simulate COR being activated (phone only) */
2315                         if (command_source != SOURCE_PHONE) return DC_INDETERMINATE;
2316                         return DC_DOKEY;        
2317
2318         }       
2319         return DC_INDETERMINATE;
2320 }
2321
2322 /*
2323 * Collect digits one by one until something matches
2324 */
2325
2326 static int collect_function_digits(struct rpt *myrpt, char *digits, 
2327         int command_source, struct rpt_link *mylink)
2328 {
2329         int i;
2330         char *stringp,*action,*param,*functiondigits;
2331         char function_table_name[30] = "";
2332         char workstring[80];
2333         
2334         struct ast_variable *vp;
2335         
2336         if(debug)       
2337                 printf("@@@@ Digits collected: %s, source: %d\n", digits, command_source);
2338         
2339         if (command_source == SOURCE_DPHONE) {
2340                 if (!myrpt->dphone_functions) return DC_INDETERMINATE;
2341                 strncpy(function_table_name, myrpt->dphone_functions, sizeof(function_table_name) - 1);
2342                 }
2343         else if (command_source == SOURCE_PHONE) {
2344                 if (!myrpt->phone_functions) return DC_INDETERMINATE;
2345                 strncpy(function_table_name, myrpt->phone_functions, sizeof(function_table_name) - 1);
2346                 }
2347         else if (command_source == SOURCE_LNK)
2348                 strncpy(function_table_name, myrpt->link_functions, sizeof(function_table_name) - 1);
2349         else
2350                 strncpy(function_table_name, myrpt->functions, sizeof(function_table_name) - 1);
2351         vp = ast_variable_browse(cfg, function_table_name);
2352         while(vp) {
2353                 if(!strncasecmp(vp->name, digits, strlen(vp->name)))
2354                         break;
2355                 vp = vp->next;
2356         }       
2357         if(!vp) {
2358                 int n;
2359
2360                 n = myrpt->longestfunc;
2361                 if (command_source == SOURCE_LNK) n = myrpt->link_longestfunc;
2362                 else 
2363                 if (command_source == SOURCE_PHONE) n = myrpt->phone_longestfunc;
2364                 else 
2365                 if (command_source == SOURCE_DPHONE) n = myrpt->dphone_longestfunc;
2366                 
2367                 if(strlen(digits) >= n)
2368                         return DC_ERROR;
2369                 else
2370                         return DC_INDETERMINATE;
2371         }       
2372         /* Found a match, retrieve value part and parse */
2373         strncpy(workstring, vp->value, sizeof(workstring) - 1 );
2374         stringp = workstring;
2375         action = strsep(&stringp, ",");
2376         param = stringp;
2377         if(debug)
2378                 printf("@@@@ action: %s, param = %s\n",action, (param) ? param : "(null)");
2379         /* Look up the action */
2380         for(i = 0 ; i < (sizeof(function_table)/sizeof(struct function_table_tag)); i++){
2381                 if(!strncasecmp(action, function_table[i].action, strlen(action)))
2382                         break;
2383         }
2384         if(debug)
2385                 printf("@@@@ table index i = %d\n",i);
2386         if(i == (sizeof(function_table)/sizeof(struct function_table_tag))){
2387                 /* Error, action not in table */
2388                 return DC_ERROR;
2389         }
2390         if(function_table[i].function == NULL){
2391                 /* Error, function undefined */
2392                 if(debug)
2393                         printf("@@@@ NULL for action: %s\n",action);
2394                 return DC_ERROR;
2395         }
2396         functiondigits = digits + strlen(vp->name);
2397         return (*function_table[i].function)(myrpt, param, functiondigits, command_source, mylink);
2398 }
2399
2400
2401 static void handle_link_data(struct rpt *myrpt, struct rpt_link *mylink,
2402         char *str)
2403 {
2404 char    tmp[300],cmd[300] = "",dest[300],src[300],c;
2405 int     seq, res;
2406 struct rpt_link *l;
2407 struct  ast_frame wf;
2408
2409         wf.frametype = AST_FRAME_TEXT;
2410         wf.subclass = 0;
2411         wf.offset = 0;
2412         wf.mallocd = 1;
2413         wf.datalen = strlen(str) + 1;
2414         wf.samples = 0;
2415         /* put string in our buffer */
2416         strncpy(tmp,str,sizeof(tmp) - 1);
2417
2418         if (!strcmp(tmp,discstr))
2419         {
2420                 mylink->disced = 1;
2421                 mylink->retries = MAX_RETRIES + 1;
2422                 ast_softhangup(mylink->chan,AST_SOFTHANGUP_DEV);
2423                 return;
2424         }
2425         if (sscanf(tmp,"%s %s %s %d %c",cmd,dest,src,&seq,&c) != 5)
2426         {
2427                 ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
2428                 return;
2429         }
2430         if (strcmp(cmd,"D"))
2431         {
2432                 ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
2433                 return;
2434         }
2435
2436         if (dest[0] == '0')
2437         {
2438                 strcpy(dest,myrpt->name);
2439         }               
2440
2441         /* if not for me, redistribute to all links */
2442         if (strcmp(dest,myrpt->name))
2443         {
2444                 l = myrpt->links.next;
2445                 /* see if this is one in list */
2446                 while(l != &myrpt->links)
2447                 {
2448                         if (l->name[0] == '0') 
2449                         {
2450                                 l = l->next;
2451                                 continue;
2452                         }
2453                         /* dont send back from where it came */
2454                         if ((l == mylink) || (!strcmp(l->name,mylink->name)))
2455                         {
2456                                 l = l->next;
2457                                 continue;
2458                         }
2459                         /* if it is, send it and we're done */
2460                         if (!strcmp(l->name,dest))
2461                         {
2462                                 /* send, but not to src */
2463                                 if (strcmp(l->name,src)) {
2464                                         wf.data = strdup(str);
2465                                         if (l->chan) ast_write(l->chan,&wf);
2466                                 }
2467                                 return;
2468                         }
2469                         l = l->next;
2470                 }
2471                 l = myrpt->links.next;
2472                 /* otherwise, send it to all of em */
2473                 while(l != &myrpt->links)
2474                 {
2475                         if (l->name[0] == '0') 
2476                         {
2477                                 l = l->next;
2478                                 continue;
2479                         }
2480                         /* dont send back from where it came */
2481                         if ((l == mylink) || (!strcmp(l->name,mylink->name)))
2482                         {
2483                                 l = l->next;
2484                                 continue;
2485                         }
2486                         /* send, but not to src */
2487                         if (strcmp(l->name,src)) {
2488                                 wf.data = strdup(str);
2489                                 if (l->chan) ast_write(l->chan,&wf);
2490                         }
2491                         l = l->next;
2492                 }
2493                 return;
2494         }
2495         ast_mutex_lock(&myrpt->lock);
2496         if (c == myrpt->endchar) myrpt->stopgen = 1;
2497         if (myrpt->callmode == 1)
2498         {
2499                 myrpt->exten[myrpt->cidx++] = c;
2500                 myrpt->exten[myrpt->cidx] = 0;
2501                 /* if this exists */
2502                 if (ast_exists_extension(myrpt->pchannel,myrpt->ourcontext,myrpt->exten,1,NULL))
2503                 {
2504                         myrpt->callmode = 2;
2505                         rpt_telemetry(myrpt,PROC,NULL); 
2506                 }
2507                 /* if can continue, do so */
2508                 if (!ast_canmatch_extension(myrpt->pchannel,myrpt->ourcontext,myrpt->exten,1,NULL)) 
2509                 {
2510                         /* call has failed, inform user */
2511                         myrpt->callmode = 4;
2512                 }
2513         }
2514         if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
2515         {
2516                 myrpt->mydtmf = c;
2517         }
2518         if (c == myrpt->funcchar)
2519         {
2520                 myrpt->rem_dtmfidx = 0;
2521                 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
2522                 time(&myrpt->rem_dtmf_time);
2523                 ast_mutex_unlock(&myrpt->lock);
2524                 return;
2525         } 
2526         else if ((c != myrpt->endchar) && (myrpt->rem_dtmfidx >= 0))
2527         {
2528                 time(&myrpt->rem_dtmf_time);
2529                 if (myrpt->rem_dtmfidx < MAXDTMF)
2530                 {
2531                         myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
2532                         myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
2533                         
2534                         ast_mutex_unlock(&myrpt->lock);
2535                         strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1);
2536                         res = collect_function_digits(myrpt, cmd, SOURCE_LNK, mylink);
2537                         ast_mutex_lock(&myrpt->lock);
2538                         
2539                         switch(res){
2540
2541                                 case DC_INDETERMINATE:
2542                                         break;
2543                                 
2544                                 case DC_REQ_FLUSH:
2545                                         myrpt->rem_dtmfidx = 0;
2546                                         myrpt->rem_dtmfbuf[0] = 0;
2547                                         break;
2548                                 
2549                                 
2550                                 case DC_COMPLETE:
2551                                         myrpt->rem_dtmfbuf[0] = 0;
2552                                         myrpt->rem_dtmfidx = -1;
2553                                         myrpt->rem_dtmf_time = 0;
2554                                         break;
2555                                 
2556                                 case DC_ERROR:
2557                                 default:
2558                                         myrpt->rem_dtmfbuf[0] = 0;
2559                                         myrpt->rem_dtmfidx = -1;
2560                                         myrpt->rem_dtmf_time = 0;
2561                                         break;
2562                         }
2563                 }
2564
2565         }
2566         ast_mutex_unlock(&myrpt->lock);
2567         return;
2568 }
2569
2570 static void handle_link_phone_dtmf(struct rpt *myrpt, struct rpt_link *mylink,
2571         char c)
2572 {
2573
2574 char    cmd[300];
2575 int     res;
2576
2577         ast_mutex_lock(&myrpt->lock);
2578         if (c == myrpt->endchar)
2579         {
2580                 if (mylink->lastrx)
2581                 {
2582                         mylink->lastrx = 0;
2583                         ast_mutex_unlock(&myrpt->lock);
2584                         return;
2585                 }
2586                 myrpt->stopgen = 1;
2587                 if (myrpt->cmdnode[0])
2588                 {
2589                         myrpt->cmdnode[0] = 0;
2590                         myrpt->dtmfidx = -1;
2591                         myrpt->dtmfbuf[0] = 0;
2592                         ast_mutex_unlock(&myrpt->lock);
2593                         rpt_telemetry(myrpt,COMPLETE,NULL);
2594                         ast_mutex_unlock(&myrpt->lock);
2595                         return;
2596                 }
2597         }
2598         if (myrpt->cmdnode[0])
2599         {
2600                 ast_mutex_unlock(&myrpt->lock);
2601                 send_link_dtmf(myrpt,c);
2602                 return;
2603         }
2604         if (myrpt->callmode == 1)
2605         {
2606                 myrpt->exten[myrpt->cidx++] = c;
2607                 myrpt->exten[myrpt->cidx] = 0;
2608                 /* if this exists */
2609                 if (ast_exists_extension(myrpt->pchannel,myrpt->ourcontext,myrpt->exten,1,NULL))
2610                 {
2611                         myrpt->callmode = 2;
2612                         rpt_telemetry(myrpt,PROC,NULL); 
2613                 }
2614                 /* if can continue, do so */
2615                 if (!ast_canmatch_extension(myrpt->pchannel,myrpt->ourcontext,myrpt->exten,1,NULL)) 
2616                 {
2617                         /* call has failed, inform user */
2618                         myrpt->callmode = 4;
2619                 }
2620         }
2621         if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
2622         {
2623                 myrpt->mydtmf = c;
2624         }
2625         if (c == myrpt->funcchar)
2626         {
2627                 myrpt->rem_dtmfidx = 0;
2628                 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
2629                 time(&myrpt->rem_dtmf_time);
2630                 ast_mutex_unlock(&myrpt->lock);
2631                 return;
2632         } 
2633         else if ((c != myrpt->endchar) && (myrpt->rem_dtmfidx >= 0))
2634         {
2635                 time(&myrpt->rem_dtmf_time);
2636                 if (myrpt->rem_dtmfidx < MAXDTMF)
2637                 {
2638                         myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
2639                         myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
2640                         
2641                         ast_mutex_unlock(&myrpt->lock);
2642                         strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1);
2643                         res = collect_function_digits(myrpt, cmd, 
2644                                 ((mylink->phonemode == 2) ? SOURCE_DPHONE : SOURCE_PHONE), mylink);
2645                         ast_mutex_lock(&myrpt->lock);
2646                         
2647                         switch(res){
2648
2649                                 case DC_INDETERMINATE:
2650                                         break;
2651                                 
2652                                 case DC_DOKEY:
2653                                         mylink->lastrx = 1;
2654                                         break;
2655                                 
2656                                 case DC_REQ_FLUSH:
2657                                         myrpt->rem_dtmfidx = 0;
2658                                         myrpt->rem_dtmfbuf[0] = 0;
2659                                         break;
2660                                 
2661                                 
2662                                 case DC_COMPLETE:
2663                                         myrpt->rem_dtmfbuf[0] = 0;
2664                                         myrpt->rem_dtmfidx = -1;
2665                                         myrpt->rem_dtmf_time = 0;
2666                                         break;
2667                                 
2668                                 case DC_ERROR:
2669                                 default:
2670                                         myrpt->rem_dtmfbuf[0] = 0;
2671                                         myrpt->rem_dtmfidx = -1;
2672                                         myrpt->rem_dtmf_time = 0;
2673                                         break;
2674                         }
2675                 }
2676
2677         }
2678         ast_mutex_unlock(&myrpt->lock);
2679         return;
2680 }
2681
2682 /* Doug Hall RBI-1 serial data definitions:
2683  *
2684  * Byte 0: Expansion external outputs 
2685  * Byte 1: 
2686  *      Bits 0-3 are BAND as follows:
2687  *      Bits 4-5 are POWER bits as follows:
2688  *              00 - Low Power
2689  *              01 - Hi Power
2690  *              02 - Med Power
2691  *      Bits 6-7 are always set
2692  * Byte 2:
2693  *      Bits 0-3 MHZ in BCD format
2694  *      Bits 4-5 are offset as follows:
2695  *              00 - minus
2696  *              01 - plus
2697  *              02 - simplex
2698  *              03 - minus minus (whatever that is)
2699  *      Bit 6 is the 0/5 KHZ bit
2700  *      Bit 7 is always set
2701  * Byte 3:
2702  *      Bits 0-3 are 10 KHZ in BCD format
2703  *      Bits 4-7 are 100 KHZ in BCD format
2704  * Byte 4: PL Tone code and encode/decode enable bits
2705  *      Bits 0-5 are PL tone code (comspec binary codes)
2706  *      Bit 6 is encode enable/disable
2707  *      Bit 7 is decode enable/disable
2708  */
2709
2710 /* take the frequency from the 10 mhz digits (and up) and convert it
2711    to a band number */
2712
2713 static int rbi_mhztoband(char *str)
2714 {
2715 int     i;
2716
2717         i = atoi(str) / 10; /* get the 10's of mhz */
2718         switch(i)
2719         {
2720             case 2:
2721                 return 10;
2722             case 5:
2723                 return 11;
2724             case 14:
2725                 return 2;
2726             case 22:
2727                 return 3;
2728             case 44:
2729                 return 4;
2730             case 124:
2731                 return 0;
2732             case 125:
2733                 return 1;
2734             case 126:
2735                 return 8;
2736             case 127:
2737                 return 5;
2738             case 128:
2739                 return 6;
2740             case 129:
2741                 return 7;
2742             default:
2743                 break;
2744         }
2745         return -1;
2746 }
2747
2748 /* take a PL frequency and turn it into a code */
2749 static int rbi_pltocode(char *str)
2750 {
2751 int i;
2752 char *s;
2753
2754         s = strchr(str,'.');
2755         i = 0;
2756         if (s) i = atoi(s + 1);
2757         i += atoi(str) * 10;
2758         switch(i)
2759         {
2760             case 670:
2761                 return 0;
2762             case 719:
2763                 return 1;
2764             case 744:
2765                 return 2;
2766             case 770:
2767                 return 3;
2768             case 797:
2769                 return 4;
2770             case 825:
2771                 return 5;
2772             case 854:
2773                 return 6;
2774             case 885:
2775                 return 7;
2776             case 915:
2777                 return 8;
2778             case 948:
2779                 return 9;
2780             case 974:
2781                 return 10;
2782             case 1000:
2783                 return 11;
2784             case 1035:
2785                 return 12;
2786             case 1072:
2787                 return 13;
2788             case 1109:
2789                 return 14;
2790             case 1148:
2791                 return 15;
2792             case 1188:
2793                 return 16;
2794             case 1230:
2795                 return 17;
2796             case 1273:
2797                 return 18;
2798             case 1318:
2799                 return 19;
2800             case 1365:
2801                 return 20;
2802             case 1413:
2803                 return 21;
2804             case 1462:
2805                 return 22;
2806             case 1514:
2807                 return 23;
2808             case 1567:
2809                 return 24;
2810             case 1622:
2811                 return 25;
2812             case 1679:
2813                 return 26;
2814             case 1738:
2815                 return 27;
2816             case 1799:
2817                 return 28;
2818             case 1862:
2819                 return 29;
2820             case 1928:
2821                 return 30;
2822             case 2035:
2823                 return 31;
2824             case 2107:
2825                 return 32;
2826             case 2181:
2827                 return 33;
2828             case 2257:
2829                 return 34;
2830             case 2336:
2831                 return 35;
2832             case 2418:
2833                 return 36;
2834             case 2503:
2835                 return 37;
2836         }
2837         return -1;
2838 }
2839
2840 /*
2841 * Shift out a formatted serial bit stream
2842 */
2843
2844 static void rbi_out_parallel(struct rpt *myrpt,unsigned char *data)
2845     {
2846     int i,j;
2847     unsigned char od,d;
2848     static volatile long long delayvar;
2849
2850     for(i = 0 ; i < 5 ; i++){
2851         od = *data++; 
2852         for(j = 0 ; j < 8 ; j++){
2853             d = od & 1;
2854             outb(d,myrpt->iobase);
2855             /* >= 15 us */
2856             for(delayvar = 1; delayvar < 15000; delayvar++); 
2857             od >>= 1;
2858             outb(d | 2,myrpt->iobase);
2859             /* >= 30 us */
2860             for(delayvar = 1; delayvar < 30000; delayvar++); 
2861             outb(d,myrpt->iobase);
2862             /* >= 10 us */
2863             for(delayvar = 1; delayvar < 10000; delayvar++); 
2864             }
2865         }
2866         /* >= 50 us */
2867         for(delayvar = 1; delayvar < 50000; delayvar++); 
2868     }
2869
2870 static void rbi_out(struct rpt *myrpt,unsigned char *data)
2871 {
2872 struct zt_radio_param r;
2873
2874         memset(&r,0,sizeof(struct zt_radio_param));
2875         r.radpar = ZT_RADPAR_REMMODE;
2876         r.data = ZT_RADPAR_REM_RBI1;
2877         /* if setparam ioctl fails, its probably not a pciradio card */
2878         if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&r) == -1)
2879         {
2880                 rbi_out_parallel(myrpt,data);
2881                 return;
2882         }
2883         r.radpar = ZT_RADPAR_REMCOMMAND;
2884         memcpy(&r.data,data,5);
2885         if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&r) == -1)
2886         {
2887                 ast_log(LOG_WARNING,"Cannot send RBI command for channel %s\n",myrpt->rxchannel->name);
2888                 return;
2889         }
2890 }
2891
2892 static int serial_remote_io(struct rpt *myrpt, unsigned char *txbuf, int txbytes, char *rxbuf,
2893         int rxmaxbytes, int asciiflag)
2894 {
2895         int i;
2896         struct zt_radio_param prm;
2897
2898         if(debug){
2899                 printf("String output was: ");
2900                 for(i = 0; i < txbytes; i++)
2901                         printf("%02X ", (unsigned char ) txbuf[i]);
2902                 printf("\n");
2903         }
2904
2905         prm.radpar = ZT_RADPAR_REMMODE;
2906         if (asciiflag)  prm.data = ZT_RADPAR_REM_SERIAL_ASCII;
2907         else prm.data = ZT_RADPAR_REM_SERIAL;
2908         if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&prm) == -1) return -1;
2909         prm.radpar = ZT_RADPAR_REMCOMMAND;
2910         prm.data = rxmaxbytes;
2911         memcpy(prm.buf,txbuf,txbytes);
2912         prm.index = txbytes;
2913         if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&prm) == -1) return -1;
2914         if (rxbuf)
2915         {
2916                 *rxbuf = 0;
2917                 memcpy(rxbuf,prm.buf,prm.index);
2918         }
2919         return(prm.index);
2920 }
2921
2922 static int setrbi(struct rpt *myrpt)
2923 {
2924 char tmp[MAXREMSTR] = "",*s;
2925 unsigned char rbicmd[5];
2926 int     band,txoffset = 0,txpower = 0,txpl;
2927
2928         /* must be a remote system */
2929         if (!myrpt->remote) return(0);
2930         /* must have rbi hardware */
2931         if (strncmp(myrpt->remote,remote_rig_rbi,3)) return(0);
2932         strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
2933         s = strchr(tmp,'.');
2934         /* if no decimal, is invalid */
2935         
2936         if (s == NULL){
2937                 if(debug)
2938                         printf("@@@@ Frequency needs a decimal\n");
2939                 return -1;
2940         }
2941         
2942         *s++ = 0;
2943         if (strlen(tmp) < 2){
2944                 if(debug)
2945                         printf("@@@@ Bad MHz digits: %s\n", tmp);
2946                 return -1;
2947         }
2948          
2949         if (strlen(s) < 3){
2950                 if(debug)
2951                         printf("@@@@ Bad KHz digits: %s\n", s);
2952                 return -1;
2953         }
2954
2955         if ((s[2] != '0') && (s[2] != '5')){
2956                 if(debug)
2957                         printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
2958                 return -1;
2959         }
2960          
2961         band = rbi_mhztoband(tmp);
2962         if (band == -1){
2963                 if(debug)
2964                         printf("@@@@ Bad Band: %s\n", tmp);
2965                 return -1;
2966         }
2967         
2968         txpl = rbi_pltocode(myrpt->txpl);
2969         
2970         if (txpl == -1){
2971                 if(debug)
2972                         printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
2973                 return -1;
2974         }
2975
2976         
2977         switch(myrpt->offset)
2978         {
2979             case REM_MINUS:
2980                 txoffset = 0;
2981                 break;
2982             case REM_PLUS:
2983                 txoffset = 0x10;
2984                 break;
2985             case REM_SIMPLEX:
2986                 txoffset = 0x20;
2987                 break;
2988         }
2989         switch(myrpt->powerlevel)
2990         {
2991             case REM_LOWPWR:
2992                 txpower = 0;
2993                 break;
2994             case REM_MEDPWR:
2995                 txpower = 0x20;
2996                 break;
2997             case REM_HIPWR:
2998                 txpower = 0x10;
2999                 break;
3000         }
3001         rbicmd[0] = 0;
3002         rbicmd[1] = band | txpower | 0xc0;
3003         rbicmd[2] = (*(s - 2) - '0') | txoffset | 0x80;
3004         if (s[2] == '5') rbicmd[2] |= 0x40;
3005         rbicmd[3] = ((*s - '0') << 4) + (s[1] - '0');
3006         rbicmd[4] = txpl;
3007         if (myrpt->txplon) rbicmd[4] |= 0x40;
3008         if (myrpt->rxplon) rbicmd[4] |= 0x80;
3009         rbi_out(myrpt,rbicmd);
3010         return 0;
3011 }
3012
3013
3014 /* Check for valid rbi frequency */
3015 /* Hard coded limits now, configurable later, maybe? */
3016
3017 static int check_freq_rbi(int m, int d, int *defmode)
3018 {
3019         int dflmd = REM_MODE_FM;
3020
3021         if(m == 50){ /* 6 meters */
3022                 if(d < 10100)
3023                         return -1;
3024         }
3025         else if((m >= 51) && ( m < 54)){
3026                 ;
3027         }
3028         else if(m == 144){ /* 2 meters */
3029                 if(d < 10100)
3030                         return -1;
3031         }
3032         else if((m >= 145) && (m < 148)){
3033                 ;
3034         }
3035         else if((m >= 222) && (m < 225)){ /* 1.25 meters */
3036                 ;
3037         }
3038         else if((m >= 430) && (m < 450)){ /* 70 centimeters */
3039                 ;
3040         }
3041         else if((m >= 1240) && (m < 1300)){ /* 23 centimeters */
3042                 ;
3043         }
3044         else
3045                 return -1;
3046         
3047         if(defmode)
3048                 *defmode = dflmd;       
3049
3050
3051         return 0;
3052 }
3053
3054 /*
3055 * Split frequency into mhz and decimals
3056 */
3057  
3058 static int split_freq(char *mhz, char *decimals, char *freq)
3059 {
3060         char freq_copy[MAXREMSTR];
3061         char *decp;
3062
3063         decp = strchr(strncpy(freq_copy, freq, MAXREMSTR),'.');
3064         if(decp){
3065                 *decp++ = 0;
3066                 strncpy(mhz, freq_copy, MAXREMSTR);
3067                 strcpy(decimals, "00000");
3068                 strncpy(decimals, decp, strlen(decp));
3069                 decimals[5] = 0;
3070                 return 0;
3071         }
3072         else
3073                 return -1;
3074
3075 }
3076         
3077 /*
3078 * Split ctcss frequency into hertz and decimal
3079 */
3080  
3081 static int split_ctcss_freq(char *hertz, char *decimal, char *freq)
3082 {
3083         char freq_copy[MAXREMSTR];
3084         char *decp;
3085
3086         decp = strchr(strncpy(freq_copy, freq, MAXREMSTR),'.');
3087         if(decp){
3088                 *decp++ = 0;
3089                 strncpy(hertz, freq_copy, MAXREMSTR);