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