More memory wrapper and cleanup work. #6226 w/one very minor compile fix mod in...
[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         if (!(mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL)))
1045         {
1046                 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
1047                 ast_mutex_lock(&myrpt->lock);
1048                 remque((struct qelem *)mytele);
1049                 ast_mutex_unlock(&myrpt->lock);
1050                 free(mytele);           
1051                 pthread_exit(NULL);
1052         }
1053         ast_mutex_lock(&myrpt->lock);
1054         mytele->chan = mychannel; /* Save a copy of the channel so we can access it externally if need be */
1055         ast_mutex_unlock(&myrpt->lock);
1056         
1057         /* make a conference for the tx */
1058         ci.chan = 0;
1059         /* If there's an ID queued, only connect the ID audio to the local tx conference so 
1060                 linked systems can't hear it */
1061         ci.confno = (((mytele->mode == ID) || (mytele->mode == IDTALKOVER) || (mytele->mode == UNKEY) || 
1062                 (mytele->mode == TAILMSG)) ?
1063                         myrpt->txconf : myrpt->conf);
1064         ci.confmode = ZT_CONF_CONFANN;
1065         /* first put the channel on the conference in announce mode */
1066         if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
1067         {
1068                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
1069                 ast_mutex_lock(&myrpt->lock);
1070                 remque((struct qelem *)mytele);
1071                 ast_mutex_unlock(&myrpt->lock);
1072                 free(mytele);           
1073                 ast_hangup(mychannel);
1074                 pthread_exit(NULL);
1075         }
1076         ast_stopstream(mychannel);
1077         switch(mytele->mode)
1078         {
1079
1080             case ID:
1081             case ID1:
1082                 /* wait a bit */
1083                 wait_interval(myrpt, (mytele->mode == ID) ? DLY_ID : DLY_TELEM,mychannel);
1084                 res = telem_any(mychannel, ident); 
1085                 imdone=1;       
1086                 break;
1087                 
1088             case TAILMSG:
1089                 res = ast_streamfile(mychannel, myrpt->tailmessages[myrpt->tailmessagen], mychannel->language); 
1090                 break;
1091                 
1092             case IDTALKOVER:
1093                 p = ast_variable_retrieve(cfg, nodename, "idtalkover");
1094                 if(p)
1095                         res = telem_any(mychannel, p); 
1096                 imdone=1;       
1097                 break;
1098                         
1099             case PROC:
1100                 /* wait a little bit longer */
1101                 wait_interval(myrpt, DLY_TELEM, mychannel);
1102                 res = ast_streamfile(mychannel, "rpt/callproceeding", mychannel->language);
1103                 break;
1104             case TERM:
1105                 /* wait a little bit longer */
1106                 wait_interval(myrpt, DLY_CALLTERM, mychannel);
1107                 res = ast_streamfile(mychannel, "rpt/callterminated", mychannel->language);
1108                 break;
1109             case COMPLETE:
1110                 /* wait a little bit */
1111                 wait_interval(myrpt, DLY_TELEM, mychannel);
1112                 res = telem_lookup(mychannel, myrpt->name, "functcomplete");
1113                 break;
1114             case UNKEY:
1115
1116                 /*
1117                 * Reset the Unkey to CT timer
1118                 */
1119
1120                 x = get_wait_interval(myrpt, DLY_UNKEY);
1121                 ast_mutex_lock(&myrpt->lock);
1122                 myrpt->unkeytocttimer = x; /* Must be protected as it is changed below */
1123                 ast_mutex_unlock(&myrpt->lock);
1124
1125                 /*
1126                 * If there's one already queued, don't do another
1127                 */
1128
1129                 tlist = myrpt->tele.next;
1130                 unkeys_queued = 0;
1131                 if (tlist != &myrpt->tele)
1132                 {
1133                         ast_mutex_lock(&myrpt->lock);
1134                         while(tlist != &myrpt->tele){
1135                                 if (tlist->mode == UNKEY) unkeys_queued++;
1136                                 tlist = tlist->next;
1137                         }
1138                         ast_mutex_unlock(&myrpt->lock);
1139                 }
1140                 if( unkeys_queued > 1){
1141                         imdone = 1;
1142                         break;
1143                 }
1144
1145                 /* Wait for the telemetry timer to expire */
1146                 /* Periodically check the timer since it can be re-initialized above */
1147
1148                 while(myrpt->unkeytocttimer)
1149                 {
1150                         int ctint;
1151                         if(myrpt->unkeytocttimer > 100)
1152                                 ctint = 100;
1153                         else
1154                                 ctint = myrpt->unkeytocttimer;
1155                         ast_safe_sleep(mychannel, ctint);
1156                         ast_mutex_lock(&myrpt->lock);
1157                         if(myrpt->unkeytocttimer < ctint)
1158                                 myrpt->unkeytocttimer = 0;
1159                         else
1160                                 myrpt->unkeytocttimer -= ctint;
1161                         ast_mutex_unlock(&myrpt->lock);
1162                 }
1163         
1164
1165                 /*
1166                 * Now, the carrier on the rptr rx should be gone. 
1167                 * If it re-appeared, then forget about sending the CT
1168                 */
1169                 if(myrpt->keyed){
1170                         imdone = 1;
1171                         break;
1172                 }
1173                         
1174                 haslink = 0;
1175                 hastx = 0;
1176                 hasremote = 0;          
1177                 l = myrpt->links.next;
1178                 if (l != &myrpt->links)
1179                 {
1180                         ast_mutex_lock(&myrpt->lock);
1181                         while(l != &myrpt->links)
1182                         {
1183                                 if (l->name[0] == '0')
1184                                 {
1185                                         l = l->next;
1186                                         continue;
1187                                 }
1188                                 haslink = 1;
1189                                 if (l->mode) {
1190                                         hastx++;
1191                                         if (l->isremote) hasremote++;
1192                                 }
1193                                 l = l->next;
1194                         }
1195                         ast_mutex_unlock(&myrpt->lock);
1196                 }
1197                 if (haslink)
1198                 {
1199
1200                         res = telem_lookup(mychannel, myrpt->name, (!hastx) ? "remotemon" : "remotetx");
1201                         if(res)
1202                                 ast_log(LOG_WARNING, "telem_lookup:remotexx failed on %s\n", mychannel->name);
1203                         
1204                 
1205                         /* if in remote cmd mode, indicate it */
1206                         if (myrpt->cmdnode[0])
1207                         {
1208                                 ast_safe_sleep(mychannel,200);
1209                                 res = telem_lookup(mychannel, myrpt->name, "cmdmode");
1210                                 if(res)
1211                                         ast_log(LOG_WARNING, "telem_lookup:cmdmode failed on %s\n", mychannel->name);
1212                                 ast_stopstream(mychannel);
1213                         }
1214                 }
1215                 else if((ct = ast_variable_retrieve(cfg, nodename, "unlinkedct"))){ /* Unlinked Courtesy Tone */
1216                         ct_copy = ast_strdupa(ct);
1217                         res = telem_lookup(mychannel, myrpt->name, ct_copy);
1218                         if(res)
1219                                 ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);               
1220                 }       
1221                         
1222                 if (hasremote && (!myrpt->cmdnode[0]))
1223                 {
1224                         /* set for all to hear */
1225                         ci.chan = 0;
1226                         ci.confno = myrpt->conf;
1227                         ci.confmode = ZT_CONF_CONFANN;
1228                         /* first put the channel on the conference in announce mode */
1229                         if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
1230                         {
1231                                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
1232                                 ast_mutex_lock(&myrpt->lock);
1233                                 remque((struct qelem *)mytele);
1234                                 ast_mutex_unlock(&myrpt->lock);
1235                                 free(mytele);           
1236                                 ast_hangup(mychannel);
1237                                 pthread_exit(NULL);
1238                         }
1239                         if((ct = ast_variable_retrieve(cfg, nodename, "remotect"))){ /* Unlinked Courtesy Tone */
1240                                 ast_safe_sleep(mychannel,200);
1241                                 ct_copy = ast_strdupa(ct);
1242                                 res = telem_lookup(mychannel, myrpt->name, ct_copy);
1243                                 if(res)
1244                                         ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);               
1245                         }       
1246                 }
1247                 imdone = 1;
1248                 break;
1249             case REMDISC:
1250                 /* wait a little bit */
1251                 wait_interval(myrpt, DLY_TELEM, mychannel);
1252                 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
1253                 if (!res) 
1254                         res = ast_waitstream(mychannel, "");
1255                 else
1256                          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1257                 ast_stopstream(mychannel);
1258                 ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
1259                 res = ast_streamfile(mychannel, ((mytele->mylink.connected) ? 
1260                         "rpt/remote_disc" : "rpt/remote_busy"), mychannel->language);
1261                 break;
1262             case REMALREADY:
1263                 /* wait a little bit */
1264                 wait_interval(myrpt, DLY_TELEM, mychannel);
1265                 res = ast_streamfile(mychannel, "rpt/remote_already", mychannel->language);
1266                 break;
1267             case REMNOTFOUND:
1268                 /* wait a little bit */
1269                 wait_interval(myrpt, DLY_TELEM, mychannel);
1270                 res = ast_streamfile(mychannel, "rpt/remote_notfound", mychannel->language);
1271                 break;
1272             case REMGO:
1273                 /* wait a little bit */
1274                 wait_interval(myrpt, DLY_TELEM, mychannel);
1275                 res = ast_streamfile(mychannel, "rpt/remote_go", mychannel->language);
1276                 break;
1277             case CONNECTED:
1278                 /* wait a little bit */
1279                 wait_interval(myrpt, DLY_TELEM,  mychannel);
1280                 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
1281                 if (!res) 
1282                         res = ast_waitstream(mychannel, "");
1283                 else
1284                          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1285                 ast_stopstream(mychannel);
1286                 ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
1287                 res = ast_streamfile(mychannel, "rpt/connected", mychannel->language);
1288                 break;
1289             case CONNFAIL:
1290                 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
1291                 if (!res) 
1292                         res = ast_waitstream(mychannel, "");
1293                 else
1294                          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1295                 ast_stopstream(mychannel);
1296                 ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
1297                 res = ast_streamfile(mychannel, "rpt/connection_failed", mychannel->language);
1298                 break;
1299             case STATUS:
1300                 /* wait a little bit */
1301                 wait_interval(myrpt, DLY_TELEM, mychannel);
1302                 hastx = 0;
1303                 linkbase.next = &linkbase;
1304                 linkbase.prev = &linkbase;
1305                 ast_mutex_lock(&myrpt->lock);
1306                 /* make our own list of links */
1307                 l = myrpt->links.next;
1308                 while(l != &myrpt->links)
1309                 {
1310                         if (l->name[0] == '0')
1311                         {
1312                                 l = l->next;
1313                                 continue;
1314                         }                       
1315                         if (!(m = ast_malloc(sizeof(*m))))
1316                         {
1317                                 ast_mutex_lock(&myrpt->lock);
1318                                 remque((struct qelem *)mytele);
1319                                 ast_mutex_unlock(&myrpt->lock);
1320                                 free(mytele);           
1321                                 ast_hangup(mychannel);
1322                                 pthread_exit(NULL);
1323                         }
1324                         memcpy(m,l,sizeof(struct rpt_link));
1325                         m->next = m->prev = NULL;
1326                         insque((struct qelem *)m,(struct qelem *)linkbase.next);
1327                         l = l->next;
1328                 }
1329                 ast_mutex_unlock(&myrpt->lock);
1330                 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
1331                 if (!res) 
1332                         res = ast_waitstream(mychannel, "");
1333                 else
1334                          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1335                 ast_stopstream(mychannel);
1336                 ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
1337                 if (!res) 
1338                         res = ast_waitstream(mychannel, "");
1339                 else
1340                          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1341                 ast_stopstream(mychannel);
1342                 if (myrpt->callmode)
1343                 {
1344                         hastx = 1;
1345                         res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
1346                         if (!res) 
1347                                 res = ast_waitstream(mychannel, "");
1348                         else
1349                                  ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1350                         ast_stopstream(mychannel);
1351                 }
1352                 l = linkbase.next;
1353                 while(l != &linkbase)
1354                 {
1355                         hastx = 1;
1356                         res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
1357                         if (!res) 
1358                                 res = ast_waitstream(mychannel, "");
1359                         else
1360                                 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1361                         ast_stopstream(mychannel);
1362                         ast_say_character_str(mychannel,l->name,NULL,mychannel->language);
1363                         if (!res) 
1364                                 res = ast_waitstream(mychannel, "");
1365                         else
1366                                  ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1367                         ast_stopstream(mychannel);
1368                         res = ast_streamfile(mychannel, ((l->mode) ? 
1369                                 "rpt/tranceive" : "rpt/monitor"), mychannel->language);
1370                         if (!res) 
1371                                 res = ast_waitstream(mychannel, "");
1372                         else
1373                                 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1374                         ast_stopstream(mychannel);
1375                         l = l->next;
1376                 }                       
1377                 if (!hastx)
1378                 {
1379                         res = ast_streamfile(mychannel, "rpt/repeat_only", mychannel->language);
1380                         if (!res) 
1381                                 res = ast_waitstream(mychannel, "");
1382                         else
1383                                  ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1384                         ast_stopstream(mychannel);
1385                 }
1386                 /* destroy our local link queue */
1387                 l = linkbase.next;
1388                 while(l != &linkbase)
1389                 {
1390                         m = l;
1391                         l = l->next;
1392                         remque((struct qelem *)m);
1393                         free(m);
1394                 }                       
1395                 imdone = 1;
1396                 break;
1397             case TIMEOUT:
1398                 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
1399                 if (!res) 
1400                         res = ast_waitstream(mychannel, "");
1401                 else
1402                          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1403                 ast_stopstream(mychannel);
1404                 ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
1405                 res = ast_streamfile(mychannel, "rpt/timeout", mychannel->language);
1406                 break;
1407                 
1408             case STATS_TIME:
1409                 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
1410                 t = time(NULL);
1411                 localtime_r(&t, &localtm);
1412                 /* Say the phase of the day is before the time */
1413                 if((localtm.tm_hour >= 0) && (localtm.tm_hour < 12))
1414                         p = "rpt/goodmorning";
1415                 else if((localtm.tm_hour >= 12) && (localtm.tm_hour < 18))
1416                         p = "rpt/goodafternoon";
1417                 else
1418                         p = "rpt/goodevening";
1419                 if (sayfile(mychannel,p) == -1)
1420                 {
1421                         imdone = 1;
1422                         break;
1423                 }
1424                 /* Say the time is ... */               
1425                 if (sayfile(mychannel,"rpt/thetimeis") == -1)
1426                 {
1427                         imdone = 1;
1428                         break;
1429                 }
1430                 /* Say the time */                              
1431                 res = ast_say_time(mychannel, t, "", mychannel->language);
1432                 if (!res) 
1433                         res = ast_waitstream(mychannel, "");
1434                 ast_stopstream(mychannel);              
1435                 imdone = 1;
1436                 break;
1437             case STATS_VERSION:
1438                 p = strstr(tdesc, "version");   
1439                 if(!p)
1440                         break;  
1441                 if(sscanf(p, "version %d.%d", &vmajor, &vminor) != 2)
1442                         break;
1443                 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
1444                 /* Say "version" */
1445                 if (sayfile(mychannel,"rpt/version") == -1)
1446                 {
1447                         imdone = 1;
1448                         break;
1449                 }
1450                 if(!res) /* Say "X" */
1451                         ast_say_number(mychannel, vmajor, "", mychannel->language, (char *) NULL);
1452                 if (!res) 
1453                         res = ast_waitstream(mychannel, "");
1454                 ast_stopstream(mychannel);      
1455                 if (saycharstr(mychannel,".") == -1)
1456                 {
1457                         imdone = 1;
1458                         break;
1459                 }
1460                 if(!res) /* Say "Y" */
1461                         ast_say_number(mychannel, vminor, "", mychannel->language, (char *) NULL);
1462                 if (!res){
1463                         res = ast_waitstream(mychannel, "");
1464                         ast_stopstream(mychannel);
1465                 }       
1466                 else
1467                          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1468                 imdone = 1;
1469                 break;
1470             case ARB_ALPHA:
1471                 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
1472                 if(mytele->param)
1473                         saycharstr(mychannel, mytele->param);
1474                 imdone = 1;
1475                 break;
1476             case REV_PATCH:
1477                 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
1478                 if(mytele->param) {
1479
1480                         /* Parts of this section taken from app_parkandannounce */
1481                         char *tpl_working, *tpl_current;
1482                         char *tmp[100], *myparm;
1483                         int looptemp=0,i=0, dres = 0;
1484         
1485
1486                         tpl_working = strdupa(mytele->param);
1487                         myparm = strsep(&tpl_working,",");
1488                         tpl_current=strsep(&tpl_working, ":");
1489
1490                         while(tpl_current && looptemp < sizeof(tmp)) {
1491                                 tmp[looptemp]=tpl_current;
1492                                 looptemp++;
1493                                 tpl_current=strsep(&tpl_working,":");
1494                         }
1495
1496                         for(i=0; i<looptemp; i++) {
1497                                 if(!strcmp(tmp[i], "PARKED")) {
1498                                         ast_say_digits(mychannel, atoi(myparm), "", mychannel->language);
1499                                 } else if(!strcmp(tmp[i], "NODE")) {
1500                                         ast_say_digits(mychannel, atoi(myrpt->name), "", mychannel->language);
1501                                 } else {
1502                                         dres = ast_streamfile(mychannel, tmp[i], mychannel->language);
1503                                         if(!dres) {
1504                                                 dres = ast_waitstream(mychannel, "");
1505                                         } else {
1506                                                 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", tmp[i], mychannel->name);
1507                                                 dres = 0;
1508                                         }
1509                                 }
1510                         }
1511                 }
1512                 imdone = 1;
1513                 break;
1514             case TEST_TONE:
1515                 imdone = 1;
1516                 myrpt->stopgen = 0;
1517                 if ((res = ast_tonepair_start(mychannel, 1004.0, 0, 99999999, 7200.0))) 
1518                         break;
1519                 while(mychannel->generatordata && (!myrpt->stopgen)) {
1520                         if (ast_safe_sleep(mychannel,1)) break;
1521                         imdone = 1;
1522                         }
1523                 break;
1524             default:
1525                 break;
1526         }
1527         myrpt->stopgen = 0;
1528         if (!imdone)
1529         {
1530                 if (!res) 
1531                         res = ast_waitstream(mychannel, "");
1532                 else {
1533                         ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1534                         res = 0;
1535                 }
1536         }
1537         ast_stopstream(mychannel);
1538         ast_mutex_lock(&myrpt->lock);
1539         if (mytele->mode == TAILMSG)
1540         {
1541                 if (!res)
1542                 {
1543                         myrpt->tailmessagen++;
1544                         if(myrpt->tailmessagen >= myrpt->tailmessagemax) myrpt->tailmessagen = 0;
1545                 }
1546                 else
1547                 {
1548                         myrpt->tmsgtimer = myrpt->tailsquashedtime;
1549                 }
1550         }
1551         remque((struct qelem *)mytele);
1552         ast_mutex_unlock(&myrpt->lock);
1553         free(mytele);           
1554         ast_hangup(mychannel);
1555         pthread_exit(NULL);
1556 }
1557
1558 static void rpt_telemetry(struct rpt *myrpt,int mode, void *data)
1559 {
1560 struct rpt_tele *tele;
1561 struct rpt_link *mylink = (struct rpt_link *) data;
1562 pthread_attr_t attr;
1563         
1564         if (!(tele = ast_calloc(1, sizeof(*tele))))
1565         {
1566                 pthread_exit(NULL);
1567                 return;
1568         }
1569         tele->rpt = myrpt;
1570         tele->mode = mode;
1571         ast_mutex_lock(&myrpt->lock);
1572         if((mode == CONNFAIL) || (mode == REMDISC) || (mode == CONNECTED)){
1573                 memset(&tele->mylink,0,sizeof(struct rpt_link));
1574                 if (mylink){
1575                         memcpy(&tele->mylink,mylink,sizeof(struct rpt_link));
1576                 }
1577         }
1578         else if ((mode == ARB_ALPHA) || (mode == REV_PATCH)) {
1579                 strncpy(tele->param, (char *) data, TELEPARAMSIZE - 1);
1580                 tele->param[TELEPARAMSIZE - 1] = 0;
1581         }
1582         insque((struct qelem *)tele,(struct qelem *)myrpt->tele.next); 
1583         ast_mutex_unlock(&myrpt->lock);
1584         pthread_attr_init(&attr);
1585         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1586         ast_pthread_create(&tele->threadid,&attr,rpt_tele_thread,(void *) tele);
1587         return;
1588 }
1589
1590 static void *rpt_call(void *this)
1591 {
1592 ZT_CONFINFO ci;  /* conference info */
1593 struct  rpt *myrpt = (struct rpt *)this;
1594 int     res;
1595 struct  ast_frame wf;
1596 int stopped,congstarted;
1597 struct ast_channel *mychannel,*genchannel;
1598
1599         myrpt->mydtmf = 0;
1600         /* allocate a pseudo-channel thru asterisk */
1601         if (!(mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL)))
1602         {
1603                 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
1604                 pthread_exit(NULL);
1605         }
1606         ci.chan = 0;
1607         ci.confno = myrpt->conf; /* use the pseudo conference */
1608         ci.confmode = ZT_CONF_REALANDPSEUDO | ZT_CONF_TALKER | ZT_CONF_LISTENER
1609                 | ZT_CONF_PSEUDO_TALKER | ZT_CONF_PSEUDO_LISTENER; 
1610         /* first put the channel on the conference */
1611         if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
1612         {
1613                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
1614                 ast_hangup(mychannel);
1615                 myrpt->callmode = 0;
1616                 pthread_exit(NULL);
1617         }
1618         /* allocate a pseudo-channel thru asterisk */
1619         if (!(genchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL)))
1620         {
1621                 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
1622                 ast_hangup(mychannel);
1623                 pthread_exit(NULL);
1624         }
1625         ci.chan = 0;
1626         ci.confno = myrpt->conf;
1627         ci.confmode = ZT_CONF_REALANDPSEUDO | ZT_CONF_TALKER | ZT_CONF_LISTENER
1628                 | ZT_CONF_PSEUDO_TALKER | ZT_CONF_PSEUDO_LISTENER; 
1629         /* first put the channel on the conference */
1630         if (ioctl(genchannel->fds[0],ZT_SETCONF,&ci) == -1)
1631         {
1632                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
1633                 ast_hangup(mychannel);
1634                 ast_hangup(genchannel);
1635                 myrpt->callmode = 0;
1636                 pthread_exit(NULL);
1637         }
1638         if (myrpt->tonezone && (tone_zone_set_zone(mychannel->fds[0],myrpt->tonezone) == -1))
1639         {
1640                 ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->tonezone);
1641                 ast_hangup(mychannel);
1642                 ast_hangup(genchannel);
1643                 myrpt->callmode = 0;
1644                 pthread_exit(NULL);
1645         }
1646         if (myrpt->tonezone && (tone_zone_set_zone(genchannel->fds[0],myrpt->tonezone) == -1))
1647         {
1648                 ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->tonezone);
1649                 ast_hangup(mychannel);
1650                 ast_hangup(genchannel);
1651                 myrpt->callmode = 0;
1652                 pthread_exit(NULL);
1653         }
1654         /* start dialtone */
1655         if (tone_zone_play_tone(mychannel->fds[0],ZT_TONE_DIALTONE) < 0)
1656         {
1657                 ast_log(LOG_WARNING, "Cannot start dialtone\n");
1658                 ast_hangup(mychannel);
1659                 ast_hangup(genchannel);
1660                 myrpt->callmode = 0;
1661                 pthread_exit(NULL);
1662         }
1663         stopped = 0;
1664         congstarted = 0;
1665         while ((myrpt->callmode == 1) || (myrpt->callmode == 4))
1666         {
1667
1668                 if ((myrpt->callmode == 1) && (myrpt->cidx > 0) && (!stopped))
1669                 {
1670                         stopped = 1;
1671                         /* stop dial tone */
1672                         tone_zone_play_tone(mychannel->fds[0],-1);
1673                 }
1674                 if ((myrpt->callmode == 4) && (!congstarted))
1675                 {
1676                         congstarted = 1;
1677                         /* start congestion tone */
1678                         tone_zone_play_tone(mychannel->fds[0],ZT_TONE_CONGESTION);
1679                 }
1680                 res = ast_safe_sleep(mychannel, MSWAIT);
1681                 if (res < 0)
1682                 {
1683                         ast_hangup(mychannel);
1684                         ast_hangup(genchannel);
1685                         ast_mutex_lock(&myrpt->lock);
1686                         myrpt->callmode = 0;
1687                         ast_mutex_unlock(&myrpt->lock);
1688                         pthread_exit(NULL);
1689                 }
1690         }
1691         /* stop any tone generation */
1692         tone_zone_play_tone(mychannel->fds[0],-1);
1693         /* end if done */
1694         if (!myrpt->callmode)
1695         {
1696                 ast_hangup(mychannel);
1697                 ast_hangup(genchannel);
1698                 ast_mutex_lock(&myrpt->lock);
1699                 myrpt->callmode = 0;
1700                 ast_mutex_unlock(&myrpt->lock);
1701                 pthread_exit(NULL);                     
1702         }
1703
1704         if (myrpt->ourcallerid && *myrpt->ourcallerid){
1705                 char *name, *loc, *instr;
1706                 instr = strdup(myrpt->ourcallerid);
1707                 if(instr){
1708                         ast_callerid_parse(instr, &name, &loc);
1709                         if(loc){
1710                                 if(mychannel->cid.cid_num)
1711                                         free(mychannel->cid.cid_num);
1712                                 mychannel->cid.cid_num = strdup(loc);
1713                         }
1714                         if(name){
1715                                 if(mychannel->cid.cid_name)
1716                                         free(mychannel->cid.cid_name);
1717                                 mychannel->cid.cid_name = strdup(name);
1718                         }
1719                         free(instr);
1720                 }
1721         }
1722
1723         strncpy(mychannel->exten, myrpt->exten, sizeof(mychannel->exten) - 1);
1724         strncpy(mychannel->context, myrpt->ourcontext, sizeof(mychannel->context) - 1);
1725         if (myrpt->acctcode)
1726                 strncpy(mychannel->accountcode, myrpt->acctcode, sizeof(mychannel->accountcode) - 1);
1727         mychannel->priority = 1;
1728         ast_channel_undefer_dtmf(mychannel);
1729         if (ast_pbx_start(mychannel) < 0)
1730         {
1731                 ast_log(LOG_WARNING, "Unable to start PBX!!\n");
1732                 ast_hangup(mychannel);
1733                 ast_hangup(genchannel);
1734                 ast_mutex_lock(&myrpt->lock);
1735                 myrpt->callmode = 0;
1736                 ast_mutex_unlock(&myrpt->lock);
1737                 pthread_exit(NULL);
1738         }
1739         usleep(10000);
1740         ast_mutex_lock(&myrpt->lock);
1741         myrpt->callmode = 3;
1742         while(myrpt->callmode)
1743         {
1744                 if ((!mychannel->pbx) && (myrpt->callmode != 4))
1745                 {
1746                         myrpt->callmode = 4;
1747                         ast_mutex_unlock(&myrpt->lock);
1748                         /* start congestion tone */
1749                         tone_zone_play_tone(genchannel->fds[0],ZT_TONE_CONGESTION);
1750                         ast_mutex_lock(&myrpt->lock);
1751                 }
1752                 if (myrpt->mydtmf)
1753                 {
1754                         wf.frametype = AST_FRAME_DTMF;
1755                         wf.subclass = myrpt->mydtmf;
1756                         wf.offset = 0;
1757                         wf.mallocd = 0;
1758                         wf.data = NULL;
1759                         wf.datalen = 0;
1760                         wf.samples = 0;
1761                         ast_mutex_unlock(&myrpt->lock);
1762                         ast_write(genchannel,&wf); 
1763                         ast_mutex_lock(&myrpt->lock);
1764                         myrpt->mydtmf = 0;
1765                 }
1766                 ast_mutex_unlock(&myrpt->lock);
1767                 usleep(MSWAIT * 1000);
1768                 ast_mutex_lock(&myrpt->lock);
1769         }
1770         ast_mutex_unlock(&myrpt->lock);
1771         tone_zone_play_tone(genchannel->fds[0],-1);
1772         if (mychannel->pbx) ast_softhangup(mychannel,AST_SOFTHANGUP_DEV);
1773         ast_hangup(genchannel);
1774         ast_mutex_lock(&myrpt->lock);
1775         myrpt->callmode = 0;
1776         ast_mutex_unlock(&myrpt->lock);
1777         pthread_exit(NULL);
1778 }
1779
1780 static void send_link_dtmf(struct rpt *myrpt,char c)
1781 {
1782 char    str[300];
1783 struct  ast_frame wf;
1784 struct  rpt_link *l;
1785
1786         snprintf(str, sizeof(str), "D %s %s %d %c", myrpt->cmdnode, myrpt->name, ++(myrpt->dtmfidx), c);
1787         wf.frametype = AST_FRAME_TEXT;
1788         wf.subclass = 0;
1789         wf.offset = 0;
1790         wf.mallocd = 1;
1791         wf.datalen = strlen(str) + 1;
1792         wf.samples = 0;
1793         l = myrpt->links.next;
1794         /* first, see if our dude is there */
1795         while(l != &myrpt->links)
1796         {
1797                 if (l->name[0] == '0') 
1798                 {
1799                         l = l->next;
1800                         continue;
1801                 }
1802                 /* if we found it, write it and were done */
1803                 if (!strcmp(l->name,myrpt->cmdnode))
1804                 {
1805                         wf.data = strdup(str);
1806                         if (l->chan) ast_write(l->chan,&wf);
1807                         return;
1808                 }
1809                 l = l->next;
1810         }
1811         l = myrpt->links.next;
1812         /* if not, give it to everyone */
1813         while(l != &myrpt->links)
1814         {
1815                 wf.data = strdup(str);
1816                 if (l->chan) ast_write(l->chan,&wf);
1817                 l = l->next;
1818         }
1819         return;
1820 }
1821
1822 /*
1823 * Internet linking function 
1824 */
1825
1826 static int function_ilink(struct rpt *myrpt, char *param, char *digits, int command_source, struct rpt_link *mylink)
1827 {
1828
1829         char *val, *s, *s1, *s2, *tele;
1830         char tmp[300], deststr[300] = "",modechange = 0;
1831         char digitbuf[MAXNODESTR];
1832         struct rpt_link *l;
1833         ZT_CONFINFO ci;  /* conference info */
1834
1835         if(!param)
1836                 return DC_ERROR;
1837                 
1838                         
1839         if (!myrpt->enable)
1840                 return DC_ERROR;
1841
1842         strncpy(digitbuf,digits,MAXNODESTR - 1);
1843
1844         if(debug)
1845                 printf("@@@@ ilink param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
1846                 
1847         switch(myatoi(param)){
1848                 case 1: /* Link off */
1849                         if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
1850                                 strcpy(digitbuf,myrpt->lastlinknode);
1851                         val = ast_variable_retrieve(cfg, myrpt->nodes, digitbuf);
1852                         if (!val){
1853                                 if(strlen(digitbuf) >= myrpt->longestnode)
1854                                         return DC_ERROR;
1855                                 break;
1856                         }
1857                         strncpy(tmp,val,sizeof(tmp) - 1);
1858                         s = tmp;
1859                         s1 = strsep(&s,",");
1860                         s2 = strsep(&s,",");
1861                         ast_mutex_lock(&myrpt->lock);
1862                         l = myrpt->links.next;
1863                         /* try to find this one in queue */
1864                         while(l != &myrpt->links){
1865                                 if (l->name[0] == '0') 
1866                                 {
1867                                         l = l->next;
1868                                         continue;
1869                                 }
1870                                 /* if found matching string */
1871                                 if (!strcmp(l->name, digitbuf))
1872                                         break;
1873                                 l = l->next;
1874                         }
1875                         if (l != &myrpt->links){ /* if found */
1876                                 struct  ast_frame wf;
1877
1878                                 strncpy(myrpt->lastlinknode,digitbuf,MAXNODESTR - 1);
1879                                 l->retries = MAX_RETRIES + 1;
1880                                 l->disced = 1;
1881                                 ast_mutex_unlock(&myrpt->lock);
1882                                 wf.frametype = AST_FRAME_TEXT;
1883                                 wf.subclass = 0;
1884                                 wf.offset = 0;
1885                                 wf.mallocd = 1;
1886                                 wf.datalen = strlen(discstr) + 1;
1887                                 wf.samples = 0;
1888                                 wf.data = strdup(discstr);
1889                                 if (l->chan)
1890                                 {
1891                                         ast_write(l->chan,&wf);
1892                                         if (ast_safe_sleep(l->chan,250) == -1) return DC_ERROR;
1893                                         ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
1894                                 }
1895                                 rpt_telemetry(myrpt, COMPLETE, NULL);
1896                                 return DC_COMPLETE;
1897                         }
1898                         ast_mutex_unlock(&myrpt->lock); 
1899                         return DC_COMPLETE;
1900                 case 2: /* Link Monitor */
1901                         if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
1902                                 strcpy(digitbuf,myrpt->lastlinknode);
1903                         val = ast_variable_retrieve(cfg, myrpt->nodes, digitbuf);
1904                         if (!val){
1905                                 if(strlen(digitbuf) >= myrpt->longestnode)
1906                                         return DC_ERROR;
1907                                 break;
1908                         }
1909                         strncpy(tmp,val,sizeof(tmp) - 1);
1910                         s = tmp;
1911                         s1 = strsep(&s,",");
1912                         s2 = strsep(&s,",");
1913                         ast_mutex_lock(&myrpt->lock);
1914                         l = myrpt->links.next;
1915                         /* try to find this one in queue */
1916                         while(l != &myrpt->links){
1917                                 if (l->name[0] == '0') 
1918                                 {
1919                                         l = l->next;
1920                                         continue;
1921                                 }
1922                                 /* if found matching string */
1923                                 if (!strcmp(l->name, digitbuf))
1924                                         break;
1925                                 l = l->next;
1926                         }
1927                         /* if found */
1928                         if (l != &myrpt->links) 
1929                         {
1930                                 /* if already in this mode, just ignore */
1931                                 if ((!l->mode) || (!l->chan)) {
1932                                         ast_mutex_unlock(&myrpt->lock);
1933                                         rpt_telemetry(myrpt,REMALREADY,NULL);
1934                                         return DC_COMPLETE;
1935                                         
1936                                 }
1937                                 ast_mutex_unlock(&myrpt->lock);
1938                                 if (l->chan) ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
1939                                 l->retries = MAX_RETRIES + 1;
1940                                 l->disced = 2;
1941                                 modechange = 1;
1942                         } else
1943                                 ast_mutex_unlock(&myrpt->lock);
1944                         strncpy(myrpt->lastlinknode,digitbuf,MAXNODESTR - 1);
1945                         /* establish call in monitor mode */                    
1946                         if (!(l = ast_calloc(1, sizeof(*l)))) {
1947                                 return DC_ERROR;
1948                         }
1949                         /* zero the silly thing */
1950                         snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
1951                         tele = strchr(deststr,'/');
1952                         if (!tele){
1953                                 fprintf(stderr,"link2:Dial number (%s) must be in format tech/number\n",deststr);
1954                                 return DC_ERROR;
1955                         }
1956                         *tele++ = 0;
1957                         l->isremote = (s && ast_true(s));
1958                         strncpy(l->name, digitbuf, MAXNODESTR - 1);
1959                         l->chan = ast_request(deststr,AST_FORMAT_SLINEAR,tele,NULL);
1960                         if (modechange) l->connected = 1;
1961                         if (l->chan){
1962                                 ast_set_read_format(l->chan,AST_FORMAT_SLINEAR);
1963                                 ast_set_write_format(l->chan,AST_FORMAT_SLINEAR);
1964                                 l->chan->whentohangup = 0;
1965                                 l->chan->appl = "Apprpt";
1966                                 l->chan->data = "(Remote Rx)";
1967                                 if (option_verbose > 2)
1968                                         ast_verbose(VERBOSE_PREFIX_3 "rpt (remote) initiating call to %s/%s on %s\n",
1969                                                 deststr,tele,l->chan->name);
1970                                 if(l->chan->cid.cid_num)
1971                                         free(l->chan->cid.cid_num);
1972                                 l->chan->cid.cid_num = strdup(myrpt->name);
1973                                 ast_call(l->chan,tele,0);
1974                         }
1975                         else
1976                         {
1977                                 rpt_telemetry(myrpt,CONNFAIL,l);
1978                                 free(l);
1979                                 if (option_verbose > 2)
1980                                         ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
1981                                                 deststr,tele,l->chan->name);
1982                                 return DC_ERROR;
1983                         }
1984                         /* allocate a pseudo-channel thru asterisk */
1985                         if (!(l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL))) {
1986                                 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
1987                                 ast_hangup(l->chan);
1988                                 free(l);
1989                                 return DC_ERROR;
1990                         }
1991                         ast_set_read_format(l->pchan,AST_FORMAT_SLINEAR);
1992                         ast_set_write_format(l->pchan,AST_FORMAT_SLINEAR);
1993                         /* make a conference for the pseudo-one */
1994                         ci.chan = 0;
1995                         ci.confno = myrpt->conf;
1996                         ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER;
1997                         /* first put the channel on the conference in proper mode */
1998                         if (ioctl(l->pchan->fds[0],ZT_SETCONF,&ci) == -1)
1999                         {
2000                                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2001                                 ast_hangup(l->chan);
2002                                 ast_hangup(l->pchan);
2003                                 free(l);
2004                                 return DC_ERROR;
2005                         }
2006                         ast_mutex_lock(&myrpt->lock);
2007                         /* insert at end of queue */
2008                         insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
2009                         ast_mutex_unlock(&myrpt->lock);
2010                         rpt_telemetry(myrpt,COMPLETE,NULL);
2011                         return DC_COMPLETE;
2012                 case 3: /* Link transceive */
2013                         if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
2014                                 strcpy(digitbuf,myrpt->lastlinknode);
2015                         val = ast_variable_retrieve(cfg, myrpt->nodes, digitbuf);
2016                         if (!val){
2017                                 if(strlen(digitbuf) >= myrpt->longestnode)
2018                                         return DC_ERROR;
2019                                 break;
2020                         }
2021                         strncpy(tmp,val,sizeof(tmp) - 1);
2022                         s = tmp;
2023                         s1 = strsep(&s,",");
2024                         s2 = strsep(&s,",");
2025                         ast_mutex_lock(&myrpt->lock);
2026                         l = myrpt->links.next;
2027                         /* try to find this one in queue */
2028                         while(l != &myrpt->links){
2029                                 if (l->name[0] == '0') 
2030                                 {
2031                                         l = l->next;
2032                                         continue;
2033                                 }
2034                                 /* if found matching string */
2035                                 if (!strcmp(l->name, digitbuf))
2036                                         break;
2037                                 l = l->next;
2038                         }
2039                         /* if found */
2040                         if (l != &myrpt->links){ 
2041                                 /* if already in this mode, just ignore */
2042                                 if ((l->mode) || (!l->chan)) {
2043                                         ast_mutex_unlock(&myrpt->lock);
2044                                         rpt_telemetry(myrpt, REMALREADY, NULL);
2045                                         return DC_COMPLETE;
2046                                 }
2047                                 ast_mutex_unlock(&myrpt->lock);
2048                                 if (l->chan) ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
2049                                 l->retries = MAX_RETRIES + 1;
2050                                 l->disced = 2;
2051                                 modechange = 1;
2052                         } else
2053                                 ast_mutex_unlock(&myrpt->lock);
2054                         strncpy(myrpt->lastlinknode,digitbuf,MAXNODESTR - 1);
2055                         /* establish call in tranceive mode */
2056                         if (!(l = ast_calloc(1, sizeof(*l)))) {
2057                                 return(DC_ERROR);
2058                         }
2059                         l->mode = 1;
2060                         l->outbound = 1;
2061                         strncpy(l->name, digitbuf, MAXNODESTR - 1);
2062                         l->isremote = (s && ast_true(s));
2063                         if (modechange) l->connected = 1;
2064                         snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
2065                         tele = strchr(deststr, '/');
2066                         if (!tele){
2067                                 fprintf(stderr,"link3:Dial number (%s) must be in format tech/number\n",deststr);
2068                                 free(l);
2069                                 return DC_ERROR;
2070                         }
2071                         *tele++ = 0;
2072                         l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele,NULL);
2073                         if (l->chan){
2074                                 ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
2075                                 ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
2076                                 l->chan->whentohangup = 0;
2077                                 l->chan->appl = "Apprpt";
2078                                 l->chan->data = "(Remote Rx)";
2079                                 if (option_verbose > 2)
2080                                         ast_verbose(VERBOSE_PREFIX_3 "rpt (remote) initiating call to %s/%s on %s\n",
2081                                                 deststr, tele, l->chan->name);
2082                                 if(l->chan->cid.cid_num)
2083                                         free(l->chan->cid.cid_num);
2084                                 l->chan->cid.cid_num = strdup(myrpt->name);
2085                                 ast_call(l->chan,tele,999);
2086                         }
2087                         else{
2088                                 rpt_telemetry(myrpt,CONNFAIL,l);
2089                                 free(l);
2090                                 if (option_verbose > 2)
2091                                         ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
2092                                                 deststr,tele,l->chan->name);
2093                                 return DC_ERROR;
2094                         }
2095                         /* allocate a pseudo-channel thru asterisk */
2096                         if (!(l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL))) {
2097                                 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
2098                                 ast_hangup(l->chan);
2099                                 free(l);
2100                                 return DC_ERROR;
2101                         }
2102                         ast_set_read_format(l->pchan, AST_FORMAT_SLINEAR);
2103                         ast_set_write_format(l->pchan, AST_FORMAT_SLINEAR);
2104                         /* make a conference for the tx */
2105                         ci.chan = 0;
2106                         ci.confno = myrpt->conf;
2107                         ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER;
2108                         /* first put the channel on the conference in proper mode */
2109                         if (ioctl(l->pchan->fds[0], ZT_SETCONF, &ci) == -1)
2110                         {
2111                                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2112                                 ast_hangup(l->chan);
2113                                 ast_hangup(l->pchan);
2114                                 free(l);
2115                                 return DC_ERROR;
2116                         }
2117                         ast_mutex_lock(&myrpt->lock);
2118                         /* insert at end of queue */
2119                         insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
2120                         ast_mutex_unlock(&myrpt->lock);
2121                         rpt_telemetry(myrpt,COMPLETE,NULL);
2122                         return DC_COMPLETE;
2123                 case 4: /* Enter Command Mode */
2124                 
2125                         /* if doesnt allow link cmd, or no links active, return */
2126                         if (((command_source != SOURCE_RPT) && (command_source != SOURCE_PHONE) && (command_source != SOURCE_DPHONE)) || (myrpt->links.next == &myrpt->links))
2127                                 return DC_COMPLETE;
2128                         
2129                         /* if already in cmd mode, or selected self, fughetabahtit */
2130                         if ((myrpt->cmdnode[0]) || (!strcmp(myrpt->name, digitbuf))){
2131                         
2132                                 rpt_telemetry(myrpt, REMALREADY, NULL);
2133                                 return DC_COMPLETE;
2134                         }
2135                         if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
2136                                 strcpy(digitbuf,myrpt->lastlinknode);
2137                         /* node must at least exist in list */
2138                         val = ast_variable_retrieve(cfg, myrpt->nodes, digitbuf);
2139                         if (!val){
2140                                 if(strlen(digitbuf) >= myrpt->longestnode)
2141                                         return DC_ERROR;
2142                                 break;
2143                         
2144                         }
2145                         ast_mutex_lock(&myrpt->lock);
2146                         strcpy(myrpt->lastlinknode,digitbuf);
2147                         strncpy(myrpt->cmdnode, digitbuf, sizeof(myrpt->cmdnode) - 1);
2148                         ast_mutex_unlock(&myrpt->lock);
2149                         rpt_telemetry(myrpt, REMGO, NULL);      
2150                         return DC_COMPLETE;
2151                         
2152                 case 5: /* Status */
2153                         rpt_telemetry(myrpt, STATUS, NULL);
2154                         return DC_COMPLETE;
2155                         
2156                         
2157                 case 6: /* All Links Off */
2158                         l = myrpt->links.next;
2159                         
2160                         while(l != &myrpt->links){
2161                                 if (l->chan) ast_softhangup(l->chan, AST_SOFTHANGUP_DEV); /* Hang 'em up */
2162                                 l = l->next;
2163                         }
2164                         rpt_telemetry(myrpt, COMPLETE, NULL);
2165                         break;
2166         
2167                 default:
2168                         return DC_ERROR;
2169                         
2170         }
2171         
2172         return DC_INDETERMINATE;
2173 }       
2174
2175 /*
2176 * Autopatch up
2177 */
2178
2179 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
2180 {
2181         pthread_attr_t attr;
2182         
2183                 
2184         if (!myrpt->enable)
2185                 return DC_ERROR;
2186                 
2187         if(debug)
2188                 printf("@@@@ Autopatch up\n");
2189
2190         ast_mutex_lock(&myrpt->lock);
2191         
2192         /* if on call, force * into current audio stream */
2193         
2194         if ((myrpt->callmode == 2) || (myrpt->callmode == 3)){
2195                 myrpt->mydtmf = myrpt->funcchar;
2196         }
2197         if (myrpt->callmode){
2198                 ast_mutex_unlock(&myrpt->lock);
2199                 return DC_COMPLETE;
2200         }
2201         myrpt->callmode = 1;
2202         myrpt->cidx = 0;
2203         myrpt->exten[myrpt->cidx] = 0;
2204         ast_mutex_unlock(&myrpt->lock);
2205         pthread_attr_init(&attr);
2206         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2207         ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *) myrpt);
2208         return DC_COMPLETE;
2209 }
2210
2211 /*
2212 * Autopatch down
2213 */
2214
2215 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
2216 {
2217         if (!myrpt->enable)
2218                 return DC_ERROR;
2219         
2220         if(debug)
2221                 printf("@@@@ Autopatch down\n");
2222                 
2223         ast_mutex_lock(&myrpt->lock);
2224         
2225         if (!myrpt->callmode){
2226                 ast_mutex_unlock(&myrpt->lock);
2227                 return DC_COMPLETE;
2228         }
2229         
2230         myrpt->callmode = 0;
2231         ast_mutex_unlock(&myrpt->lock);
2232         rpt_telemetry(myrpt, TERM, NULL);
2233         return DC_COMPLETE;
2234 }
2235
2236 /*
2237 * Status
2238 */
2239
2240 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
2241 {
2242
2243         if(!param)
2244                 return DC_ERROR;
2245                 
2246                         
2247         if (!myrpt->enable)
2248                 return DC_ERROR;
2249
2250         if(debug)
2251                 printf("@@@@ status param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
2252         
2253         switch(myatoi(param)){
2254                 case 1: /* System ID */
2255                         rpt_telemetry(myrpt, ID1, NULL);
2256                         return DC_COMPLETE;
2257                 case 2: /* System Time */
2258                         rpt_telemetry(myrpt, STATS_TIME, NULL);
2259                         return DC_COMPLETE;
2260                 case 3: /* app_rpt.c version */
2261                         rpt_telemetry(myrpt, STATS_VERSION, NULL);
2262                 default:
2263                         return DC_ERROR;
2264         }
2265         return DC_INDETERMINATE;
2266 }
2267
2268 /*
2269 * COP - Control operator
2270 */
2271
2272 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
2273 {
2274         if(!param)
2275                 return DC_ERROR;
2276         
2277         switch(myatoi(param)){
2278                 case 1: /* System reset */
2279                         system("killall -9 asterisk"); /* FIXME to drastic? */
2280                         return DC_COMPLETE;
2281
2282                 case 2:
2283                         myrpt->enable = 1;
2284                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "RPTENA");
2285                         return DC_COMPLETE;
2286                         
2287                 case 3:
2288                         myrpt->enable = 0;
2289                         return DC_COMPLETE;
2290                         
2291                 case 4: /* test tone on */
2292                         rpt_telemetry(myrpt, TEST_TONE, NULL);
2293                         return DC_COMPLETE;
2294
2295                 case 5: /* Disgorge variables to log for debug purposes */
2296                         myrpt->disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
2297                         return DC_COMPLETE;
2298
2299                 case 6: /* Simulate COR being activated (phone only) */
2300                         if (command_source != SOURCE_PHONE) return DC_INDETERMINATE;
2301                         return DC_DOKEY;        
2302
2303         }       
2304         return DC_INDETERMINATE;
2305 }
2306
2307 /*
2308 * Collect digits one by one until something matches
2309 */
2310
2311 static int collect_function_digits(struct rpt *myrpt, char *digits, 
2312         int command_source, struct rpt_link *mylink)
2313 {
2314         int i;
2315         char *stringp,*action,*param,*functiondigits;
2316         char function_table_name[30] = "";
2317         char workstring[80];
2318         
2319         struct ast_variable *vp;
2320         
2321         if(debug)       
2322                 printf("@@@@ Digits collected: %s, source: %d\n", digits, command_source);
2323         
2324         if (command_source == SOURCE_DPHONE) {
2325                 if (!myrpt->dphone_functions) return DC_INDETERMINATE;
2326                 strncpy(function_table_name, myrpt->dphone_functions, sizeof(function_table_name) - 1);
2327                 }
2328         else if (command_source == SOURCE_PHONE) {
2329                 if (!myrpt->phone_functions) return DC_INDETERMINATE;
2330                 strncpy(function_table_name, myrpt->phone_functions, sizeof(function_table_name) - 1);
2331                 }
2332         else if (command_source == SOURCE_LNK)
2333                 strncpy(function_table_name, myrpt->link_functions, sizeof(function_table_name) - 1);
2334         else
2335                 strncpy(function_table_name, myrpt->functions, sizeof(function_table_name) - 1);
2336         vp = ast_variable_browse(cfg, function_table_name);
2337         while(vp) {
2338                 if(!strncasecmp(vp->name, digits, strlen(vp->name)))
2339                         break;
2340                 vp = vp->next;
2341         }       
2342         if(!vp) {
2343                 int n;
2344
2345                 n = myrpt->longestfunc;
2346                 if (command_source == SOURCE_LNK) n = myrpt->link_longestfunc;
2347                 else 
2348                 if (command_source == SOURCE_PHONE) n = myrpt->phone_longestfunc;
2349                 else 
2350                 if (command_source == SOURCE_DPHONE) n = myrpt->dphone_longestfunc;
2351                 
2352                 if(strlen(digits) >= n)
2353                         return DC_ERROR;
2354                 else
2355                         return DC_INDETERMINATE;
2356         }       
2357         /* Found a match, retrieve value part and parse */
2358         strncpy(workstring, vp->value, sizeof(workstring) - 1 );
2359         stringp = workstring;
2360         action = strsep(&stringp, ",");
2361         param = stringp;
2362         if(debug)
2363                 printf("@@@@ action: %s, param = %s\n",action, (param) ? param : "(null)");
2364         /* Look up the action */
2365         for(i = 0 ; i < (sizeof(function_table)/sizeof(struct function_table_tag)); i++){
2366                 if(!strncasecmp(action, function_table[i].action, strlen(action)))
2367                         break;
2368         }
2369         if(debug)
2370                 printf("@@@@ table index i = %d\n",i);
2371         if(i == (sizeof(function_table)/sizeof(struct function_table_tag))){
2372                 /* Error, action not in table */
2373                 return DC_ERROR;
2374         }
2375         if(function_table[i].function == NULL){
2376                 /* Error, function undefined */
2377                 if(debug)
2378                         printf("@@@@ NULL for action: %s\n",action);
2379                 return DC_ERROR;
2380         }
2381         functiondigits = digits + strlen(vp->name);
2382         return (*function_table[i].function)(myrpt, param, functiondigits, command_source, mylink);
2383 }
2384
2385
2386 static void handle_link_data(struct rpt *myrpt, struct rpt_link *mylink,
2387         char *str)
2388 {
2389 char    tmp[300],cmd[300] = "",dest[300],src[300],c;
2390 int     seq, res;
2391 struct rpt_link *l;
2392 struct  ast_frame wf;
2393
2394         wf.frametype = AST_FRAME_TEXT;
2395         wf.subclass = 0;
2396         wf.offset = 0;
2397         wf.mallocd = 1;
2398         wf.datalen = strlen(str) + 1;
2399         wf.samples = 0;
2400         /* put string in our buffer */
2401         strncpy(tmp,str,sizeof(tmp) - 1);
2402
2403         if (!strcmp(tmp,discstr))
2404         {
2405                 mylink->disced = 1;
2406                 mylink->retries = MAX_RETRIES + 1;
2407                 ast_softhangup(mylink->chan,AST_SOFTHANGUP_DEV);
2408                 return;
2409         }
2410         if (sscanf(tmp,"%s %s %s %d %c",cmd,dest,src,&seq,&c) != 5)
2411         {
2412                 ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
2413                 return;
2414         }
2415         if (strcmp(cmd,"D"))
2416         {
2417                 ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
2418                 return;
2419         }
2420
2421         if (dest[0] == '0')
2422         {
2423                 strcpy(dest,myrpt->name);
2424         }               
2425
2426         /* if not for me, redistribute to all links */
2427         if (strcmp(dest,myrpt->name))
2428         {
2429                 l = myrpt->links.next;
2430                 /* see if this is one in list */
2431                 while(l != &myrpt->links)
2432                 {
2433                         if (l->name[0] == '0') 
2434                         {
2435                                 l = l->next;
2436                                 continue;
2437                         }
2438                         /* dont send back from where it came */
2439                         if ((l == mylink) || (!strcmp(l->name,mylink->name)))
2440                         {
2441                                 l = l->next;
2442                                 continue;
2443                         }
2444                         /* if it is, send it and we're done */
2445                         if (!strcmp(l->name,dest))
2446                         {
2447                                 /* send, but not to src */
2448                                 if (strcmp(l->name,src)) {
2449                                         wf.data = strdup(str);
2450                                         if (l->chan) ast_write(l->chan,&wf);
2451                                 }
2452                                 return;
2453                         }
2454                         l = l->next;
2455                 }
2456                 l = myrpt->links.next;
2457                 /* otherwise, send it to all of em */
2458                 while(l != &myrpt->links)
2459                 {
2460                         if (l->name[0] == '0') 
2461                         {
2462                                 l = l->next;
2463                                 continue;
2464                         }
2465                         /* dont send back from where it came */
2466                         if ((l == mylink) || (!strcmp(l->name,mylink->name)))
2467                         {
2468                                 l = l->next;
2469                                 continue;
2470                         }
2471                         /* send, but not to src */
2472                         if (strcmp(l->name,src)) {
2473                                 wf.data = strdup(str);
2474                                 if (l->chan) ast_write(l->chan,&wf);
2475                         }
2476                         l = l->next;
2477                 }
2478                 return;
2479         }
2480         ast_mutex_lock(&myrpt->lock);
2481         if (c == myrpt->endchar) myrpt->stopgen = 1;
2482         if (myrpt->callmode == 1)
2483         {
2484                 myrpt->exten[myrpt->cidx++] = c;
2485                 myrpt->exten[myrpt->cidx] = 0;
2486                 /* if this exists */
2487                 if (ast_exists_extension(myrpt->pchannel,myrpt->ourcontext,myrpt->exten,1,NULL))
2488                 {
2489                         myrpt->callmode = 2;
2490                         rpt_telemetry(myrpt,PROC,NULL); 
2491                 }
2492                 /* if can continue, do so */
2493                 if (!ast_canmatch_extension(myrpt->pchannel,myrpt->ourcontext,myrpt->exten,1,NULL)) 
2494                 {
2495                         /* call has failed, inform user */
2496                         myrpt->callmode = 4;
2497                 }
2498         }
2499         if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
2500         {
2501                 myrpt->mydtmf = c;
2502         }
2503         if (c == myrpt->funcchar)
2504         {
2505                 myrpt->rem_dtmfidx = 0;
2506                 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
2507                 time(&myrpt->rem_dtmf_time);
2508                 ast_mutex_unlock(&myrpt->lock);
2509                 return;
2510         } 
2511         else if ((c != myrpt->endchar) && (myrpt->rem_dtmfidx >= 0))
2512         {
2513                 time(&myrpt->rem_dtmf_time);
2514                 if (myrpt->rem_dtmfidx < MAXDTMF)
2515                 {
2516                         myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
2517                         myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
2518                         
2519                         ast_mutex_unlock(&myrpt->lock);
2520                         strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1);
2521                         res = collect_function_digits(myrpt, cmd, SOURCE_LNK, mylink);
2522                         ast_mutex_lock(&myrpt->lock);
2523                         
2524                         switch(res){
2525
2526                                 case DC_INDETERMINATE:
2527                                         break;
2528                                 
2529                                 case DC_REQ_FLUSH:
2530                                         myrpt->rem_dtmfidx = 0;
2531                                         myrpt->rem_dtmfbuf[0] = 0;
2532                                         break;
2533                                 
2534                                 
2535                                 case DC_COMPLETE:
2536                                         myrpt->rem_dtmfbuf[0] = 0;
2537                                         myrpt->rem_dtmfidx = -1;
2538                                         myrpt->rem_dtmf_time = 0;
2539                                         break;
2540                                 
2541                                 case DC_ERROR:
2542                                 default:
2543                                         myrpt->rem_dtmfbuf[0] = 0;
2544                                         myrpt->rem_dtmfidx = -1;
2545                                         myrpt->rem_dtmf_time = 0;
2546                                         break;
2547                         }
2548                 }
2549
2550         }
2551         ast_mutex_unlock(&myrpt->lock);
2552         return;
2553 }
2554
2555 static void handle_link_phone_dtmf(struct rpt *myrpt, struct rpt_link *mylink,
2556         char c)
2557 {
2558
2559 char    cmd[300];
2560 int     res;
2561
2562         ast_mutex_lock(&myrpt->lock);
2563         if (c == myrpt->endchar)
2564         {
2565                 if (mylink->lastrx)
2566                 {
2567                         mylink->lastrx = 0;
2568                         ast_mutex_unlock(&myrpt->lock);
2569                         return;
2570                 }
2571                 myrpt->stopgen = 1;
2572                 if (myrpt->cmdnode[0])
2573                 {
2574                         myrpt->cmdnode[0] = 0;
2575                         myrpt->dtmfidx = -1;
2576                         myrpt->dtmfbuf[0] = 0;
2577                         ast_mutex_unlock(&myrpt->lock);
2578                         rpt_telemetry(myrpt,COMPLETE,NULL);
2579                         ast_mutex_unlock(&myrpt->lock);
2580                         return;
2581                 }
2582         }
2583         if (myrpt->cmdnode[0])
2584         {
2585                 ast_mutex_unlock(&myrpt->lock);
2586                 send_link_dtmf(myrpt,c);
2587                 return;
2588         }
2589         if (myrpt->callmode == 1)
2590         {
2591                 myrpt->exten[myrpt->cidx++] = c;
2592                 myrpt->exten[myrpt->cidx] = 0;
2593                 /* if this exists */
2594                 if (ast_exists_extension(myrpt->pchannel,myrpt->ourcontext,myrpt->exten,1,NULL))
2595                 {
2596                         myrpt->callmode = 2;
2597                         rpt_telemetry(myrpt,PROC,NULL); 
2598                 }
2599                 /* if can continue, do so */
2600                 if (!ast_canmatch_extension(myrpt->pchannel,myrpt->ourcontext,myrpt->exten,1,NULL)) 
2601                 {
2602                         /* call has failed, inform user */
2603                         myrpt->callmode = 4;
2604                 }
2605         }
2606         if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
2607         {
2608                 myrpt->mydtmf = c;
2609         }
2610         if (c == myrpt->funcchar)
2611         {
2612                 myrpt->rem_dtmfidx = 0;
2613                 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
2614                 time(&myrpt->rem_dtmf_time);
2615                 ast_mutex_unlock(&myrpt->lock);
2616                 return;
2617         } 
2618         else if ((c != myrpt->endchar) && (myrpt->rem_dtmfidx >= 0))
2619         {
2620                 time(&myrpt->rem_dtmf_time);
2621                 if (myrpt->rem_dtmfidx < MAXDTMF)
2622                 {
2623                         myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
2624                         myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
2625                         
2626                         ast_mutex_unlock(&myrpt->lock);
2627                         strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1);
2628                         res = collect_function_digits(myrpt, cmd, 
2629                                 ((mylink->phonemode == 2) ? SOURCE_DPHONE : SOURCE_PHONE), mylink);
2630                         ast_mutex_lock(&myrpt->lock);
2631                         
2632                         switch(res){
2633
2634                                 case DC_INDETERMINATE:
2635                                         break;
2636                                 
2637                                 case DC_DOKEY:
2638                                         mylink->lastrx = 1;
2639                                         break;
2640                                 
2641                                 case DC_REQ_FLUSH:
2642                                         myrpt->rem_dtmfidx = 0;
2643                                         myrpt->rem_dtmfbuf[0] = 0;
2644                                         break;
2645                                 
2646                                 
2647                                 case DC_COMPLETE:
2648                                         myrpt->rem_dtmfbuf[0] = 0;
2649                                         myrpt->rem_dtmfidx = -1;
2650                                         myrpt->rem_dtmf_time = 0;
2651                                         break;
2652                                 
2653                                 case DC_ERROR:
2654                                 default:
2655                                         myrpt->rem_dtmfbuf[0] = 0;
2656                                         myrpt->rem_dtmfidx = -1;
2657                                         myrpt->rem_dtmf_time = 0;
2658                                         break;
2659                         }
2660                 }
2661
2662         }
2663         ast_mutex_unlock(&myrpt->lock);
2664         return;
2665 }
2666
2667 /* Doug Hall RBI-1 serial data definitions:
2668  *
2669  * Byte 0: Expansion external outputs 
2670  * Byte 1: 
2671  *      Bits 0-3 are BAND as follows:
2672  *      Bits 4-5 are POWER bits as follows:
2673  *              00 - Low Power
2674  *              01 - Hi Power
2675  *              02 - Med Power
2676  *      Bits 6-7 are always set
2677  * Byte 2:
2678  *      Bits 0-3 MHZ in BCD format
2679  *      Bits 4-5 are offset as follows:
2680  *              00 - minus
2681  *              01 - plus
2682  *              02 - simplex
2683  *              03 - minus minus (whatever that is)
2684  *      Bit 6 is the 0/5 KHZ bit
2685  *      Bit 7 is always set
2686  * Byte 3:
2687  *      Bits 0-3 are 10 KHZ in BCD format
2688  *      Bits 4-7 are 100 KHZ in BCD format
2689  * Byte 4: PL Tone code and encode/decode enable bits
2690  *      Bits 0-5 are PL tone code (comspec binary codes)
2691  *      Bit 6 is encode enable/disable
2692  *      Bit 7 is decode enable/disable
2693  */
2694
2695 /* take the frequency from the 10 mhz digits (and up) and convert it
2696    to a band number */
2697
2698 static int rbi_mhztoband(char *str)
2699 {
2700 int     i;
2701
2702         i = atoi(str) / 10; /* get the 10's of mhz */
2703         switch(i)
2704         {
2705             case 2:
2706                 return 10;
2707             case 5:
2708                 return 11;
2709             case 14:
2710                 return 2;
2711             case 22:
2712                 return 3;
2713             case 44:
2714                 return 4;
2715             case 124:
2716                 return 0;
2717             case 125:
2718                 return 1;
2719             case 126:
2720                 return 8;
2721             case 127:
2722                 return 5;
2723             case 128:
2724                 return 6;
2725             case 129:
2726                 return 7;
2727             default:
2728                 break;
2729         }
2730         return -1;
2731 }
2732
2733 /* take a PL frequency and turn it into a code */
2734 static int rbi_pltocode(char *str)
2735 {
2736 int i;
2737 char *s;
2738
2739         s = strchr(str,'.');
2740         i = 0;
2741         if (s) i = atoi(s + 1);
2742         i += atoi(str) * 10;
2743         switch(i)
2744         {
2745             case 670:
2746                 return 0;
2747             case 719:
2748                 return 1;
2749             case 744:
2750                 return 2;
2751             case 770:
2752                 return 3;
2753             case 797:
2754                 return 4;
2755             case 825:
2756                 return 5;
2757             case 854:
2758                 return 6;
2759             case 885:
2760                 return 7;
2761             case 915:
2762                 return 8;
2763             case 948:
2764                 return 9;
2765             case 974:
2766                 return 10;
2767             case 1000:
2768                 return 11;
2769             case 1035:
2770                 return 12;
2771             case 1072:
2772                 return 13;
2773             case 1109:
2774                 return 14;
2775             case 1148:
2776                 return 15;
2777             case 1188:
2778                 return 16;
2779             case 1230:
2780                 return 17;
2781             case 1273:
2782                 return 18;
2783             case 1318:
2784                 return 19;
2785             case 1365:
2786                 return 20;
2787             case 1413:
2788                 return 21;
2789             case 1462:
2790                 return 22;
2791             case 1514:
2792                 return 23;
2793             case 1567:
2794                 return 24;
2795             case 1622:
2796                 return 25;
2797             case 1679:
2798                 return 26;
2799             case 1738:
2800                 return 27;
2801             case 1799:
2802                 return 28;
2803             case 1862:
2804                 return 29;
2805             case 1928:
2806                 return 30;
2807             case 2035:
2808                 return 31;
2809             case 2107:
2810                 return 32;
2811             case 2181:
2812                 return 33;
2813             case 2257:
2814                 return 34;
2815             case 2336:
2816                 return 35;
2817             case 2418:
2818                 return 36;
2819             case 2503:
2820                 return 37;
2821         }
2822         return -1;
2823 }
2824
2825 /*
2826 * Shift out a formatted serial bit stream
2827 */
2828
2829 static void rbi_out_parallel(struct rpt *myrpt,unsigned char *data)
2830     {
2831     int i,j;
2832     unsigned char od,d;
2833     static volatile long long delayvar;
2834
2835     for(i = 0 ; i < 5 ; i++){
2836         od = *data++; 
2837         for(j = 0 ; j < 8 ; j++){
2838             d = od & 1;
2839             outb(d,myrpt->iobase);
2840             /* >= 15 us */
2841             for(delayvar = 1; delayvar < 15000; delayvar++); 
2842             od >>= 1;
2843             outb(d | 2,myrpt->iobase);
2844             /* >= 30 us */
2845             for(delayvar = 1; delayvar < 30000; delayvar++); 
2846             outb(d,myrpt->iobase);
2847             /* >= 10 us */
2848             for(delayvar = 1; delayvar < 10000; delayvar++); 
2849             }
2850         }
2851         /* >= 50 us */
2852         for(delayvar = 1; delayvar < 50000; delayvar++); 
2853     }
2854
2855 static void rbi_out(struct rpt *myrpt,unsigned char *data)
2856 {
2857 struct zt_radio_param r;
2858
2859         memset(&r,0,sizeof(struct zt_radio_param));
2860         r.radpar = ZT_RADPAR_REMMODE;
2861         r.data = ZT_RADPAR_REM_RBI1;
2862         /* if setparam ioctl fails, its probably not a pciradio card */
2863         if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&r) == -1)
2864         {
2865                 rbi_out_parallel(myrpt,data);
2866                 return;
2867         }
2868         r.radpar = ZT_RADPAR_REMCOMMAND;
2869         memcpy(&r.data,data,5);
2870         if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&r) == -1)
2871         {
2872                 ast_log(LOG_WARNING,"Cannot send RBI command for channel %s\n",myrpt->rxchannel->name);
2873                 return;
2874         }
2875 }
2876
2877 static int serial_remote_io(struct rpt *myrpt, unsigned char *txbuf, int txbytes, char *rxbuf,
2878         int rxmaxbytes, int asciiflag)
2879 {
2880         int i;
2881         struct zt_radio_param prm;
2882
2883         if(debug){
2884                 printf("String output was: ");
2885                 for(i = 0; i < txbytes; i++)
2886                         printf("%02X ", (unsigned char ) txbuf[i]);
2887                 printf("\n");
2888         }
2889
2890         prm.radpar = ZT_RADPAR_REMMODE;
2891         if (asciiflag)  prm.data = ZT_RADPAR_REM_SERIAL_ASCII;
2892         else prm.data = ZT_RADPAR_REM_SERIAL;
2893         if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&prm) == -1) return -1;
2894         prm.radpar = ZT_RADPAR_REMCOMMAND;
2895         prm.data = rxmaxbytes;
2896         memcpy(prm.buf,txbuf,txbytes);
2897         prm.index = txbytes;
2898         if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&prm) == -1) return -1;
2899         if (rxbuf)
2900         {
2901                 *rxbuf = 0;
2902                 memcpy(rxbuf,prm.buf,prm.index);
2903         }
2904         return(prm.index);
2905 }
2906
2907 static int setrbi(struct rpt *myrpt)
2908 {
2909 char tmp[MAXREMSTR] = "",*s;
2910 unsigned char rbicmd[5];
2911 int     band,txoffset = 0,txpower = 0,txpl;
2912
2913         /* must be a remote system */
2914         if (!myrpt->remote) return(0);
2915         /* must have rbi hardware */
2916         if (strncmp(myrpt->remote,remote_rig_rbi,3)) return(0);
2917         strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
2918         s = strchr(tmp,'.');
2919         /* if no decimal, is invalid */
2920         
2921         if (s == NULL){
2922                 if(debug)
2923                         printf("@@@@ Frequency needs a decimal\n");
2924                 return -1;
2925         }
2926         
2927         *s++ = 0;
2928         if (strlen(tmp) < 2){
2929                 if(debug)
2930                         printf("@@@@ Bad MHz digits: %s\n", tmp);
2931                 return -1;
2932         }
2933          
2934         if (strlen(s) < 3){
2935                 if(debug)
2936                         printf("@@@@ Bad KHz digits: %s\n", s);
2937                 return -1;
2938         }
2939
2940         if ((s[2] != '0') && (s[2] != '5')){
2941                 if(debug)
2942                         printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
2943                 return -1;
2944         }
2945          
2946         band = rbi_mhztoband(tmp);
2947         if (band == -1){
2948                 if(debug)
2949                         printf("@@@@ Bad Band: %s\n", tmp);
2950                 return -1;
2951         }
2952         
2953         txpl = rbi_pltocode(myrpt->txpl);
2954         
2955         if (txpl == -1){
2956                 if(debug)
2957                         printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
2958                 return -1;
2959         }
2960
2961         
2962         switch(myrpt->offset)
2963         {
2964             case REM_MINUS:
2965                 txoffset = 0;
2966                 break;
2967             case REM_PLUS:
2968                 txoffset = 0x10;
2969                 break;
2970             case REM_SIMPLEX:
2971                 txoffset = 0x20;
2972                 break;
2973         }
2974         switch(myrpt->powerlevel)
2975         {
2976             case REM_LOWPWR:
2977                 txpower = 0;
2978                 break;
2979             case REM_MEDPWR:
2980                 txpower = 0x20;
2981                 break;
2982             case REM_HIPWR:
2983                 txpower = 0x10;
2984                 break;
2985         }
2986         rbicmd[0] = 0;
2987         rbicmd[1] = band | txpower | 0xc0;
2988         rbicmd[2] = (*(s - 2) - '0') | txoffset | 0x80;
2989         if (s[2] == '5') rbicmd[2] |= 0x40;
2990         rbicmd[3] = ((*s - '0') << 4) + (s[1] - '0');
2991         rbicmd[4] = txpl;
2992         if (myrpt->txplon) rbicmd[4] |= 0x40;
2993         if (myrpt->rxplon) rbicmd[4] |= 0x80;
2994         rbi_out(myrpt,rbicmd);
2995         return 0;
2996 }
2997
2998
2999 /* Check for valid rbi frequency */
3000 /* Hard coded limits now, configurable later, maybe? */
3001
3002 static int check_freq_rbi(int m, int d, int *defmode)
3003 {
3004         int dflmd = REM_MODE_FM;
3005
3006         if(m == 50){ /* 6 meters */
3007                 if(d < 10100)
3008                         return -1;
3009         }
3010         else if((m >= 51) && ( m < 54)){
3011                 ;
3012         }
3013         else if(m == 144){ /* 2 meters */
3014                 if(d < 10100)
3015                         return -1;
3016         }
3017         else if((m >= 145) && (m < 148)){
3018                 ;
3019         }
3020         else if((m >= 222) && (m < 225)){ /* 1.25 meters */
3021                 ;
3022         }
3023         else if((m >= 430) && (m < 450)){ /* 70 centimeters */
3024                 ;
3025         }
3026         else if((m >= 1240) && (m < 1300)){ /* 23 centimeters */
3027                 ;
3028         }
3029         else
3030                 return -1;
3031         
3032         if(defmode)
3033                 *defmode = dflmd;       
3034
3035
3036         return 0;
3037 }
3038
3039 /*
3040 * Split frequency into mhz and decimals
3041 */
3042  
3043 static int split_freq(char *mhz, char *decimals, char *freq)
3044 {
3045         char freq_copy[MAXREMSTR];
3046         char *decp;
3047
3048         decp = strchr(strncpy(freq_copy, freq, MAXREMSTR),'.');
3049         if(decp){
3050                 *decp++ = 0;
3051                 strncpy(mhz, freq_copy, MAXREMSTR);
3052                 strcpy(decimals, "00000");
3053                 strncpy(decimals, decp, strlen(decp));
3054                 decimals[5] = 0;
3055                 return 0;
3056         }
3057         else
3058                 return -1;
3059
3060 }
3061         
3062 /*
3063 * Split ctcss frequency into hertz and decimal
3064 */
3065  
3066 static int split_ctcss_freq(char *hertz, char *decimal, char *freq)
3067 {
3068         char freq_copy[MAXREMSTR];
3069         char *decp;
3070
3071         decp = strchr(strncpy(freq_copy, freq, MAXREMSTR),'.');
3072         if(decp){
3073                 *decp++ = 0;
3074                 strncpy(hertz, freq_copy, MAXREMSTR);
3075                 strncpy(decimal, decp, strlen(decp));
3076                 decimal[strlen(decp)] = '\0';
3077                 return 0;
3078         }
3079         else
3080                 return -1;
3081 }
3082
3083
3084
3085 /*
3086 * FT-897 I/O handlers
3087 */
3088
3089 /* Check to see that the frequency is valid */
3090 /* Hard coded limits now, configurable later, maybe? */
3091
3092
3093 static int check_freq_ft897(int m, int d, int *defmode)