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