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