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