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