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