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