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