a4992cb1e39c26a28c1bc3a47a7f9ff1b9431cf8
[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.4 6/19/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  *  *9 - system reset
27  *
28  *  To send an asterisk (*) while dialing or talking on phone,
29  *  use the autopatch acess code.
30  */
31  
32 /* number of digits for function after *. Must be at least 1 */
33 #define FUNCTION_LEN 4
34 /* string containing all of the 1 digit functions */
35 #define SHORTFUNCS "056789"
36
37 /* maximum digits in DTMF buffer, and seconds after * for DTMF command timeout */
38
39 #define MAXDTMF 10
40 #define DTMF_TIMEOUT 3
41
42 #define NODES "nodes"
43
44 #define MAXCONNECTTIME 5000
45
46 #define MAXNODESTR 300
47
48 enum {REM_OFF,REM_MONITOR,REM_TX};
49
50 enum{ID,PROC,TERM,COMPLETE,UNKEY,REMDISC,REMALREADY,REMNOTFOUND,REMGO,
51         CONNECTED,CONNFAIL,STATUS};
52
53 #include <pthread.h>
54 #include <asterisk/lock.h>
55 #include <asterisk/file.h>
56 #include <asterisk/logger.h>
57 #include <asterisk/channel.h>
58 #include <asterisk/callerid.h>
59 #include <asterisk/pbx.h>
60 #include <asterisk/module.h>
61 #include <asterisk/translate.h>
62 #include <asterisk/options.h>
63 #include <asterisk/config.h>
64 #include <asterisk/utils.h>
65 #include <asterisk/say.h>
66 #include <stdio.h>
67 #include <unistd.h>
68 #include <string.h>
69 #include <stdlib.h>
70 #include <search.h>
71 #include <sys/types.h>
72 #include <sys/stat.h>
73 #include <errno.h>
74 #include <dirent.h>
75 #include <ctype.h>
76 #include <sys/stat.h>
77 #include <sys/time.h>
78 #include <sys/file.h>
79 #include <sys/ioctl.h>
80 #include <math.h>
81 #include <tonezone.h>
82 #include <linux/zaptel.h>
83
84 static  char *tdesc = "Radio Repeater / Remote Base  version 0.3  06/18/2004";
85 static char *app = "Rpt";
86
87 static char *synopsis = "Radio Repeater/Remote Base Control System";
88
89 static char *descrip = 
90 "  Rpt(sysname):  Radio Remote Link or Remote Base Link Endpoint Process.\n";
91
92 static int debug = 0;
93 static int nrpts = 0;
94
95 struct  ast_config *cfg;
96
97 STANDARD_LOCAL_USER;
98 LOCAL_USER_DECL;
99
100 #define MSWAIT 200
101 #define HANGTIME 5000
102 #define TOTIME 180000
103 #define IDTIME 300000
104 #define MAXRPTS 20
105
106 static  pthread_t rpt_master_thread;
107
108 struct rpt;
109
110 struct rpt_link
111 {
112         struct rpt_link *next;
113         struct rpt_link *prev;
114         char    mode;                   /* 1 if in tx mode */
115         char    isremote;
116         char    name[MAXNODESTR];       /* identifier (routing) string */
117         char    lasttx;
118         char    lastrx;
119         char    connected;
120         char    outbound;
121         long elaptime;
122         struct ast_channel *chan;       
123         struct ast_channel *pchan;      
124 } ;
125
126 struct rpt_tele
127 {
128         struct rpt_tele *next;
129         struct rpt_tele *prev;
130         struct rpt *rpt;
131         int     mode;
132         struct rpt_link mylink;
133         pthread_t threadid;
134 } ;
135
136 static struct rpt
137 {
138         char *name;
139         ast_mutex_t lock;
140         char *rxchanname;
141         char *txchanname;
142         char *ourcontext;
143         char *ourcallerid;
144         char *acctcode;
145         char *ident;
146         char *tonezone;
147         struct rpt_link links;
148         int hangtime;
149         int totime;
150         int idtime;
151         char exttx;
152         char localtx;
153         char remoterx;
154         char remotetx;
155         char remoteon;
156         char simple;
157         char remote;
158         char dtmfbuf[MAXDTMF];
159         char rem_dtmfbuf[MAXDTMF];
160         char cmdnode[50];
161         struct ast_channel *rxchannel,*txchannel;
162         struct ast_channel *pchannel,*txpchannel;
163         struct rpt_tele tele;
164         pthread_t rpt_call_thread,rpt_thread;
165         time_t rem_dtmf_time;
166         int tailtimer,totimer,idtimer,txconf,conf,callmode,cidx;
167         int dtmfidx,rem_dtmfidx;
168         char mydtmf;
169         char exten[AST_MAX_EXTENSION];
170 } rpt_vars[MAXRPTS];            
171
172 static void *rpt_tele_thread(void *this)
173 {
174 ZT_CONFINFO ci;  /* conference info */
175 int     res = 0,hastx,imdone = 0;
176 struct  rpt_tele *mytele = (struct rpt_tele *)this;
177 struct  rpt *myrpt;
178 struct  rpt_link *l,*m,linkbase;
179 struct  ast_channel *mychannel;
180
181         /* get a pointer to myrpt */
182         myrpt = mytele->rpt;
183         /* allocate a pseudo-channel thru asterisk */
184         mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo");
185         if (!mychannel)
186         {
187                 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
188                 ast_mutex_lock(&myrpt->lock);
189                 remque((struct qelem *)mytele);
190                 ast_mutex_unlock(&myrpt->lock);
191                 free(mytele);           
192                 pthread_exit(NULL);
193         }
194         /* make a conference for the tx */
195         ci.chan = 0;
196         ci.confno = myrpt->conf; /* use the tx conference */
197         ci.confmode = ZT_CONF_CONFANN;
198         /* first put the channel on the conference in announce mode */
199         if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
200         {
201                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
202                 ast_mutex_lock(&myrpt->lock);
203                 remque((struct qelem *)mytele);
204                 ast_mutex_unlock(&myrpt->lock);
205                 free(mytele);           
206                 ast_hangup(mychannel);
207                 pthread_exit(NULL);
208         }
209         ast_stopstream(mychannel);
210         switch(mytele->mode)
211         {
212             case ID:
213                 res = ast_streamfile(mychannel, myrpt->ident, mychannel->language);
214                 break;
215             case PROC:
216                 /* wait a little bit longer */
217                 usleep(1500000);
218                 res = ast_streamfile(mychannel, "rpt/callproceeding", mychannel->language);
219                 break;
220             case TERM:
221                 /* wait a little bit longer */
222                 usleep(1500000);
223                 res = ast_streamfile(mychannel, "rpt/callterminated", mychannel->language);
224                 break;
225             case COMPLETE:
226                 /* wait a little bit */
227                 usleep(1000000);
228                 res = ast_streamfile(mychannel, "rpt/functioncomplete", mychannel->language);
229                 break;
230             case UNKEY:
231                 /* wait a little bit */
232                 usleep(1000000);
233                 hastx = 0;
234                 l = myrpt->links.next;
235                 if (l != &myrpt->links)
236                 {
237                         ast_mutex_lock(&myrpt->lock);
238                         while(l != &myrpt->links)
239                         {
240                                 if (l->mode) hastx++;
241                                 l = l->next;
242                         }
243                         ast_mutex_unlock(&myrpt->lock);
244                         res = ast_streamfile(mychannel, 
245                                 ((!hastx) ? "rpt/remote_monitor" : "rpt/remote_tx"),
246                                         mychannel->language);
247                         if (!res) 
248                                 res = ast_waitstream(mychannel, "");
249                         else
250                                  ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
251                         ast_stopstream(mychannel);
252                 } 
253                 /* if in remote cmd mode, indicate it */
254                 if (myrpt->cmdnode[0])
255                 {
256                         ast_safe_sleep(mychannel,200);
257                         res = ast_streamfile(mychannel, "rpt/remote_cmd", mychannel->language);
258                         if (!res) 
259                                 res = ast_waitstream(mychannel, "");
260                         else
261                                  ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
262                         ast_stopstream(mychannel);
263                 }
264                 imdone = 1;
265                 break;
266             case REMDISC:
267                 /* wait a little bit */
268                 usleep(1000000);
269                 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
270                 if (!res) 
271                         res = ast_waitstream(mychannel, "");
272                 else
273                          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
274                 ast_stopstream(mychannel);
275                 ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
276                 res = ast_streamfile(mychannel, ((mytele->mylink.connected) ? 
277                         "rpt/remote_disc" : "rpt/remote_busy"), mychannel->language);
278                 break;
279             case REMALREADY:
280                 /* wait a little bit */
281                 usleep(1000000);
282                 res = ast_streamfile(mychannel, "rpt/remote_already", mychannel->language);
283                 break;
284             case REMNOTFOUND:
285                 /* wait a little bit */
286                 usleep(1000000);
287                 res = ast_streamfile(mychannel, "rpt/remote_notfound", mychannel->language);
288                 break;
289             case REMGO:
290                 /* wait a little bit */
291                 usleep(1000000);
292                 res = ast_streamfile(mychannel, "rpt/remote_go", mychannel->language);
293                 break;
294             case CONNECTED:
295                 /* wait a little bit */
296                 usleep(1000000);
297                 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
298                 if (!res) 
299                         res = ast_waitstream(mychannel, "");
300                 else
301                          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
302                 ast_stopstream(mychannel);
303                 ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
304                 res = ast_streamfile(mychannel, "rpt/connected", mychannel->language);
305                 break;
306             case CONNFAIL:
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, "rpt/connection_failed", mychannel->language);
315                 break;
316             case STATUS:
317                 /* wait a little bit */
318                 usleep(1000000);
319                 hastx = 0;
320                 linkbase.next = &linkbase;
321                 linkbase.prev = &linkbase;
322                 ast_mutex_lock(&myrpt->lock);
323                 /* make our own list of links */
324                 l = myrpt->links.next;
325                 while(l != &myrpt->links)
326                 {
327                         m = malloc(sizeof(struct rpt_link));
328                         if (!m)
329                         {
330                                 ast_log(LOG_WARNING, "Cannot alloc memory on %s\n", mychannel->name);
331                                 pthread_exit(NULL);
332                         }
333                         memcpy(m,l,sizeof(struct rpt_link));
334                         m->next = m->prev = NULL;
335                         insque((struct qelem *)m,(struct qelem *)linkbase.next);
336                         l = l->next;
337                 }
338                 ast_mutex_unlock(&myrpt->lock);
339                 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
340                 if (!res) 
341                         res = ast_waitstream(mychannel, "");
342                 else
343                          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
344                 ast_stopstream(mychannel);
345                 ast_say_character_str(mychannel,myrpt->name,NULL,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                 if (myrpt->callmode)
352                 {
353                         hastx = 1;
354                         res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
355                         if (!res) 
356                                 res = ast_waitstream(mychannel, "");
357                         else
358                                  ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
359                         ast_stopstream(mychannel);
360                 }
361                 l = linkbase.next;
362                 while(l != &linkbase)
363                 {
364                         hastx = 1;
365                         res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
366                         if (!res) 
367                                 res = ast_waitstream(mychannel, "");
368                         else
369                                 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
370                         ast_stopstream(mychannel);
371                         ast_say_character_str(mychannel,l->name,NULL,mychannel->language);
372                         if (!res) 
373                                 res = ast_waitstream(mychannel, "");
374                         else
375                                  ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
376                         ast_stopstream(mychannel);
377                         res = ast_streamfile(mychannel, ((l->mode) ? 
378                                 "rpt/tranceive" : "rpt/monitor"), mychannel->language);
379                         if (!res) 
380                                 res = ast_waitstream(mychannel, "");
381                         else
382                                 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
383                         ast_stopstream(mychannel);
384                         l = l->next;
385                 }                       
386                 if (!hastx)
387                 {
388                         res = ast_streamfile(mychannel, "rpt/repeat_only", mychannel->language);
389                         if (!res) 
390                                 res = ast_waitstream(mychannel, "");
391                         else
392                                  ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
393                         ast_stopstream(mychannel);
394                 }
395                 /* destroy our local link queue */
396                 l = linkbase.next;
397                 while(l != &linkbase)
398                 {
399                         m = l;
400                         l = l->next;
401                         remque((struct qelem *)m);
402                         free(m);
403                 }                       
404                 imdone = 1;
405                 break;
406         }
407         if (!imdone)
408         {
409                 if (!res) 
410                         res = ast_waitstream(mychannel, "");
411                 else {
412                         ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
413                         res = 0;
414                 }
415         }
416         ast_stopstream(mychannel);
417         ast_mutex_lock(&myrpt->lock);
418         remque((struct qelem *)mytele);
419         ast_mutex_unlock(&myrpt->lock);
420         free(mytele);           
421         ast_hangup(mychannel);
422         pthread_exit(NULL);
423 }
424
425 static void rpt_telemetry(struct rpt *myrpt,int mode,struct rpt_link *mylink)
426 {
427 struct rpt_tele *tele;
428 pthread_attr_t attr;
429
430         tele = malloc(sizeof(struct rpt_tele));
431         if (!tele)
432         {
433                 ast_log(LOG_WARNING, "Unable to allocate memory\n");
434                 pthread_exit(NULL);
435                 return;
436         }
437         /* zero it out */
438         memset((char *)tele,0,sizeof(struct rpt_tele));
439         tele->rpt = myrpt;
440         tele->mode = mode;
441         ast_mutex_lock(&myrpt->lock);
442         memset(&tele->mylink,0,sizeof(struct rpt_link));
443         if (mylink)
444         {
445                 memcpy(&tele->mylink,mylink,sizeof(struct rpt_link));
446         }               
447         insque((struct qelem *)tele,(struct qelem *)myrpt->tele.next); 
448         ast_mutex_unlock(&myrpt->lock);
449         pthread_attr_init(&attr);
450         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
451         pthread_create(&tele->threadid,&attr,rpt_tele_thread,(void *) tele);
452         return;
453 }
454
455 static void *rpt_call(void *this)
456 {
457 ZT_CONFINFO ci;  /* conference info */
458 struct  rpt *myrpt = (struct rpt *)this;
459 int     res;
460 struct  ast_frame *f,wf;
461 int stopped,congstarted;
462 struct ast_channel *mychannel,*genchannel;
463
464         myrpt->mydtmf = 0;
465         /* allocate a pseudo-channel thru asterisk */
466         mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo");
467         if (!mychannel)
468         {
469                 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
470                 pthread_exit(NULL);
471         }
472         ci.chan = 0;
473         ci.confno = myrpt->conf; /* use the pseudo conference */
474         ci.confmode = ZT_CONF_REALANDPSEUDO | ZT_CONF_TALKER | ZT_CONF_LISTENER
475                 | ZT_CONF_PSEUDO_TALKER | ZT_CONF_PSEUDO_LISTENER; 
476         /* first put the channel on the conference */
477         if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
478         {
479                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
480                 ast_hangup(mychannel);
481                 myrpt->callmode = 0;
482                 pthread_exit(NULL);
483         }
484         /* allocate a pseudo-channel thru asterisk */
485         genchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo");
486         if (!genchannel)
487         {
488                 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
489                 ast_hangup(mychannel);
490                 pthread_exit(NULL);
491         }
492         ci.chan = 0;
493         ci.confno = myrpt->conf;
494         ci.confmode = ZT_CONF_REALANDPSEUDO | ZT_CONF_TALKER | ZT_CONF_LISTENER
495                 | ZT_CONF_PSEUDO_TALKER | ZT_CONF_PSEUDO_LISTENER; 
496         /* first put the channel on the conference */
497         if (ioctl(genchannel->fds[0],ZT_SETCONF,&ci) == -1)
498         {
499                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
500                 ast_hangup(mychannel);
501                 ast_hangup(genchannel);
502                 myrpt->callmode = 0;
503                 pthread_exit(NULL);
504         }
505         if (myrpt->tonezone && (tone_zone_set_zone(mychannel->fds[0],myrpt->tonezone) == -1))
506         {
507                 ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->tonezone);
508                 ast_hangup(mychannel);
509                 ast_hangup(genchannel);
510                 myrpt->callmode = 0;
511                 pthread_exit(NULL);
512         }
513         if (myrpt->tonezone && (tone_zone_set_zone(genchannel->fds[0],myrpt->tonezone) == -1))
514         {
515                 ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->tonezone);
516                 ast_hangup(mychannel);
517                 ast_hangup(genchannel);
518                 myrpt->callmode = 0;
519                 pthread_exit(NULL);
520         }
521         /* start dialtone */
522         if (tone_zone_play_tone(mychannel->fds[0],ZT_TONE_DIALTONE) < 0)
523         {
524                 ast_log(LOG_WARNING, "Cannot start dialtone\n");
525                 ast_hangup(mychannel);
526                 ast_hangup(genchannel);
527                 myrpt->callmode = 0;
528                 pthread_exit(NULL);
529         }
530         stopped = 0;
531         congstarted = 0;
532         while ((myrpt->callmode == 1) || (myrpt->callmode == 4))
533         {
534
535                 if ((myrpt->callmode == 1) && (myrpt->cidx > 0) && (!stopped))
536                 {
537                         stopped = 1;
538                         /* stop dial tone */
539                         tone_zone_play_tone(mychannel->fds[0],-1);
540                 }
541                 if ((myrpt->callmode == 4) && (!congstarted))
542                 {
543                         congstarted = 1;
544                         /* start congestion tone */
545                         tone_zone_play_tone(mychannel->fds[0],ZT_TONE_CONGESTION);
546                 }
547                 res = ast_waitfor(mychannel, MSWAIT);
548                 if (res < 0)
549                 {
550                         ast_hangup(mychannel);
551                         ast_hangup(genchannel);
552                         ast_mutex_lock(&myrpt->lock);
553                         myrpt->callmode = 0;
554                         ast_mutex_unlock(&myrpt->lock);
555                         pthread_exit(NULL);
556                 }
557                 if (res == 0) continue;
558                 f = ast_read(mychannel);
559                 if (f == NULL) 
560                 {
561                         ast_hangup(mychannel);
562                         ast_hangup(genchannel);
563                         ast_mutex_lock(&myrpt->lock);
564                         myrpt->callmode = 0;
565                         ast_mutex_unlock(&myrpt->lock);
566                         pthread_exit(NULL);                     
567                 }
568                 if ((f->frametype == AST_FRAME_CONTROL) &&
569                     (f->subclass == AST_CONTROL_HANGUP))
570                 {
571                         ast_frfree(f);
572                         ast_hangup(mychannel);
573                         ast_hangup(genchannel);
574                         ast_mutex_lock(&myrpt->lock);
575                         myrpt->callmode = 0;
576                         ast_mutex_unlock(&myrpt->lock);
577                         pthread_exit(NULL);                     
578                 }
579                 ast_frfree(f);
580         }
581         /* stop any tone generation */
582         tone_zone_play_tone(mychannel->fds[0],-1);
583         /* end if done */
584         if (!myrpt->callmode)
585         {
586                 ast_hangup(mychannel);
587                 ast_hangup(genchannel);
588                 ast_mutex_lock(&myrpt->lock);
589                 myrpt->callmode = 0;
590                 ast_mutex_unlock(&myrpt->lock);
591                 pthread_exit(NULL);                     
592         }
593         if (myrpt->ourcallerid && *myrpt->ourcallerid)
594         {
595                 if (mychannel->callerid) free(mychannel->callerid);
596                 mychannel->callerid = strdup(myrpt->ourcallerid);
597         }
598         strcpy(mychannel->exten,myrpt->exten);
599         strcpy(mychannel->context,myrpt->ourcontext);
600         if (myrpt->acctcode)
601                 strcpy(mychannel->accountcode,myrpt->acctcode);
602         mychannel->priority = 1;
603         ast_channel_undefer_dtmf(mychannel);
604         if (ast_pbx_start(mychannel) < 0)
605         {
606                 ast_log(LOG_WARNING, "Unable to start PBX!!\n");
607                 ast_hangup(mychannel);
608                 ast_hangup(genchannel);
609                 ast_mutex_lock(&myrpt->lock);
610                 myrpt->callmode = 0;
611                 ast_mutex_unlock(&myrpt->lock);
612                 pthread_exit(NULL);
613         }
614         ast_mutex_lock(&myrpt->lock);
615         myrpt->callmode = 3;
616         while(myrpt->callmode)
617         {
618                 if ((!mychannel->pvt) && (myrpt->callmode != 4))
619                 {
620                         myrpt->callmode = 4;
621                         ast_mutex_unlock(&myrpt->lock);
622                         /* start congestion tone */
623                         tone_zone_play_tone(genchannel->fds[0],ZT_TONE_CONGESTION);
624                         ast_mutex_lock(&myrpt->lock);
625                 }
626                 if (myrpt->mydtmf)
627                 {
628                         wf.frametype = AST_FRAME_DTMF;
629                         wf.subclass = myrpt->mydtmf;
630                         wf.offset = 0;
631                         wf.mallocd = 0;
632                         wf.data = NULL;
633                         wf.datalen = 0;
634                         wf.samples = 0;
635                         ast_mutex_unlock(&myrpt->lock);
636                         ast_write(genchannel,&wf); 
637                         ast_mutex_lock(&myrpt->lock);
638                         myrpt->mydtmf = 0;
639                 }
640                 ast_mutex_unlock(&myrpt->lock);
641                 usleep(25000);
642                 ast_mutex_lock(&myrpt->lock);
643         }
644         ast_mutex_unlock(&myrpt->lock);
645         tone_zone_play_tone(genchannel->fds[0],-1);
646         if (mychannel->pvt) ast_softhangup(mychannel,AST_SOFTHANGUP_DEV);
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
654 static void send_link_dtmf(struct rpt *myrpt,char c)
655 {
656 char    str[300];
657 struct  ast_frame wf;
658 struct  rpt_link *l;
659
660         sprintf(str,"D %s %s %d %c",myrpt->cmdnode,myrpt->name,++(myrpt->dtmfidx),c);
661         wf.frametype = AST_FRAME_TEXT;
662         wf.subclass = 0;
663         wf.offset = 0;
664         wf.mallocd = 1;
665         wf.datalen = strlen(str) + 1;
666         wf.samples = 0;
667         l = myrpt->links.next;
668         /* first, see if our dude is there */
669         while(l != &myrpt->links)
670         {
671                 if (!l->isremote)
672                 {
673                         /* if we found it, write it and were done */
674                         if (!strcmp(l->name,myrpt->cmdnode))
675                         {
676                                 wf.data = strdup(str);
677                                 ast_write(l->chan,&wf);
678                                 return;
679                         }
680                 }
681                 l = l->next;
682         }
683         l = myrpt->links.next;
684         /* if not, give it to everyone */
685         while(l != &myrpt->links)
686         {
687                 if (!l->isremote) 
688                 {
689                         wf.data = strdup(str);
690                         ast_write(l->chan,&wf);
691                 }
692                 l = l->next;
693         }
694         return;
695 }
696
697 static void process_dtmf(char *cmd,struct rpt *myrpt, int allow_linkcmd)
698 {
699 pthread_attr_t attr;
700 char *tele,tmp[300],deststr[300],*val,*s,*s1;
701 struct rpt_link *l;
702 ZT_CONFINFO ci;  /* conference info */
703
704         switch(atoi(cmd) / 1000)
705         {
706         case 6: /* autopatch on / send asterisk (*) */
707                 ast_mutex_lock(&myrpt->lock);
708                 /* if on call, force * into current audio stream */
709                 if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
710                 {
711                         myrpt->mydtmf = '*';
712                         ast_mutex_unlock(&myrpt->lock);
713                         break;
714                 }
715                 if (myrpt->callmode)
716                 {
717                         ast_mutex_unlock(&myrpt->lock);
718                         return;
719                 }
720                 myrpt->callmode = 1;
721                 myrpt->cidx = 0;
722                 myrpt->exten[myrpt->cidx] = 0;
723                 ast_mutex_unlock(&myrpt->lock);
724                 pthread_attr_init(&attr);
725                 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
726                 pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *) myrpt);
727                 return;
728         case 0: /* autopatch off */
729                 ast_mutex_lock(&myrpt->lock);
730                 if (!myrpt->callmode)
731                 {
732                         ast_mutex_unlock(&myrpt->lock);
733                         return;
734                 }
735                 myrpt->callmode = 0;
736                 ast_mutex_unlock(&myrpt->lock);
737                 rpt_telemetry(myrpt,TERM,NULL);
738                 return;
739         case 9: /* master reset */
740                 ast_mutex_lock(&myrpt->lock);
741                 myrpt->callmode = 0;
742                 ast_mutex_unlock(&myrpt->lock);
743                 l = myrpt->links.next;
744                 /* disconnect all of the remote stuff */
745                 while(l != &myrpt->links)
746                 {
747                         ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
748                         l = l->next;
749                 }
750                 break;
751         case 1: /* remote base off */
752                 val = ast_variable_retrieve(cfg,NODES,cmd + 1);
753                 if (!val)
754                 {
755                         rpt_telemetry(myrpt,REMNOTFOUND,NULL);
756                         return;
757                 }
758                 strncpy(tmp,val,sizeof(tmp) - 1);
759                 s = tmp;
760                 s1 = strsep(&s,",");
761                 ast_mutex_lock(&myrpt->lock);
762                 l = myrpt->links.next;
763                 /* try to find this one in queue */
764                 while(l != &myrpt->links)
765                 {
766                         /* if found matching string */
767                         if (!strcmp(l->name,cmd + 1)) break;
768                         l = l->next;
769                 }
770                 if (l != &myrpt->links) /* if found */
771                 {
772                         ast_mutex_unlock(&myrpt->lock);
773                         ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
774                         break;
775                 }
776                 ast_mutex_unlock(&myrpt->lock);
777                 return;
778         case 2: /* remote base monitor */
779                 val = ast_variable_retrieve(cfg,NODES,cmd + 1);
780                 if (!val)
781                 {
782                         rpt_telemetry(myrpt,REMNOTFOUND,NULL);
783                         return;
784                 }
785                 strncpy(tmp,val,sizeof(tmp) - 1);
786                 s = tmp;
787                 s1 = strsep(&s,",");
788                 ast_mutex_lock(&myrpt->lock);
789                 l = myrpt->links.next;
790                 /* try to find this one in queue */
791                 while(l != &myrpt->links)
792                 {
793                         /* if found matching string */
794                         if (!strcmp(l->name,cmd + 1)) break;
795                         l = l->next;
796                 }
797                 /* if found */
798                 if (l != &myrpt->links) 
799                 {
800                         /* if already in this mode, just ignore */
801                         if (!l->mode) {
802                                 ast_mutex_unlock(&myrpt->lock);
803                                 rpt_telemetry(myrpt,REMALREADY,NULL);
804                                 return;
805                         }
806                         ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
807                         usleep(500000); 
808                 }
809                 ast_mutex_unlock(&myrpt->lock);
810                 /* establish call in monitor mode */
811                 l = malloc(sizeof(struct rpt_link));
812                 if (!l)
813                 {
814                         ast_log(LOG_WARNING, "Unable to malloc\n");
815                         pthread_exit(NULL);
816                 }
817                 /* zero the silly thing */
818                 memset((char *)l,0,sizeof(struct rpt_link));
819                 sprintf(deststr,"IAX2/%s",s1);
820                 tele = strchr(deststr,'/');
821                 if (!tele)
822                 {
823                         fprintf(stderr,"rpt:Dial number (%s) must be in format tech/number\n",deststr);
824                         pthread_exit(NULL);
825                 }
826                 *tele++ = 0;
827                 l->isremote = (s && ast_true(s));
828                 strncpy(l->name,cmd + 1,MAXNODESTR - 1);
829                 l->chan = ast_request(deststr,AST_FORMAT_SLINEAR,tele);
830                 if (l->chan)
831                 {
832                         ast_set_read_format(l->chan,AST_FORMAT_SLINEAR);
833                         ast_set_write_format(l->chan,AST_FORMAT_SLINEAR);
834                         l->chan->whentohangup = 0;
835                         l->chan->appl = "Apprpt";
836                         l->chan->data = "(Remote Rx)";
837                         if (option_verbose > 2)
838                                 ast_verbose(VERBOSE_PREFIX_3 "rpt (remote) initiating call to %s/%s on %s\n",
839                                         deststr,tele,l->chan->name);
840                         l->chan->callerid = strdup(myrpt->name);
841                         ast_call(l->chan,tele,0);
842                 }
843                 else
844                 {
845                         free(l);
846                         if (option_verbose > 2)
847                                 ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
848                                         deststr,tele,l->chan->name);
849                         return;
850                 }
851                 /* allocate a pseudo-channel thru asterisk */
852                 l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo");
853                 if (!l->pchan)
854                 {
855                         fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
856                         pthread_exit(NULL);
857                 }
858                 ast_set_read_format(l->pchan,AST_FORMAT_SLINEAR);
859                 ast_set_write_format(l->pchan,AST_FORMAT_SLINEAR);
860                 /* make a conference for the pseudo-one */
861                 ci.chan = 0;
862                 ci.confno = myrpt->conf;
863                 ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER;
864                 /* first put the channel on the conference in proper mode */
865                 if (ioctl(l->pchan->fds[0],ZT_SETCONF,&ci) == -1)
866                 {
867                         ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
868                         pthread_exit(NULL);
869                 }
870                 ast_mutex_lock(&myrpt->lock);
871                 /* insert at end of queue */
872                 insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
873                 ast_mutex_unlock(&myrpt->lock);
874                 break;
875         case 3: /* remote base tranceieve */
876                 val = ast_variable_retrieve(cfg,NODES,cmd + 1);
877                 if (!val)
878                 {
879                         rpt_telemetry(myrpt,REMNOTFOUND,NULL);
880                         return;
881                 }
882                 strncpy(tmp,val,sizeof(tmp) - 1);
883                 s = tmp;
884                 s1 = strsep(&s,",");
885                 ast_mutex_lock(&myrpt->lock);
886                 l = myrpt->links.next;
887                 /* try to find this one in queue */
888                 while(l != &myrpt->links)
889                 {
890                         /* if found matching string */
891                         if (!strcmp(l->name,cmd + 1)) break;
892                 }
893                 /* if found */
894                 if (l != &myrpt->links) 
895                 {
896                         /* if already in this mode, just ignore */
897                         if (l->mode)
898                         {
899                                 ast_mutex_unlock(&myrpt->lock);
900                                 rpt_telemetry(myrpt,REMALREADY,NULL);
901                                 return;
902                         }
903                         ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
904                         usleep(500000); 
905                 }
906                 ast_mutex_unlock(&myrpt->lock);
907                 /* establish call in tranceive mode */
908                 l = malloc(sizeof(struct rpt_link));
909                 if (!l)
910                 {
911                         ast_log(LOG_WARNING, "Unable to malloc\n");
912                         pthread_exit(NULL);
913                 }
914                 /* zero the silly thing */
915                 memset((char *)l,0,sizeof(struct rpt_link));
916                 l->mode = 1;
917                 strncpy(l->name,cmd + 1,MAXNODESTR - 1);
918                 l->isremote = (s && ast_true(s));
919                 sprintf(deststr,"IAX2/%s",s1);
920                 tele = strchr(deststr,'/');
921                 if (!tele)
922                 {
923                         fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
924                         pthread_exit(NULL);
925                 }
926                 *tele++ = 0;
927                 l->chan = ast_request(deststr,AST_FORMAT_SLINEAR,tele);
928                 if (l->chan)
929                 {
930                         ast_set_read_format(l->chan,AST_FORMAT_SLINEAR);
931                         ast_set_write_format(l->chan,AST_FORMAT_SLINEAR);
932                         l->chan->whentohangup = 0;
933                         l->chan->appl = "Apprpt";
934                         l->chan->data = "(Remote Rx)";
935                         if (option_verbose > 2)
936                                 ast_verbose(VERBOSE_PREFIX_3 "rpt (remote) initiating call to %s/%s on %s\n",
937                                         deststr,tele,l->chan->name);
938                         l->chan->callerid = strdup(myrpt->name);
939                         ast_call(l->chan,tele,999);
940                 }
941                 else
942                 {
943                         free(l);
944                         if (option_verbose > 2)
945                                 ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
946                                         deststr,tele,l->chan->name);
947                         return;
948                 }
949                 /* allocate a pseudo-channel thru asterisk */
950                 l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo");
951                 if (!l->pchan)
952                 {
953                         fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
954                         pthread_exit(NULL);
955                 }
956                 ast_set_read_format(l->pchan,AST_FORMAT_SLINEAR);
957                 ast_set_write_format(l->pchan,AST_FORMAT_SLINEAR);
958                 /* make a conference for the tx */
959                 ci.chan = 0;
960                 ci.confno = myrpt->conf;
961                 ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER;
962                 /* first put the channel on the conference in proper mode */
963                 if (ioctl(l->pchan->fds[0],ZT_SETCONF,&ci) == -1)
964                 {
965                         ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
966                         pthread_exit(NULL);
967                 }
968                 ast_mutex_lock(&myrpt->lock);
969                 /* insert at end of queue */
970                 insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
971                 ast_mutex_unlock(&myrpt->lock);
972                 break;
973         case 4: /* remote cmd mode */
974                 /* if doesnt allow link cmd, return */
975                 if ((!allow_linkcmd) || (myrpt->links.next == &myrpt->links)) return;
976                 /* if already in cmd mode, or selected self, forget it */
977                 if ((myrpt->cmdnode[0]) || (!strcmp(myrpt->name,cmd + 1)))
978                 {
979                         rpt_telemetry(myrpt,REMALREADY,NULL);
980                         return;
981                 }
982                 /* node must at least exist in list */
983                 val = ast_variable_retrieve(cfg,NODES,cmd + 1);
984                 if (!val)
985                 {
986                         rpt_telemetry(myrpt,REMNOTFOUND,NULL);
987                         return;
988                 }
989                 ast_mutex_lock(&myrpt->lock);
990                 myrpt->dtmfidx = -1;
991                 myrpt->dtmfbuf[0] = 0;
992                 myrpt->rem_dtmfidx = -1;
993                 myrpt->rem_dtmfbuf[0] = 0;
994                 strcpy(myrpt->cmdnode,cmd + 1);
995                 ast_mutex_unlock(&myrpt->lock);
996                 rpt_telemetry(myrpt,REMGO,NULL);                                
997                 return;
998         case 7: /* system status */
999                 rpt_telemetry(myrpt,STATUS,NULL);
1000                 return;
1001         case 8: /* force ID */
1002                 myrpt->idtimer = 0;
1003                 return;
1004         default:
1005                 return;
1006         }
1007         rpt_telemetry(myrpt,COMPLETE,NULL);
1008 }
1009
1010 static void handle_link_data(struct rpt *myrpt, char *str)
1011 {
1012 char    tmp[300],cmd[300],dest[300],src[300],c;
1013 int     seq;
1014 struct rpt_link *l;
1015 struct  ast_frame wf;
1016
1017         /* if we are a remote, we dont want to do this */
1018         if (myrpt->remote) return;
1019         wf.frametype = AST_FRAME_TEXT;
1020         wf.subclass = 0;
1021         wf.offset = 0;
1022         wf.mallocd = 1;
1023         wf.datalen = strlen(str) + 1;
1024         wf.samples = 0;
1025         l = myrpt->links.next;
1026         /* put string in our buffer */
1027         strncpy(tmp,str,sizeof(tmp) - 1);
1028         if (sscanf(tmp,"%s %s %s %d %c",cmd,dest,src,&seq,&c) != 5)
1029         {
1030                 ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
1031                 return;
1032         }
1033         if (strcmp(cmd,"D"))
1034         {
1035                 ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
1036                 return;
1037         }
1038         /* if not for me, redistribute to all links */
1039         if (strcmp(dest,myrpt->name))
1040         {
1041                 l = myrpt->links.next;
1042                 while(l != &myrpt->links)
1043                 {
1044                         if (!l->isremote)
1045                         {
1046                                 wf.data = strdup(str);
1047                                 ast_write(l->chan,&wf);
1048                         }
1049                         l = l->next;
1050                 }
1051                 return;
1052         }
1053         ast_mutex_lock(&myrpt->lock);
1054         if (c == '*')
1055         {
1056                 myrpt->rem_dtmfidx = 0;
1057                 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
1058                 time(&myrpt->rem_dtmf_time);
1059                 ast_mutex_unlock(&myrpt->lock);
1060                 return;
1061         } 
1062         else if ((c != '#') && (myrpt->rem_dtmfidx >= 0))
1063         {
1064                 time(&myrpt->rem_dtmf_time);
1065                 if (myrpt->rem_dtmfidx < MAXDTMF)
1066                 {
1067                         myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
1068                         myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
1069                         /* if to terminate function now */
1070                         if ((myrpt->rem_dtmfidx == 1) && strchr(SHORTFUNCS,c))
1071                         {
1072                                 while(myrpt->rem_dtmfidx < FUNCTION_LEN)
1073                                         myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = '0';
1074                                 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
1075                         }
1076                 }
1077                 if (myrpt->rem_dtmfidx == FUNCTION_LEN)
1078                 {
1079                         strcpy(cmd,myrpt->rem_dtmfbuf);
1080                         myrpt->rem_dtmfbuf[0] = 0;
1081                         myrpt->rem_dtmfidx = -1;
1082                         ast_mutex_unlock(&myrpt->lock);
1083                         process_dtmf(cmd,myrpt,0);
1084                         return;
1085                 }
1086         }
1087         ast_mutex_unlock(&myrpt->lock);
1088         return;
1089 }
1090
1091 /* single thread with one file (request) to dial */
1092 static void *rpt(void *this)
1093 {
1094 struct  rpt *myrpt = (struct rpt *)this;
1095 char *tele;
1096 int ms = MSWAIT,lasttx,keyed,val,remrx;
1097 struct ast_channel *who;
1098 ZT_CONFINFO ci;  /* conference info */
1099 time_t  dtmf_time,t;
1100 struct rpt_link *l,*m;
1101 pthread_attr_t attr;
1102
1103         ast_mutex_lock(&myrpt->lock);
1104         tele = strchr(myrpt->rxchanname,'/');
1105         if (!tele)
1106         {
1107                 fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
1108                 ast_mutex_unlock(&myrpt->lock);
1109                 pthread_exit(NULL);
1110         }
1111         *tele++ = 0;
1112         myrpt->rxchannel = ast_request(myrpt->rxchanname,AST_FORMAT_SLINEAR,tele);
1113         if (myrpt->rxchannel)
1114         {
1115                 ast_set_read_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
1116                 ast_set_write_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
1117                 myrpt->rxchannel->whentohangup = 0;
1118                 myrpt->rxchannel->appl = "Apprpt";
1119                 myrpt->rxchannel->data = "(Repeater Rx)";
1120                 if (option_verbose > 2)
1121                         ast_verbose(VERBOSE_PREFIX_3 "rpt (Rx) initiating call to %s/%s on %s\n",
1122                                 myrpt->rxchanname,tele,myrpt->rxchannel->name);
1123                 ast_call(myrpt->rxchannel,tele,999);
1124         }
1125         else
1126         {
1127                 fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
1128                 ast_mutex_unlock(&myrpt->lock);
1129                 pthread_exit(NULL);
1130         }
1131         if (myrpt->txchanname)
1132         {
1133                 tele = strchr(myrpt->txchanname,'/');
1134                 if (!tele)
1135                 {
1136                         fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
1137                         ast_mutex_unlock(&myrpt->lock);
1138                         pthread_exit(NULL);
1139                 }
1140                 *tele++ = 0;
1141                 myrpt->txchannel = ast_request(myrpt->txchanname,AST_FORMAT_SLINEAR,tele);
1142                 if (myrpt->txchannel)
1143                 {
1144                         ast_set_read_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
1145                         ast_set_write_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
1146                         myrpt->txchannel->whentohangup = 0;
1147                         myrpt->txchannel->appl = "Apprpt";
1148                         myrpt->txchannel->data = "(Repeater Rx)";
1149                         if (option_verbose > 2)
1150                                 ast_verbose(VERBOSE_PREFIX_3 "rpt (Tx) initiating call to %s/%s on %s\n",
1151                                         myrpt->txchanname,tele,myrpt->txchannel->name);
1152                         ast_call(myrpt->txchannel,tele,999);
1153                 }
1154                 else
1155                 {
1156                         fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
1157                         ast_mutex_unlock(&myrpt->lock);
1158                         pthread_exit(NULL);
1159                 }
1160         }
1161         else
1162         {
1163                 myrpt->txchannel = myrpt->rxchannel;
1164         }
1165         /* allocate a pseudo-channel thru asterisk */
1166         myrpt->pchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo");
1167         if (!myrpt->pchannel)
1168         {
1169                 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
1170                 ast_mutex_unlock(&myrpt->lock);
1171                 pthread_exit(NULL);
1172         }
1173         /* make a conference for the tx */
1174         ci.chan = 0;
1175         ci.confno = -1; /* make a new conf */
1176         ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER;
1177         /* first put the channel on the conference in proper mode */
1178         if (ioctl(myrpt->txchannel->fds[0],ZT_SETCONF,&ci) == -1)
1179         {
1180                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
1181                 ast_mutex_unlock(&myrpt->lock);
1182                 pthread_exit(NULL);
1183         }
1184         /* save tx conference number */
1185         myrpt->txconf = ci.confno;
1186         /* make a conference for the pseudo */
1187         ci.chan = 0;
1188         ci.confno = -1; /* make a new conf */
1189         ci.confmode = ZT_CONF_CONFANNMON; 
1190         /* first put the channel on the conference in announce mode */
1191         if (ioctl(myrpt->pchannel->fds[0],ZT_SETCONF,&ci) == -1)
1192         {
1193                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
1194                 ast_mutex_unlock(&myrpt->lock);
1195                 pthread_exit(NULL);
1196         }
1197         /* save pseudo channel conference number */
1198         myrpt->conf = ci.confno;
1199         /* allocate a pseudo-channel thru asterisk */
1200         myrpt->txpchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo");
1201         if (!myrpt->txpchannel)
1202         {
1203                 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
1204                 ast_mutex_unlock(&myrpt->lock);
1205                 pthread_exit(NULL);
1206         }
1207         /* make a conference for the tx */
1208         ci.chan = 0;
1209         ci.confno = myrpt->txconf;
1210         ci.confmode = ZT_CONF_CONF | ZT_CONF_TALKER ;
1211         /* first put the channel on the conference in proper mode */
1212         if (ioctl(myrpt->txpchannel->fds[0],ZT_SETCONF,&ci) == -1)
1213         {
1214                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
1215                 ast_mutex_unlock(&myrpt->lock);
1216                 pthread_exit(NULL);
1217         }
1218         /* Now, the idea here is to copy from the physical rx channel buffer
1219            into the pseudo tx buffer, and from the pseudo rx buffer into the 
1220            tx channel buffer */
1221         myrpt->links.next = &myrpt->links;
1222         myrpt->links.prev = &myrpt->links;
1223         myrpt->tailtimer = 0;
1224         myrpt->totimer = 0;
1225         myrpt->idtimer = 0;
1226         myrpt->callmode = 0;
1227         ast_mutex_unlock(&myrpt->lock);
1228         lasttx = 0;
1229         keyed = 0;
1230         myrpt->dtmfidx = -1;
1231         myrpt->dtmfbuf[0] = 0;
1232         myrpt->rem_dtmfidx = -1;
1233         myrpt->rem_dtmfbuf[0] = 0;
1234         dtmf_time = 0;
1235         myrpt->rem_dtmf_time = 0;
1236         val = 0;
1237         ast_channel_setoption(myrpt->rxchannel,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0);
1238         val = 1;
1239         ast_channel_setoption(myrpt->rxchannel,AST_OPTION_RELAXDTMF,&val,sizeof(char),0);
1240         while (ms >= 0)
1241         {
1242                 struct ast_frame *f;
1243                 struct ast_channel *cs[300];
1244                 int totx,elap,n,toexit;
1245
1246                 if (ast_check_hangup(myrpt->rxchannel)) break;
1247                 if (ast_check_hangup(myrpt->txchannel)) break;
1248                 if (ast_check_hangup(myrpt->pchannel)) break;
1249                 if (ast_check_hangup(myrpt->txpchannel)) break;
1250                 ast_mutex_lock(&myrpt->lock);
1251                 myrpt->localtx = keyed;
1252                 l = myrpt->links.next;
1253                 remrx = 0;
1254                 while(l != &myrpt->links)
1255                 {
1256                         if (l->lastrx) remrx = 1;
1257                         l = l->next;
1258                 }
1259                 totx = (keyed || myrpt->callmode || 
1260                         (myrpt->tele.next != &myrpt->tele));
1261                 myrpt->exttx = totx;
1262                 totx |= remrx;
1263                 if (!totx) myrpt->totimer = myrpt->totime;
1264                 else myrpt->tailtimer = myrpt->hangtime;
1265                 totx = (totx || myrpt->tailtimer) && myrpt->totimer;
1266                 /* if wants to transmit and in phone call, but timed out, 
1267                         reset time-out timer if keyed */
1268                 if ((!totx) && (!myrpt->totimer) && myrpt->callmode && keyed)
1269                 {
1270                         myrpt->totimer = myrpt->totime;
1271                         ast_mutex_unlock(&myrpt->lock);
1272                         continue;
1273                 }
1274                 /* if timed-out and in circuit busy after call */
1275                 if ((!totx) && (!myrpt->totimer) && (myrpt->callmode == 4))
1276                 {
1277                         myrpt->callmode = 0;
1278                 }
1279                 if (totx && (!myrpt->idtimer))
1280                 {
1281                         myrpt->idtimer = myrpt->idtime;
1282                         ast_mutex_unlock(&myrpt->lock);
1283                         rpt_telemetry(myrpt,ID,NULL);
1284                         ast_mutex_lock(&myrpt->lock);
1285                 }
1286                 if (totx && (!lasttx))
1287                 {
1288                         lasttx = 1;
1289                         ast_mutex_unlock(&myrpt->lock);
1290                         ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
1291                         ast_mutex_lock(&myrpt->lock);
1292                 }
1293                 if ((!totx) && lasttx)
1294                 {
1295                         lasttx = 0;
1296                         ast_mutex_unlock(&myrpt->lock);
1297                         ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
1298                         ast_mutex_lock(&myrpt->lock);
1299                 }
1300                 time(&t);
1301                 /* if DTMF timeout */
1302                 if ((!myrpt->cmdnode[0]) && (myrpt->dtmfidx >= 0) && ((dtmf_time + DTMF_TIMEOUT) < t))
1303                 {
1304                         myrpt->dtmfidx = -1;
1305                         myrpt->dtmfbuf[0] = 0;
1306                 }                       
1307                 /* if remote DTMF timeout */
1308                 if ((myrpt->rem_dtmfidx >= 0) && ((myrpt->rem_dtmf_time + DTMF_TIMEOUT) < t))
1309                 {
1310                         myrpt->rem_dtmfidx = -1;
1311                         myrpt->rem_dtmfbuf[0] = 0;
1312                 }                       
1313                 n = 0;
1314                 cs[n++] = myrpt->rxchannel;
1315                 cs[n++] = myrpt->pchannel;
1316                 cs[n++] = myrpt->txpchannel;
1317                 if (myrpt->txchannel != myrpt->rxchannel) cs[n++] = myrpt->txchannel;
1318                 l = myrpt->links.next;
1319                 while(l != &myrpt->links)
1320                 {
1321                         cs[n++] = l->chan;
1322                         cs[n++] = l->pchan;
1323                         l = l->next;
1324                 }
1325                 ast_mutex_unlock(&myrpt->lock);
1326                 ms = MSWAIT;
1327                 who = ast_waitfor_n(cs,n,&ms);
1328                 if (who == NULL) ms = 0;
1329                 elap = MSWAIT - ms;
1330                 ast_mutex_lock(&myrpt->lock);
1331                 l = myrpt->links.next;
1332                 while(l != &myrpt->links)
1333                 {
1334                         /* ignore non-timing channels */
1335                         if (l->elaptime < 0)
1336                         {
1337                                 l = l->next;
1338                                 continue;
1339                         }
1340                         l->elaptime += elap;
1341                         /* if connection has taken too long */
1342                         if ((l->elaptime > MAXCONNECTTIME) && 
1343                            (l->chan->_state != AST_STATE_UP))
1344                         {
1345                                 ast_mutex_unlock(&myrpt->lock);
1346                                 ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
1347                                 rpt_telemetry(myrpt,CONNFAIL,l);
1348                                 ast_mutex_lock(&myrpt->lock);
1349                         }
1350                         l = l->next;
1351                 }
1352                 if (myrpt->tailtimer) myrpt->tailtimer -= elap;
1353                 if (myrpt->tailtimer < 0) myrpt->tailtimer = 0;
1354                 if (myrpt->totimer) myrpt->totimer -= elap;
1355                 if (myrpt->totimer < 0) myrpt->totimer = 0;
1356                 if (myrpt->idtimer) myrpt->idtimer -= elap;
1357                 if (myrpt->idtimer < 0) myrpt->idtimer = 0;
1358                 ast_mutex_unlock(&myrpt->lock);
1359                 if (!ms) continue;
1360                 if (who == myrpt->rxchannel) /* if it was a read from rx */
1361                 {
1362                         f = ast_read(myrpt->rxchannel);
1363                         if (!f)
1364                         {
1365                                 if (debug) printf("@@@@ rpt:Hung Up\n");
1366                                 break;
1367                         }
1368                         if (f->frametype == AST_FRAME_VOICE)
1369                         {
1370                                 ast_write(myrpt->pchannel,f);
1371                         }
1372                         else if (f->frametype == AST_FRAME_DTMF)
1373                         {
1374                                 char c;
1375
1376                                 c = (char) f->subclass; /* get DTMF char */
1377                                 if (c == '#')
1378                                 {
1379                                         /* if in simple mode, kill autopatch */
1380                                         if (myrpt->simple && myrpt->callmode)
1381                                         {
1382                                                 myrpt->callmode = 0;
1383                                                 rpt_telemetry(myrpt,TERM,NULL);
1384                                                 continue;
1385                                         }
1386                                         ast_mutex_lock(&myrpt->lock);
1387                                         if (myrpt->cmdnode[0])
1388                                         {
1389                                                 myrpt->cmdnode[0] = 0;
1390                                                 myrpt->dtmfidx = -1;
1391                                                 myrpt->dtmfbuf[0] = 0;
1392                                                 ast_mutex_unlock(&myrpt->lock);
1393                                                 rpt_telemetry(myrpt,COMPLETE,NULL);
1394                                         } else ast_mutex_unlock(&myrpt->lock);
1395                                         continue;
1396                                 }
1397                                 if (myrpt->cmdnode[0])
1398                                 {
1399                                         send_link_dtmf(myrpt,c);
1400                                         continue;
1401                                 }
1402                                 if (!myrpt->simple)
1403                                 {
1404                                         if (c == '*')
1405                                         {
1406                                                 myrpt->dtmfidx = 0;
1407                                                 myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
1408                                                 time(&dtmf_time);
1409                                                 continue;
1410                                         } 
1411                                         else if ((c != '#') && (myrpt->dtmfidx >= 0))
1412                                         {
1413                                                 time(&dtmf_time);
1414                                                 if (myrpt->dtmfidx < MAXDTMF)
1415                                                 {
1416                                                         myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
1417                                                         myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
1418                                                         /* if to terminate function now */
1419                                                         if ((myrpt->dtmfidx == 1) && strchr(SHORTFUNCS,c))
1420                                                         {
1421                                                                 while(myrpt->dtmfidx < FUNCTION_LEN)
1422                                                                         myrpt->dtmfbuf[myrpt->dtmfidx++] = '0';
1423                                                                 myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
1424                                                         }
1425                                                 }
1426                                                 if (myrpt->dtmfidx == FUNCTION_LEN)
1427                                                 {
1428                                                         process_dtmf(myrpt->dtmfbuf,myrpt,1);
1429                                                         myrpt->dtmfbuf[0] = 0;
1430                                                         myrpt->dtmfidx = -1;
1431                                                         continue;
1432                                                 }
1433                                         }
1434                                 }
1435                                 else
1436                                 {
1437                                         if ((!myrpt->callmode) && (c == '*'))
1438                                         {
1439                                                 myrpt->callmode = 1;
1440                                                 myrpt->cidx = 0;
1441                                                 myrpt->exten[myrpt->cidx] = 0;
1442                                                 pthread_attr_init(&attr);
1443                                                 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1444                                                 pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *)myrpt);
1445                                                 continue;
1446                                         }
1447                                 }
1448                                 if (myrpt->callmode == 1)
1449                                 {
1450                                         myrpt->exten[myrpt->cidx++] = c;
1451                                         myrpt->exten[myrpt->cidx] = 0;
1452                                         /* if this exists */
1453                                         if (ast_exists_extension(myrpt->pchannel,myrpt->ourcontext,myrpt->exten,1,NULL))
1454                                         {
1455                                                 myrpt->callmode = 2;
1456                                                 rpt_telemetry(myrpt,PROC,NULL);
1457                                         }
1458                                         /* if can continue, do so */
1459                                         if (ast_canmatch_extension(myrpt->pchannel,myrpt->ourcontext,myrpt->exten,1,NULL)) continue;
1460                                         /* call has failed, inform user */
1461                                         myrpt->callmode = 4;
1462                                         continue;
1463                                 }
1464                                 if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
1465                                 {
1466                                         myrpt->mydtmf = f->subclass;
1467                                 }
1468                         }                                               
1469                         else if (f->frametype == AST_FRAME_CONTROL)
1470                         {
1471                                 if (f->subclass == AST_CONTROL_HANGUP)
1472                                 {
1473                                         if (debug) printf("@@@@ rpt:Hung Up\n");
1474                                         ast_frfree(f);
1475                                         break;
1476                                 }
1477                                 /* if RX key */
1478                                 if (f->subclass == AST_CONTROL_RADIO_KEY)
1479                                 {
1480                                         if (debug) printf("@@@@ rx key\n");
1481                                         keyed = 1;
1482                                 }
1483                                 /* if RX un-key */
1484                                 if (f->subclass == AST_CONTROL_RADIO_UNKEY)
1485                                 {
1486                                         if (debug) printf("@@@@ rx un-key\n");
1487                                         keyed = 0;
1488                                         /* if we have remotes, twiddle */
1489                                         if (myrpt->cmdnode[0] || (myrpt->links.next != &myrpt->links))
1490                                         {
1491                                                 rpt_telemetry(myrpt,UNKEY,NULL);
1492                                         }
1493                                 }
1494                         }
1495                         ast_frfree(f);
1496                         continue;
1497                 }
1498                 if (who == myrpt->pchannel) /* if it was a read from pseudo */
1499                 {
1500                         f = ast_read(myrpt->pchannel);
1501                         if (!f)
1502                         {
1503                                 if (debug) printf("@@@@ rpt:Hung Up\n");
1504                                 break;
1505                         }
1506                         if (f->frametype == AST_FRAME_VOICE)
1507                         {
1508                                 ast_write(myrpt->txpchannel,f);
1509                         }
1510                         if (f->frametype == AST_FRAME_CONTROL)
1511                         {
1512                                 if (f->subclass == AST_CONTROL_HANGUP)
1513                                 {
1514                                         if (debug) printf("@@@@ rpt:Hung Up\n");
1515                                         ast_frfree(f);
1516                                         break;
1517                                 }
1518                         }
1519                         ast_frfree(f);
1520                         continue;
1521                 }
1522                 if (who == myrpt->txchannel) /* if it was a read from tx */
1523                 {
1524                         f = ast_read(myrpt->txchannel);
1525                         if (!f)
1526                         {
1527                                 if (debug) printf("@@@@ rpt:Hung Up\n");
1528                                 break;
1529                         }
1530                         if (f->frametype == AST_FRAME_CONTROL)
1531                         {
1532                                 if (f->subclass == AST_CONTROL_HANGUP)
1533                                 {
1534                                         if (debug) printf("@@@@ rpt:Hung Up\n");
1535                                         ast_frfree(f);
1536                                         break;
1537                                 }
1538                         }
1539                         ast_frfree(f);
1540                         continue;
1541                 }
1542                 toexit = 0;
1543                 l = myrpt->links.next;
1544                 while(l != &myrpt->links)
1545                 {
1546                         if (who == l->chan) /* if it was a read from rx */
1547                         {
1548                                 ast_mutex_lock(&myrpt->lock);
1549                                 remrx = 0;
1550                                 /* see if any other links are receiving */
1551                                 m = myrpt->links.next;
1552                                 while(m != &myrpt->links)
1553                                 {
1554                                         /* if not us, count it */
1555                                         if ((m != l) && (m->lastrx)) remrx = 1;
1556                                         m = m->next;
1557                                 }
1558                                 ast_mutex_unlock(&myrpt->lock);
1559                                 totx = (((l->isremote) ? myrpt->localtx : 
1560                                         myrpt->exttx) || remrx) && l->mode;
1561                                 if (l->lasttx != totx)
1562                                 {
1563                                         if (totx)
1564                                         {
1565                                                 ast_indicate(l->chan,AST_CONTROL_RADIO_KEY);
1566                                         }
1567                                         else
1568                                         {
1569                                                 ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
1570                                         }
1571                                 }
1572                                 l->lasttx = totx;
1573                                 f = ast_read(l->chan);
1574                                 if (!f)
1575                                 {
1576                                         ast_mutex_lock(&myrpt->lock);
1577                                         /* remove from queue */
1578                                         remque((struct qelem *) l);
1579                                         ast_mutex_unlock(&myrpt->lock);
1580                                         rpt_telemetry(myrpt,REMDISC,l);
1581                                         /* hang-up on call to device */
1582                                         ast_hangup(l->chan);
1583                                         ast_hangup(l->pchan);
1584                                         free(l);
1585                                         break;
1586                                 }
1587                                 if (f->frametype == AST_FRAME_VOICE)
1588                                 {
1589                                         ast_write(l->pchan,f);
1590                                 }
1591                                 if (f->frametype == AST_FRAME_TEXT)
1592                                 {
1593                                         handle_link_data(myrpt,f->data);
1594                                 }
1595                                 if (f->frametype == AST_FRAME_CONTROL)
1596                                 {
1597                                         if (f->subclass == AST_CONTROL_ANSWER)
1598                                         {
1599                                                 l->connected = 1;
1600                                                 l->elaptime = -1;
1601                                                 rpt_telemetry(myrpt,CONNECTED,l);
1602                                         }
1603                                         /* if RX key */
1604                                         if (f->subclass == AST_CONTROL_RADIO_KEY)
1605                                         {
1606                                                 if (debug) printf("@@@@ rx key\n");
1607                                                 l->lastrx = 1;
1608                                         }
1609                                         /* if RX un-key */
1610                                         if (f->subclass == AST_CONTROL_RADIO_UNKEY)
1611                                         {
1612                                                 if (debug) printf("@@@@ rx un-key\n");
1613                                                 l->lastrx = 0;
1614                                         }
1615                                         if (f->subclass == AST_CONTROL_HANGUP)
1616                                         {
1617                                                 ast_frfree(f);
1618                                                 ast_mutex_lock(&myrpt->lock);
1619                                                 /* remove from queue */
1620                                                 remque((struct qelem *) l);
1621                                                 ast_mutex_unlock(&myrpt->lock);
1622                                                 rpt_telemetry(myrpt,REMDISC,l);
1623                                                 /* hang-up on call to device */
1624                                                 ast_hangup(l->chan);
1625                                                 ast_hangup(l->pchan);
1626                                                 free(l);
1627                                                 break;
1628                                         }
1629                                 }
1630                                 ast_frfree(f);
1631                                 break;
1632                         }
1633                         if (who == l->pchan) 
1634                         {
1635                                 f = ast_read(l->pchan);
1636                                 if (!f)
1637                                 {
1638                                         if (debug) printf("@@@@ rpt:Hung Up\n");
1639                                         toexit = 1;
1640                                         break;
1641                                 }
1642                                 if (f->frametype == AST_FRAME_VOICE)
1643                                 {
1644                                         ast_write(l->chan,f);
1645                                 }
1646                                 if (f->frametype == AST_FRAME_CONTROL)
1647                                 {
1648                                         if (f->subclass == AST_CONTROL_HANGUP)
1649                                         {
1650                                                 if (debug) printf("@@@@ rpt:Hung Up\n");
1651                                                 ast_frfree(f);
1652                                                 toexit = 1;
1653                                                 break;
1654                                         }
1655                                 }
1656                                 ast_frfree(f);
1657                                 break;
1658                         }
1659                         l = l->next;
1660                 }
1661                 if (toexit) break;
1662                 if (who == myrpt->txpchannel) /* if it was a read from remote tx */
1663                 {
1664                         f = ast_read(myrpt->txpchannel);
1665                         if (!f)
1666                         {
1667                                 if (debug) printf("@@@@ rpt:Hung Up\n");
1668                                 break;
1669                         }
1670                         if (f->frametype == AST_FRAME_CONTROL)
1671                         {
1672                                 if (f->subclass == AST_CONTROL_HANGUP)
1673                                 {
1674                                         if (debug) printf("@@@@ rpt:Hung Up\n");
1675                                         ast_frfree(f);
1676                                         break;
1677                                 }
1678                         }
1679                         ast_frfree(f);
1680                         continue;
1681                 }
1682         }
1683         ast_mutex_lock(&myrpt->lock);
1684         ast_hangup(myrpt->pchannel);
1685         ast_hangup(myrpt->txpchannel);
1686         ast_hangup(myrpt->rxchannel);
1687         if (myrpt->txchannel != myrpt->rxchannel) ast_hangup(myrpt->txchannel);
1688         l = myrpt->links.next;
1689         while(l != &myrpt->links)
1690         {
1691                 struct rpt_link *ll = l;
1692                 /* remove from queue */
1693                 remque((struct qelem *) l);
1694                 /* hang-up on call to device */
1695                 ast_hangup(l->chan);
1696                 ast_hangup(l->pchan);
1697                 l = l->next;
1698                 free(ll);
1699         }
1700         ast_mutex_unlock(&myrpt->lock);
1701         if (debug) printf("@@@@ rpt:Hung up channel\n");
1702         pthread_exit(NULL); 
1703         return NULL;
1704 }
1705
1706 static void *rpt_master(void *ignore)
1707 {
1708 char *this,*val;
1709 int     i,n;
1710
1711         /* start with blank config */
1712         memset(&rpt_vars,0,sizeof(rpt_vars));
1713
1714         cfg = ast_load("rpt.conf");
1715         if (!cfg) {
1716                 ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf.  Radio Repeater disabled.\n");
1717                 pthread_exit(NULL);
1718         }
1719
1720         /* go thru all the specified repeaters */
1721         this = NULL;
1722         n = 0;
1723         while((this = ast_category_browse(cfg,this)) != NULL)
1724         {
1725                 if (!strcmp(this,NODES)) continue;
1726                 ast_log(LOG_DEBUG,"Loading config for repeater %s\n",this);
1727                 ast_mutex_init(&rpt_vars[n].lock);
1728                 rpt_vars[n].tele.next = &rpt_vars[n].tele;
1729                 rpt_vars[n].tele.prev = &rpt_vars[n].tele;
1730                 rpt_vars[n].name = this;
1731                 rpt_vars[n].rxchanname = ast_variable_retrieve(cfg,this,"rxchannel");
1732                 rpt_vars[n].txchanname = ast_variable_retrieve(cfg,this,"txchannel");
1733                 rpt_vars[n].ourcontext = ast_variable_retrieve(cfg,this,"context");
1734                 if (!rpt_vars[n].ourcontext) rpt_vars[n].ourcontext = this;
1735                 rpt_vars[n].ourcallerid = ast_variable_retrieve(cfg,this,"callerid");
1736                 rpt_vars[n].acctcode = ast_variable_retrieve(cfg,this,"accountcode");
1737                 rpt_vars[n].ident = ast_variable_retrieve(cfg,this,"idrecording");
1738                 val = ast_variable_retrieve(cfg,this,"hangtime");
1739                 if (val) rpt_vars[n].hangtime = atoi(val);
1740                         else rpt_vars[n].hangtime = HANGTIME;
1741                 val = ast_variable_retrieve(cfg,this,"totime");
1742                 if (val) rpt_vars[n].totime = atoi(val);
1743                         else rpt_vars[n].totime = TOTIME;
1744                 val = ast_variable_retrieve(cfg,this,"idtime");
1745                 if (val) rpt_vars[n].idtime = atoi(val);
1746                         else rpt_vars[n].idtime = IDTIME;
1747                 val = ast_variable_retrieve(cfg,this,"simple");
1748                 if (val) rpt_vars[n].simple = ast_true(val); 
1749                         else rpt_vars[n].simple = 0;
1750                 val = ast_variable_retrieve(cfg,this,"remote");
1751                 if (val) rpt_vars[n].remote = ast_true(val); 
1752                         else rpt_vars[n].remote = 0;
1753                 rpt_vars[n].tonezone = ast_variable_retrieve(cfg,this,"tonezone");
1754                 n++;
1755         }
1756         nrpts = n;
1757         ast_log(LOG_DEBUG, "Total of %d repeaters configured.\n",n);
1758         /* start em all */
1759         for(i = 0; i < n; i++)
1760         {
1761                 if (!rpt_vars[i].rxchanname)
1762                 {
1763                         ast_log(LOG_WARNING,"Did not specify rxchanname for node %s\n",rpt_vars[i].name);
1764                         pthread_exit(NULL);
1765                 }
1766                 /* if is a remote, dont start one for it */
1767                 if (rpt_vars[i].remote) continue;
1768                 if (!rpt_vars[i].ident)
1769                 {
1770                         ast_log(LOG_WARNING,"Did not specify ident for node %s\n",rpt_vars[i].name);
1771                         pthread_exit(NULL);
1772                 }
1773                 pthread_create(&rpt_vars[i].rpt_thread,NULL,rpt,(void *) &rpt_vars[i]);
1774         }
1775         /* wait for first one to die (should be never) */
1776         pthread_join(rpt_vars[0].rpt_thread,NULL);
1777         pthread_exit(NULL);
1778 }
1779
1780 static int rpt_exec(struct ast_channel *chan, void *data)
1781 {
1782         int res=-1,i,keyed = 0,rem_totx;
1783         struct localuser *u;
1784         char tmp[256];
1785         char *options,*stringp,*tele;
1786         struct  rpt *myrpt;
1787         struct ast_frame *f;
1788         struct ast_channel *who;
1789         struct ast_channel *cs[20];
1790         struct  rpt_link *l;
1791         ZT_CONFINFO ci;  /* conference info */
1792         int ms,elap;
1793
1794         if (!data || ast_strlen_zero((char *)data)) {
1795                 ast_log(LOG_WARNING, "Rpt requires an argument (system node)\n");
1796                 return -1;
1797         }
1798         strncpy(tmp, (char *)data, sizeof(tmp)-1);
1799         stringp=tmp;
1800         strsep(&stringp, "|");
1801         options = strsep(&stringp, "|");
1802         myrpt = NULL;
1803         /* see if we can find our specified one */
1804         for(i = 0; i < nrpts; i++)
1805         {
1806                 /* if name matches, assign it and exit loop */
1807                 if (!strcmp(tmp,rpt_vars[i].name))
1808                 {
1809                         myrpt = &rpt_vars[i];
1810                         break;
1811                 }
1812         }
1813         if (myrpt == NULL)
1814         {
1815                 ast_log(LOG_WARNING, "Cannot find specified system node %s\n",tmp);
1816                 return -1;
1817         }
1818         /* if is not a remote */
1819         if (!myrpt->remote)
1820         {
1821                 char *b,*b1;
1822
1823                 /* look at callerid to see what node this comes from */
1824                 if (!chan->callerid) /* if doesnt have callerid */
1825                 {
1826                         ast_log(LOG_WARNING, "Trying to use busy link on %s\n",tmp);
1827                         return -1;
1828                 }
1829                 ast_callerid_parse(chan->callerid,&b,&b1);
1830                 ast_shrink_phone_number(b1);
1831                 if (!strcmp(myrpt->name,b1))
1832                 {
1833                         ast_log(LOG_WARNING, "Trying to link to self!!\n");
1834                         return -1;
1835                 }
1836                 ast_mutex_lock(&myrpt->lock);
1837                 l = myrpt->links.next;
1838                 /* try to find this one in queue */
1839                 while(l != &myrpt->links)
1840                 {
1841                         /* if found matching string */
1842                         if (!strcmp(l->name,b1)) break;
1843                 }
1844                 /* if found */
1845                 if (l != &myrpt->links) 
1846                 {
1847                         /* remove from queue */
1848                         remque((struct qelem *) l);
1849                         ast_mutex_unlock(&myrpt->lock);
1850                         /* hang-up on call to device */
1851                         ast_hangup(l->chan);
1852                         ast_hangup(l->pchan);
1853                         free(l);
1854                         usleep(500000); 
1855                 } else 
1856                         ast_mutex_unlock(&myrpt->lock);
1857                 /* establish call in tranceive mode */
1858                 l = malloc(sizeof(struct rpt_link));
1859                 if (!l)
1860                 {
1861                         ast_log(LOG_WARNING, "Unable to malloc\n");
1862                         pthread_exit(NULL);
1863                 }
1864                 /* zero the silly thing */
1865                 memset((char *)l,0,sizeof(struct rpt_link));
1866                 l->mode = 1;
1867                 strncpy(l->name,b1,MAXNODESTR - 1);
1868                 l->isremote = 0;
1869                 l->chan = chan;
1870                 l->connected = 1;
1871                 ast_set_read_format(l->chan,AST_FORMAT_SLINEAR);
1872                 ast_set_write_format(l->chan,AST_FORMAT_SLINEAR);
1873                 /* allocate a pseudo-channel thru asterisk */
1874                 l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo");
1875                 if (!l->pchan)
1876                 {
1877                         fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
1878                         pthread_exit(NULL);
1879                 }
1880                 ast_set_read_format(l->pchan,AST_FORMAT_SLINEAR);
1881                 ast_set_write_format(l->pchan,AST_FORMAT_SLINEAR);
1882                 /* make a conference for the tx */
1883                 ci.chan = 0;
1884                 ci.confno = myrpt->conf;
1885                 ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER;
1886                 /* first put the channel on the conference in proper mode */
1887                 if (ioctl(l->pchan->fds[0],ZT_SETCONF,&ci) == -1)
1888                 {
1889                         ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
1890                         pthread_exit(NULL);
1891                 }
1892                 ast_mutex_lock(&myrpt->lock);
1893                 /* insert at end of queue */
1894                 insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
1895                 ast_mutex_unlock(&myrpt->lock);
1896                 if (chan->_state != AST_STATE_UP) {
1897                         ast_answer(chan);
1898                 }
1899                 return AST_PBX_KEEPALIVE;
1900         }
1901         /* if remote, error if anyone else already linked */
1902         if (myrpt->remoteon)
1903         {
1904                 ast_mutex_unlock(&myrpt->lock);
1905                 ast_log(LOG_WARNING, "Trying to use busy link on %s\n",tmp);
1906                 return -1;
1907         }
1908         LOCAL_USER_ADD(u);
1909         tele = strchr(myrpt->rxchanname,'/');
1910         if (!tele)
1911         {
1912                 fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
1913                 ast_mutex_unlock(&myrpt->lock);
1914                 pthread_exit(NULL);
1915         }
1916         *tele++ = 0;
1917         ast_mutex_lock(&myrpt->lock);
1918         myrpt->rxchannel = ast_request(myrpt->rxchanname,AST_FORMAT_SLINEAR,tele);
1919         if (myrpt->rxchannel)
1920         {
1921                 ast_set_read_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
1922                 ast_set_write_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
1923                 myrpt->rxchannel->whentohangup = 0;
1924                 myrpt->rxchannel->appl = "Apprpt";
1925                 myrpt->rxchannel->data = "(Repeater Rx)";
1926                 if (option_verbose > 2)
1927                         ast_verbose(VERBOSE_PREFIX_3 "rpt (Rx) initiating call to %s/%s on %s\n",
1928                                 myrpt->rxchanname,tele,myrpt->rxchannel->name);
1929                 ast_mutex_unlock(&myrpt->lock);
1930                 ast_call(myrpt->rxchannel,tele,999);
1931                 ast_mutex_lock(&myrpt->lock);
1932         }
1933         else
1934         {
1935                 fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
1936                 ast_mutex_unlock(&myrpt->lock);
1937                 pthread_exit(NULL);
1938         }
1939         *--tele = '/';
1940         if (myrpt->txchanname)
1941         {
1942                 tele = strchr(myrpt->txchanname,'/');
1943                 if (!tele)
1944                 {
1945                         fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
1946                         ast_mutex_unlock(&myrpt->lock);
1947                         pthread_exit(NULL);
1948                 }
1949                 *tele++ = 0;
1950                 myrpt->txchannel = ast_request(myrpt->txchanname,AST_FORMAT_SLINEAR,tele);
1951                 if (myrpt->txchannel)
1952                 {
1953                         ast_set_read_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
1954                         ast_set_write_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
1955                         myrpt->txchannel->whentohangup = 0;
1956                         myrpt->txchannel->appl = "Apprpt";
1957                         myrpt->txchannel->data = "(Repeater Rx)";
1958                         if (option_verbose > 2)
1959                                 ast_verbose(VERBOSE_PREFIX_3 "rpt (Tx) initiating call to %s/%s on %s\n",
1960                                         myrpt->txchanname,tele,myrpt->txchannel->name);
1961                         ast_mutex_unlock(&myrpt->lock);
1962                         ast_call(myrpt->txchannel,tele,999);
1963                         ast_mutex_lock(&myrpt->lock);
1964                 }
1965                 else
1966                 {
1967                         fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
1968                         ast_mutex_unlock(&myrpt->lock);
1969                         pthread_exit(NULL);
1970                 }
1971                 *--tele = '/';
1972         }
1973         else
1974         {
1975                 myrpt->txchannel = myrpt->rxchannel;
1976         }
1977         myrpt->remoterx = 0;
1978         myrpt->remotetx = 0;
1979         myrpt->remoteon = 1;
1980         ast_mutex_unlock(&myrpt->lock);
1981         ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
1982         ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
1983         /* if we are on 2w loop and are a remote, turn EC on */
1984         if (myrpt->remote && (myrpt->rxchannel == myrpt->txchannel))
1985         {
1986                 i = 128;
1987                 ioctl(myrpt->rxchannel->fds[0],ZT_ECHOCANCEL,&i);
1988         }
1989         if (chan->_state != AST_STATE_UP) {
1990                 ast_answer(chan);
1991         }
1992         cs[0] = chan;
1993         cs[1] = myrpt->rxchannel;
1994         for(;;)
1995         {
1996                 if (ast_check_hangup(chan)) break;
1997                 if (ast_check_hangup(myrpt->rxchannel)) break;
1998                 ms = MSWAIT;
1999                 who = ast_waitfor_n(cs,2,&ms);
2000                 if (who == NULL) ms = 0;
2001                 elap = MSWAIT - ms;
2002                 if (!ms) continue;
2003                 rem_totx = keyed;
2004                 if (rem_totx && (!myrpt->remotetx))
2005                 {
2006                         myrpt->remotetx = 1;
2007                         ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
2008                 }
2009                 if ((!rem_totx) && myrpt->remotetx)
2010                 {
2011                         myrpt->remotetx = 0;
2012                         ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
2013                 }
2014                 if (who == chan) /* if it was a read from incomming */
2015                 {
2016                         f = ast_read(chan);
2017                         if (!f)
2018                         {
2019                                 if (debug) printf("@@@@ link:Hung Up\n");
2020                                 break;
2021                         }
2022                         if (f->frametype == AST_FRAME_VOICE)
2023                         {
2024                                 /* if not transmitting, zero-out audio */
2025                                 if (!myrpt->remotetx)
2026                                         memset(f->data,0,f->datalen);
2027                                 ast_write(myrpt->txchannel,f);
2028                         }
2029                         else if (f->frametype == AST_FRAME_TEXT)
2030                         {
2031                                 handle_link_data(myrpt,f->data);
2032                         }
2033                         else if (f->frametype == AST_FRAME_CONTROL)
2034                         {
2035                                 if (f->subclass == AST_CONTROL_HANGUP)
2036                                 {
2037                                         if (debug) printf("@@@@ rpt:Hung Up\n");
2038                                         ast_frfree(f);
2039                                         break;
2040                                 }
2041                                 /* if RX key */
2042                                 if (f->subclass == AST_CONTROL_RADIO_KEY)
2043                                 {
2044                                         if (debug) printf("@@@@ rx key\n");
2045                                         keyed = 1;
2046                                 }
2047                                 /* if RX un-key */
2048                                 if (f->subclass == AST_CONTROL_RADIO_UNKEY)
2049                                 {
2050                                         if (debug) printf("@@@@ rx un-key\n");
2051                                         keyed = 0;
2052                                 }
2053                         }
2054                         ast_frfree(f);
2055                         continue;
2056                 }
2057                 if (who == myrpt->rxchannel) /* if it was a read from radio */
2058                 {
2059                         f = ast_read(myrpt->rxchannel);
2060                         if (!f)
2061                         {
2062                                 if (debug) printf("@@@@ link:Hung Up\n");
2063                                 break;
2064                         }
2065                         if (f->frametype == AST_FRAME_VOICE)
2066                         {
2067                                 if ((myrpt->remote) && (myrpt->remotetx))
2068                                         memset(f->data,0,f->datalen);
2069                                  ast_write(chan,f);
2070                         }
2071                         else if (f->frametype == AST_FRAME_CONTROL)
2072                         {
2073                                 if (f->subclass == AST_CONTROL_HANGUP)
2074                                 {
2075                                         if (debug) printf("@@@@ rpt:Hung Up\n");
2076                                         ast_frfree(f);
2077                                         break;
2078                                 }
2079                                 /* if RX key */
2080                                 if (f->subclass == AST_CONTROL_RADIO_KEY)
2081                                 {
2082                                         if (debug) printf("@@@@ remote rx key\n");
2083                                         if (!myrpt->remotetx)
2084                                         {
2085                                                 ast_indicate(chan,AST_CONTROL_RADIO_KEY);
2086                                                 myrpt->remoterx = 1;
2087                                         }
2088                                 }
2089                                 /* if RX un-key */
2090                                 if (f->subclass == AST_CONTROL_RADIO_UNKEY)
2091                                 {
2092                                         if (debug) printf("@@@@ remote rx un-key\n");
2093                                         if (!myrpt->remotetx) 
2094                                         {
2095                                                 ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
2096                                                 myrpt->remoterx = 0;
2097                                         }
2098                                 }
2099                         }
2100                         ast_frfree(f);
2101                         continue;
2102                 }
2103
2104         }
2105         ast_mutex_lock(&myrpt->lock);
2106         if (myrpt->rxchannel != myrpt->txchannel) ast_hangup(myrpt->txchannel);
2107         ast_hangup(myrpt->rxchannel);
2108         myrpt->remoteon = 0;
2109         ast_mutex_unlock(&myrpt->lock);
2110         LOCAL_USER_REMOVE(u);
2111         return res;
2112 }
2113
2114 int unload_module(void)
2115 {
2116         STANDARD_HANGUP_LOCALUSERS;
2117         return ast_unregister_application(app);
2118         return 0;
2119 }
2120
2121 int load_module(void)
2122 {
2123         pthread_create(&rpt_master_thread,NULL,rpt_master,NULL);
2124         return ast_register_application(app, rpt_exec, synopsis, descrip);
2125 }
2126
2127 char *description(void)
2128 {
2129         return tdesc;
2130 }
2131
2132 int usecount(void)
2133 {
2134         int res;
2135         STANDARD_USECOUNT(res);
2136         return res;
2137 }
2138
2139 char *key()
2140 {
2141         return ASTERISK_GPL_KEY;
2142 }