Complete re-vamp of Radio Repeater application (app_rpt) and VERY minor changes in...
[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.2 5/30/04
7  * 
8  * Copyright (C) 2002-2004, Jim Dixon
9  *
10  * Jim Dixon <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 access
19  *  *1 - remote base off
20  *  *2 - remote base monitor
21  *  *3 - remote base tranceive
22  *  *8 - force ID
23  *  *9 - system reset
24  *
25  *  To send an asterisk (*) while dialing or talking on phone,
26  *  use the autopatch acess code.
27  */
28  
29 /* number of digits for function after *. Must be at least 1 */
30 #define FUNCTION_LEN 1
31
32 /* maximum digits in DTMF buffer, and seconds after * for DTMF command timeout */
33
34 #define MAXDTMF 10
35 #define DTMF_TIMEOUT 3
36
37 enum {REM_OFF,REM_MONITOR,REM_TX};
38
39 #include <asterisk/lock.h>
40 #include <asterisk/file.h>
41 #include <asterisk/logger.h>
42 #include <asterisk/channel.h>
43 #include <asterisk/pbx.h>
44 #include <asterisk/module.h>
45 #include <asterisk/translate.h>
46 #include <asterisk/options.h>
47 #include <asterisk/config.h>
48 #include <stdio.h>
49 #include <unistd.h>
50 #include <string.h>
51 #include <stdlib.h>
52 #include <pthread.h>
53 #include <sys/types.h>
54 #include <sys/stat.h>
55 #include <errno.h>
56 #include <dirent.h>
57 #include <ctype.h>
58 #include <sys/stat.h>
59 #include <sys/time.h>
60 #include <sys/file.h>
61 #include <sys/ioctl.h>
62 #include <math.h>
63 #include <tonezone.h>
64 #include <linux/zaptel.h>
65
66 static  char *tdesc = "Radio Repeater / Remote Base  version 0.2  05/30/2004";
67 static int debug = 0;
68 STANDARD_LOCAL_USER;
69 LOCAL_USER_DECL;
70
71 #define MSWAIT 200
72 #define HANGTIME 5000
73 #define TOTIME 180000
74 #define IDTIME 300000
75 #define MAXRPTS 20
76
77 static  pthread_t rpt_master_thread;
78
79 static struct rpt
80 {
81         char *name;
82         char *rxchanname;
83         char *txchanname;
84         char *rem_rxchanname;
85         char *rem_txchanname;
86         char *ourcontext;
87         char *ourcallerid;
88         char *acctcode;
89         char *idrecording;
90         char *tonezone;
91         int hangtime;
92         int totime;
93         int idtime;
94         char remoterx;
95         char remotetx;
96         char remotemode;
97         char simple;
98         struct ast_channel *rxchannel,*txchannel,*rem_rxchannel;
99         struct ast_channel *rem_txchannel,*pchannel;
100         int tailtimer,totimer,idtimer,txconf,pconf,callmode,cidx;
101         pthread_t rpt_id_thread,rpt_term_thread,rpt_proc_thread,rpt_call_thread;
102         char mydtmf,iding,terming,teleing,comping,procing;
103         char exten[AST_MAX_EXTENSION];
104 } rpt_vars[MAXRPTS];            
105
106
107 static void *rpt_id(void *this)
108 {
109 ZT_CONFINFO ci;  /* conference info */
110 int     res;
111 struct  rpt *myrpt = (struct rpt *)this;
112 struct ast_channel *mychannel;
113
114         /* allocate a pseudo-channel thru asterisk */
115         mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo");
116         if (!mychannel)
117         {
118                 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
119                 pthread_exit(NULL);
120         }
121         /* make a conference for the tx */
122         ci.chan = 0;
123         ci.confno = myrpt->txconf; /* use the tx conference */
124         ci.confmode = ZT_CONF_CONFANN;
125         /* first put the channel on the conference in announce mode */
126         if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
127         {
128                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
129                 pthread_exit(NULL);
130         }
131         myrpt->iding = 1;
132         ast_stopstream(mychannel);
133         res = ast_streamfile(mychannel, myrpt->idrecording, mychannel->language);
134         if (!res) 
135                 res = ast_waitstream(mychannel, "");
136         else {
137                 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
138                 res = 0;
139         }
140         myrpt->iding = 0;
141         ast_stopstream(mychannel);
142         ast_hangup(mychannel);
143         pthread_exit(NULL);
144 }
145
146 static void *rpt_proc(void *this)
147 {
148 ZT_CONFINFO ci;  /* conference info */
149 int     res;
150 struct  rpt *myrpt = (struct rpt *)this;
151 struct ast_channel *mychannel;
152
153         /* wait a little bit */
154         usleep(1500000);
155         /* allocate a pseudo-channel thru asterisk */
156         mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo");
157         if (!mychannel)
158         {
159                 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
160                 pthread_exit(NULL);
161         }
162         /* make a conference for the tx */
163         ci.chan = 0;
164         ci.confno = myrpt->txconf; /* use the tx conference */
165         ci.confmode = ZT_CONF_CONFANN;
166         /* first put the channel on the conference in announce mode */
167         if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
168         {
169                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
170                 pthread_exit(NULL);
171         }
172         myrpt->procing = 1;
173         ast_stopstream(mychannel);
174         res = ast_streamfile(mychannel, "callproceeding", mychannel->language);
175         if (!res) 
176                 res = ast_waitstream(mychannel, "");
177         else {
178                 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
179                 res = 0;
180         }
181         myrpt->procing = 0;
182         ast_stopstream(mychannel);
183         ast_hangup(mychannel);
184         pthread_exit(NULL);
185 }
186
187 static void *rpt_term(void *this)
188 {
189 ZT_CONFINFO ci;  /* conference info */
190 int     res;
191 struct  rpt *myrpt = (struct rpt *)this;
192 struct ast_channel *mychannel;
193
194         /* wait a little bit */
195         usleep(1500000);
196         /* allocate a pseudo-channel thru asterisk */
197         mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo");
198         if (!mychannel)
199         {
200                 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
201                 pthread_exit(NULL);
202         }
203         /* make a conference for the tx */
204         ci.chan = 0;
205         ci.confno = myrpt->txconf; /* use the tx conference */
206         ci.confmode = ZT_CONF_CONFANN;
207         /* first put the channel on the conference in announce mode */
208         if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
209         {
210                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
211                 pthread_exit(NULL);
212         }
213         myrpt->terming = 1;
214         ast_stopstream(mychannel);
215         res = ast_streamfile(mychannel, "callterminated", mychannel->language);
216         if (!res) 
217                 res = ast_waitstream(mychannel, "");
218         else {
219                 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
220                 res = 0;
221         }
222         myrpt->terming = 0;
223         ast_stopstream(mychannel);
224         ast_hangup(mychannel);
225         pthread_exit(NULL);
226 }
227
228 static void *rpt_complete(void *this)
229 {
230 ZT_CONFINFO ci;  /* conference info */
231 int     res;
232 struct  rpt *myrpt = (struct rpt *)this;
233 struct ast_channel *mychannel;
234
235         /* wait a little bit */
236         usleep(1000000);
237         /* allocate a pseudo-channel thru asterisk */
238         mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo");
239         if (!mychannel)
240         {
241                 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
242                 pthread_exit(NULL);
243         }
244         /* make a conference for the tx */
245         ci.chan = 0;
246         ci.confno = myrpt->txconf; /* use the tx conference */
247         ci.confmode = ZT_CONF_CONFANN;
248         /* first put the channel on the conference in announce mode */
249         if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
250         {
251                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
252                 pthread_exit(NULL);
253         }
254         myrpt->comping = 1;
255         ast_stopstream(mychannel);
256         res = ast_streamfile(mychannel, "functioncomplete", mychannel->language);
257         if (!res) 
258                 res = ast_waitstream(mychannel, "");
259         else {
260                 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
261                 res = 0;
262         }
263         myrpt->comping = 0;
264         ast_stopstream(mychannel);
265         ast_hangup(mychannel);
266         pthread_exit(NULL);
267 }
268
269 static void *rpt_remote_telemetry(void *this)
270 {
271 ZT_CONFINFO ci;  /* conference info */
272 int res;
273 struct  rpt *myrpt = (struct rpt *)this;
274 struct ast_channel *mychannel;
275
276         /* wait a little bit */
277         usleep(1000000);
278         /* allocate a pseudo-channel thru asterisk */
279         mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo");
280         if (!mychannel)
281         {
282                 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
283                 pthread_exit(NULL);
284         }
285         /* make a conference for the tx */
286         ci.chan = 0;
287         ci.confno = myrpt->txconf; /* use the tx conference */
288         ci.confmode = ZT_CONF_CONFANN;
289         /* first put the channel on the conference in announce mode */
290         if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
291         {
292                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
293                 pthread_exit(NULL);
294         }
295         myrpt->teleing = 1;
296         ast_stopstream(mychannel);
297         res = ast_streamfile(mychannel, 
298                 ((myrpt->remotemode == REM_MONITOR) ? "remote_monitor" : "remote_tx"),
299                         mychannel->language);
300         if (!res) 
301                 res = ast_waitstream(mychannel, "");
302         else {
303                 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
304                 res = 0;
305         }
306         myrpt->teleing = 0;
307         ast_hangup(mychannel);
308         pthread_exit(NULL);
309 }
310
311 static void *rpt_call(void *this)
312 {
313 ZT_CONFINFO ci;  /* conference info */
314 struct  rpt *myrpt = (struct rpt *)this;
315 int     res;
316 struct  ast_frame *f,wf;
317 int stopped,congstarted;
318 struct ast_channel *mychannel,*genchannel;
319
320         myrpt->mydtmf = 0;
321         /* allocate a pseudo-channel thru asterisk */
322         mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo");
323         if (!mychannel)
324         {
325                 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
326                 pthread_exit(NULL);
327         }
328         ci.chan = 0;
329         ci.confno = myrpt->pconf; /* use the pseudo conference */
330         ci.confmode = ZT_CONF_REALANDPSEUDO | ZT_CONF_TALKER | ZT_CONF_LISTENER
331                 | ZT_CONF_PSEUDO_TALKER | ZT_CONF_PSEUDO_LISTENER; 
332         /* first put the channel on the conference */
333         if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
334         {
335                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
336                 ast_hangup(mychannel);
337                 myrpt->callmode = 0;
338                 pthread_exit(NULL);
339         }
340         /* allocate a pseudo-channel thru asterisk */
341         genchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo");
342         if (!genchannel)
343         {
344                 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
345                 ast_hangup(mychannel);
346                 pthread_exit(NULL);
347         }
348         ci.chan = 0;
349         ci.confno = myrpt->pconf;
350         ci.confmode = ZT_CONF_REALANDPSEUDO | ZT_CONF_TALKER | ZT_CONF_LISTENER
351                 | ZT_CONF_PSEUDO_TALKER | ZT_CONF_PSEUDO_LISTENER; 
352         /* first put the channel on the conference */
353         if (ioctl(genchannel->fds[0],ZT_SETCONF,&ci) == -1)
354         {
355                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
356                 ast_hangup(mychannel);
357                 ast_hangup(genchannel);
358                 myrpt->callmode = 0;
359                 pthread_exit(NULL);
360         }
361         if (myrpt->tonezone && (tone_zone_set_zone(mychannel->fds[0],myrpt->tonezone) == -1))
362         {
363                 ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->tonezone);
364                 ast_hangup(mychannel);
365                 ast_hangup(genchannel);
366                 myrpt->callmode = 0;
367                 pthread_exit(NULL);
368         }
369         if (myrpt->tonezone && (tone_zone_set_zone(genchannel->fds[0],myrpt->tonezone) == -1))
370         {
371                 ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->tonezone);
372                 ast_hangup(mychannel);
373                 ast_hangup(genchannel);
374                 myrpt->callmode = 0;
375                 pthread_exit(NULL);
376         }
377         /* start dialtone */
378         if (tone_zone_play_tone(mychannel->fds[0],ZT_TONE_DIALTONE) < 0)
379         {
380                 ast_log(LOG_WARNING, "Cannot start dialtone\n");
381                 ast_hangup(mychannel);
382                 ast_hangup(genchannel);
383                 myrpt->callmode = 0;
384                 pthread_exit(NULL);
385         }
386         stopped = 0;
387         congstarted = 0;
388         while ((myrpt->callmode == 1) || (myrpt->callmode == 4))
389         {
390
391                 if ((myrpt->callmode == 1) && (myrpt->cidx > 0) && (!stopped))
392                 {
393                         stopped = 1;
394                         /* stop dial tone */
395                         tone_zone_play_tone(mychannel->fds[0],-1);
396                 }
397                 if ((myrpt->callmode == 4) && (!congstarted))
398                 {
399                         congstarted = 1;
400                         /* start congestion tone */
401                         tone_zone_play_tone(mychannel->fds[0],ZT_TONE_CONGESTION);
402                 }
403                 res = ast_waitfor(mychannel, MSWAIT);
404                 if (res < 0)
405                 {
406                         ast_hangup(mychannel);
407                         ast_hangup(genchannel);
408                         myrpt->callmode = 0;
409                         pthread_exit(NULL);
410                 }
411                 if (res == 0) continue;
412                 f = ast_read(mychannel);
413                 if (f == NULL) 
414                 {
415                         ast_hangup(mychannel);
416                         ast_hangup(genchannel);
417                         myrpt->callmode = 0;
418                         pthread_exit(NULL);                     
419                 }
420                 if ((f->frametype == AST_FRAME_CONTROL) &&
421                     (f->subclass == AST_CONTROL_HANGUP))
422                 {
423                         ast_frfree(f);
424                         ast_hangup(mychannel);
425                         ast_hangup(genchannel);
426                         myrpt->callmode = 0;
427                         pthread_exit(NULL);                     
428                 }
429                 ast_frfree(f);
430         }
431         /* stop any tone generation */
432         tone_zone_play_tone(mychannel->fds[0],-1);
433         /* end if done */
434         if (!myrpt->callmode)
435         {
436                 ast_hangup(mychannel);
437                 ast_hangup(genchannel);
438                 myrpt->callmode = 0;
439                 pthread_exit(NULL);                     
440         }
441         if (myrpt->ourcallerid && *myrpt->ourcallerid)
442         {
443                 if (mychannel->callerid) free(mychannel->callerid);
444                 mychannel->callerid = strdup(myrpt->ourcallerid);
445         }
446         strcpy(mychannel->exten,myrpt->exten);
447         strcpy(mychannel->context,myrpt->ourcontext);
448         if (myrpt->acctcode)
449                 strcpy(mychannel->accountcode,myrpt->acctcode);
450         mychannel->priority = 1;
451         ast_channel_undefer_dtmf(mychannel);
452         if (ast_pbx_start(mychannel) < 0)
453         {
454                 ast_log(LOG_WARNING, "Unable to start PBX!!\n");
455                 ast_hangup(mychannel);
456                 ast_hangup(genchannel);
457                 myrpt->callmode = 0;
458                 pthread_exit(NULL);
459         }
460         myrpt->callmode = 3;
461
462         while(myrpt->callmode)
463         {
464                 if ((!mychannel->pvt) && (myrpt->callmode != 4))
465                 {
466                         myrpt->callmode = 4;
467                         /* start congestion tone */
468                         tone_zone_play_tone(genchannel->fds[0],ZT_TONE_CONGESTION);
469                 }
470                 if (myrpt->mydtmf)
471                 {
472                         wf.frametype = AST_FRAME_DTMF;
473                         wf.subclass = myrpt->mydtmf;
474                         wf.offset = 0;
475                         wf.mallocd = 0;
476                         wf.data = NULL;
477                         wf.datalen = 0;
478                         wf.samples = 0;
479                         ast_write(genchannel,&wf); 
480                         myrpt->mydtmf = 0;
481                 }
482                 usleep(25000);
483         }
484         tone_zone_play_tone(genchannel->fds[0],-1);
485         if (mychannel->pvt) ast_softhangup(mychannel,AST_SOFTHANGUP_DEV);
486         ast_hangup(genchannel);
487         myrpt->callmode = 0;
488         pthread_exit(NULL);
489 }
490
491 static void process_dtmf(char *cmd,struct rpt *myrpt)
492 {
493 pthread_attr_t attr;
494 ZT_CONFINFO ci;  /* conference info */
495
496         switch(atoi(cmd))
497         {
498         case 0: /* autopatch on / send asterisk (*) */
499                 /* if on call, force * into current audio stream */
500                 if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
501                 {
502                         myrpt->mydtmf = '*';
503                         break;
504                 }
505                 if (myrpt->callmode) return;
506                 myrpt->callmode = 1;
507                 myrpt->cidx = 0;
508                 myrpt->exten[myrpt->cidx] = 0;
509                 pthread_attr_init(&attr);
510                 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
511                 pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *)myrpt);
512                 return;
513         case 9: /* master reset */
514                 myrpt->callmode = 0;
515                 /* fall thru intentionally */
516         case 1: /* remote base off */
517                 if (myrpt->rem_rxchannel == NULL) return;
518                 myrpt->remotemode = REM_OFF;
519                 ci.chan = 0;
520                 ci.confno = 0;
521                 ci.confmode = 0;
522                 /* Take off conf */
523                 if (ioctl(myrpt->rem_rxchannel->fds[0],ZT_SETCONF,&ci) == -1)
524                 {
525                         ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
526                         pthread_exit(NULL);
527                 }
528                 /* Take off conf */
529                 if (ioctl(myrpt->rem_txchannel->fds[0],ZT_SETCONF,&ci) == -1)
530                 {
531                         ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
532                         pthread_exit(NULL);
533                 }
534                 break;
535         case 2: /* remote base monitor */
536                 if (myrpt->rem_rxchannel == NULL) return;
537                 myrpt->remotemode = REM_MONITOR;
538                 if (myrpt->remoterx && (!myrpt->remotetx))
539                 {
540                         ci.chan = 0;
541                         ci.confno = myrpt->pconf;
542                         ci.confmode = ZT_CONF_CONF | ZT_CONF_TALKER;
543                         /* Put on conf */
544                         if (ioctl(myrpt->rem_rxchannel->fds[0],ZT_SETCONF,&ci) == -1)
545                         {
546                                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
547                                 pthread_exit(NULL);
548                         }
549                 }
550                 break;
551         case 3: /* remote base tranceieve */
552                 if (myrpt->rem_rxchannel == NULL) return;
553                 myrpt->remotemode = REM_TX;
554                 if (myrpt->remoterx && (!myrpt->remotetx))
555                 {
556                         ci.chan = 0;
557                         ci.confno = myrpt->pconf;
558                         ci.confmode = ZT_CONF_CONF | ZT_CONF_TALKER;
559                         /* Put on conf */
560                         if (ioctl(myrpt->rem_rxchannel->fds[0],ZT_SETCONF,&ci) == -1)
561                         {
562                                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
563                                 pthread_exit(NULL);
564                         }
565                 }
566                 break;
567         case 8: /* force ID */
568                 myrpt->idtimer = 0;
569                 return;
570         default:
571                 return;
572         }
573         /* send function complete */
574         pthread_attr_init(&attr);
575         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
576         pthread_create(&myrpt->rpt_call_thread,&attr,rpt_complete,(void *)myrpt);
577 }
578
579 /* single thread with one file (request) to dial */
580 static void *rpt(void *this)
581 {
582 struct  rpt *myrpt = (struct rpt *)this;
583 char *tele;
584 int ms = MSWAIT,lasttx,keyed,val,dtmfidx;
585 char dtmfbuf[MAXDTMF];
586 struct ast_channel *who;
587 ZT_CONFINFO ci;  /* conference info */
588 time_t  dtmf_time,t;
589 pthread_attr_t attr;
590
591         tele = strchr(myrpt->rxchanname,'/');
592         if (!tele)
593         {
594                 fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
595                 pthread_exit(NULL);
596         }
597         *tele++ = 0;
598         myrpt->rxchannel = ast_request(myrpt->rxchanname,AST_FORMAT_SLINEAR,tele);
599         if (myrpt->rxchannel)
600         {
601                 ast_set_read_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
602                 ast_set_write_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
603                 myrpt->rxchannel->whentohangup = 0;
604                 myrpt->rxchannel->appl = "Apprpt";
605                 myrpt->rxchannel->data = "(Repeater Rx)";
606                 if (option_verbose > 2)
607                         ast_verbose(VERBOSE_PREFIX_3 "rpt (Rx) initiating call to %s/%s on %s\n",
608                                 myrpt->rxchanname,tele,myrpt->rxchannel->name);
609                 ast_call(myrpt->rxchannel,tele,999);
610         }
611         else
612         {
613                 fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
614                 pthread_exit(NULL);
615         }
616         if (myrpt->txchanname)
617         {
618                 tele = strchr(myrpt->txchanname,'/');
619                 if (!tele)
620                 {
621                         fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
622                         pthread_exit(NULL);
623                 }
624                 *tele++ = 0;
625                 myrpt->txchannel = ast_request(myrpt->txchanname,AST_FORMAT_SLINEAR,tele);
626                 if (myrpt->txchannel)
627                 {
628                         ast_set_read_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
629                         ast_set_write_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
630                         myrpt->txchannel->whentohangup = 0;
631                         myrpt->txchannel->appl = "Apprpt";
632                         myrpt->txchannel->data = "(Repeater Rx)";
633                         if (option_verbose > 2)
634                                 ast_verbose(VERBOSE_PREFIX_3 "rpt (Tx) initiating call to %s/%s on %s\n",
635                                         myrpt->txchanname,tele,myrpt->txchannel->name);
636                         ast_call(myrpt->txchannel,tele,999);
637                 }
638                 else
639                 {
640                         fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
641                         pthread_exit(NULL);
642                 }
643         }
644         else
645         {
646                 myrpt->txchannel = myrpt->rxchannel;
647         }
648         myrpt->rem_rxchannel = NULL;
649         myrpt->rem_txchannel = NULL;
650         myrpt->remoterx = 0;
651         myrpt->remotemode = REM_OFF;
652         if (myrpt->rem_rxchanname)
653         {
654                 tele = strchr(myrpt->rem_rxchanname,'/');
655                 if (!tele)
656                 {
657                         fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
658                         pthread_exit(NULL);
659                 }
660                 *tele++ = 0;
661                 myrpt->rem_rxchannel = ast_request(myrpt->rem_rxchanname,AST_FORMAT_SLINEAR,tele);
662                 if (myrpt->rem_rxchannel)
663                 {
664                         ast_set_read_format(myrpt->rem_rxchannel,AST_FORMAT_SLINEAR);
665                         ast_set_write_format(myrpt->rem_rxchannel,AST_FORMAT_SLINEAR);
666                         myrpt->rem_rxchannel->whentohangup = 0;
667                         myrpt->rem_rxchannel->appl = "Apprpt";
668                         myrpt->rem_rxchannel->data = "(Repeater/Remote Rx)";
669                         if (option_verbose > 2)
670                                 ast_verbose(VERBOSE_PREFIX_3 "rpt (RemoteRx) initiating call to %s/%s on %s\n",
671                                         myrpt->rem_rxchanname,tele,myrpt->rem_rxchannel->name);
672                         ast_call(myrpt->rem_rxchannel,tele,999);
673                 }
674                 else
675                 {
676                         fprintf(stderr,"rpt:Sorry unable to obtain RemoteRx channel\n");
677                         pthread_exit(NULL);
678                 }
679                 if (myrpt->rem_txchanname)  /* if in remote base mode */
680                 {
681                         tele = strchr(myrpt->rem_txchanname,'/');
682                         if (!tele)
683                         {
684                                 fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
685                                 pthread_exit(NULL);
686                         }
687                         *tele++ = 0;
688                         myrpt->rem_txchannel = ast_request(myrpt->rem_txchanname,AST_FORMAT_SLINEAR,tele);
689                         if (myrpt->rem_txchannel)
690                         {
691                                 ast_set_read_format(myrpt->rem_txchannel,AST_FORMAT_SLINEAR);
692                                 ast_set_write_format(myrpt->rem_txchannel,AST_FORMAT_SLINEAR);
693                                 myrpt->rem_txchannel->whentohangup = 0;
694                                 myrpt->rem_txchannel->appl = "Apprpt";
695                                 myrpt->rem_txchannel->data = "(Repeater/Remote Tx)";
696                                 if (option_verbose > 2)
697                                         ast_verbose(VERBOSE_PREFIX_3 "rpt (RemoteTx) initiating call to %s/%s on %s\n",
698                                                 myrpt->rem_txchanname,tele,myrpt->rem_txchannel->name);
699                                 ast_call(myrpt->rem_txchannel,tele,999);
700                         }
701                         else
702                         {
703                                 fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
704                                 pthread_exit(NULL);
705                         }
706                 }
707                 else
708                 {
709                         myrpt->rem_txchannel = myrpt->rem_rxchannel;
710                 }
711         }
712         /* allocate a pseudo-channel thru asterisk */
713         myrpt->pchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo");
714         if (!myrpt->pchannel)
715         {
716                 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
717                 pthread_exit(NULL);
718         }
719         /* make a conference for the tx */
720         ci.chan = 0;
721         ci.confno = -1; /* make a new conf */
722         ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER;
723         /* first put the channel on the conference in announce mode */
724         if (ioctl(myrpt->txchannel->fds[0],ZT_SETCONF,&ci) == -1)
725         {
726                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
727                 pthread_exit(NULL);
728         }
729         /* save tx conference number */
730         myrpt->txconf = ci.confno;
731         /* make a conference for the pseudo */
732         ci.chan = 0;
733         ci.confno = -1; /* make a new conf */
734         ci.confmode = ZT_CONF_CONFANNMON; 
735         /* first put the channel on the conference in announce mode */
736         if (ioctl(myrpt->pchannel->fds[0],ZT_SETCONF,&ci) == -1)
737         {
738                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
739                 pthread_exit(NULL);
740         }
741         /* save pseudo channel conference number */
742         myrpt->pconf = ci.confno;
743         /* Now, the idea here is to copy from the physical rx channel buffer
744            into the pseudo tx buffer, and from the pseudo rx buffer into the 
745            tx channel buffer */
746         myrpt->tailtimer = 0;
747         myrpt->totimer = 0;
748         myrpt->idtimer = 0;
749         lasttx = 0;
750         myrpt->remotetx = 0;
751         keyed = 0;
752         myrpt->callmode = 0;
753         dtmfidx = -1;
754         dtmfbuf[0] = 0;
755         dtmf_time = 0;
756         val = 0;
757         ast_channel_setoption(myrpt->rxchannel,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0);
758         val = 1;
759         ast_channel_setoption(myrpt->rxchannel,AST_OPTION_RELAXDTMF,&val,sizeof(char),0);
760         if (myrpt->rem_rxchannel)
761         {
762                 val = 0;
763                 ast_channel_setoption(myrpt->rem_rxchannel,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0);
764                 val = 1;
765                 ast_channel_setoption(myrpt->rem_rxchannel,AST_OPTION_RELAXDTMF,&val,sizeof(char),0);
766         }
767         while (ms >= 0)
768         {
769                 struct ast_frame *f;
770                 struct ast_channel *cs[5];
771                 int totx,rem_totx,elap,n;
772
773                 if (ast_check_hangup(myrpt->rxchannel)) break;
774                 if (ast_check_hangup(myrpt->txchannel)) break;
775                 if (myrpt->rem_rxchannel)
776                 {
777                         if (ast_check_hangup(myrpt->rem_rxchannel)) break;
778                         if (ast_check_hangup(myrpt->rem_txchannel)) break;
779                 }
780                 totx = (keyed || myrpt->callmode || myrpt->iding || myrpt->terming
781                     || ((myrpt->remotemode != REM_OFF) && myrpt->remoterx) ||
782                         myrpt->teleing || myrpt->comping || myrpt->procing);
783                 if (!totx) myrpt->totimer = myrpt->totime;
784                 else myrpt->tailtimer = myrpt->hangtime;
785                 totx = (totx || myrpt->tailtimer) && myrpt->totimer;
786                 /* if wants to transmit and in phone call, but timed out, 
787                         reset time-out timer if keyed */
788                 if ((!totx) && (!myrpt->totimer) && myrpt->callmode && keyed)
789                 {
790                         myrpt->totimer = myrpt->totime;
791                         continue;
792                 }
793                 /* if timed-out and in circuit busy after call */
794                 if ((!totx) && (!myrpt->totimer) && (myrpt->callmode == 4))
795                 {
796                         myrpt->callmode = 0;
797                 }
798                 if (totx && (!myrpt->idtimer))
799                 {
800                         myrpt->idtimer = myrpt->idtime;
801                         pthread_attr_init(&attr);
802                         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
803                         pthread_create(&myrpt->rpt_id_thread,&attr,rpt_id,(void *) myrpt);
804                 }
805                 if (totx && (!lasttx))
806                 {
807                         lasttx = 1;
808                         ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
809                 }
810                 if ((!totx) && lasttx)
811                 {
812                         lasttx = 0;
813                         ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
814                 }
815                 rem_totx = ((keyed && (myrpt->remotemode == REM_TX)) && myrpt->totimer);
816                 if (rem_totx && (!myrpt->remotetx))
817                 {
818                         myrpt->remotetx = 1;
819                         ci.chan = 0;
820                         ci.confno = 0;
821                         ci.confmode = 0;
822                         /* Take off conf */
823                         if (ioctl(myrpt->rem_rxchannel->fds[0],ZT_SETCONF,&ci) == -1)
824                         {
825                                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
826                                 pthread_exit(NULL);
827                         }
828                         ast_indicate(myrpt->rem_txchannel,AST_CONTROL_RADIO_KEY);
829                         ci.chan = 0;
830                         ci.confno = myrpt->txconf;
831                         ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER; 
832                         /* Put the channel on the conference in listener mode */
833                         if (ioctl(myrpt->rem_txchannel->fds[0],ZT_SETCONF,&ci) == -1)
834                         {
835                                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
836                                 pthread_exit(NULL);
837                         }
838                 }
839                 if ((!rem_totx) && myrpt->remotetx)
840                 {
841                         myrpt->remotetx = 0;
842                         ast_indicate(myrpt->rem_txchannel,AST_CONTROL_RADIO_UNKEY);
843                         ci.chan = 0;
844                         ci.confno = 0;
845                         ci.confmode = 0;
846                         /* Take off conf */
847                         if (ioctl(myrpt->rem_txchannel->fds[0],ZT_SETCONF,&ci) == -1)
848                         {
849                                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
850                                 pthread_exit(NULL);
851                         }
852                         if (myrpt->remotemode != REM_OFF)
853                         {
854                                 ci.chan = 0;
855                                 ci.confno = myrpt->pconf;
856                                 ci.confmode = ZT_CONF_CONF | ZT_CONF_TALKER;
857                                 /* Put on conf */
858                                 if (ioctl(myrpt->rem_rxchannel->fds[0],ZT_SETCONF,&ci) == -1)
859                                 {
860                                         ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
861                                         pthread_exit(NULL);
862                                 }
863                         }
864                 }
865                 time(&t);
866                 /* if DTMF timeout */
867                 if ((dtmfidx >= 0) && ((dtmf_time + DTMF_TIMEOUT) < t))
868                 {
869                         dtmfidx = -1;
870                         dtmfbuf[0] = 0;
871                 }                       
872                 n = 0;
873                 cs[n++] = myrpt->rxchannel;
874                 cs[n++] = myrpt->pchannel;
875                 if (myrpt->txchannel != myrpt->rxchannel) cs[n++] = myrpt->txchannel;
876                 if (myrpt->rem_rxchannel)
877                 {
878                         cs[n++] = myrpt->rem_rxchannel;
879                         if (myrpt->rem_txchannel != myrpt->rem_rxchannel)
880                                 cs[n++] = myrpt->rem_txchannel;
881                 }
882                 ms = MSWAIT;
883                 who = ast_waitfor_n(cs,n,&ms);
884                 if (who == NULL) ms = 0;
885                 elap = MSWAIT - ms;
886                 if (myrpt->tailtimer) myrpt->tailtimer -= elap;
887                 if (myrpt->tailtimer < 0) myrpt->tailtimer = 0;
888                 if (myrpt->totimer) myrpt->totimer -= elap;
889                 if (myrpt->totimer < 0) myrpt->totimer = 0;
890                 if (myrpt->idtimer) myrpt->idtimer -= elap;
891                 if (myrpt->idtimer < 0) myrpt->idtimer = 0;
892                 if (!ms) continue;
893                 if (who == myrpt->rxchannel) /* if it was a read from rx */
894                 {
895                         f = ast_read(myrpt->rxchannel);
896                         if (!f)
897                         {
898                                 if (debug) printf("@@@@ rpt:Hung Up\n");
899                                 break;
900                         }
901                         if (f->frametype == AST_FRAME_VOICE)
902                         {
903                                 ast_write(myrpt->pchannel,f);
904                         }
905                         else if (f->frametype == AST_FRAME_DTMF)
906                         {
907                                 char c;
908
909                                 c = (char) f->subclass; /* get DTMF char */
910                                 if (!myrpt->simple)
911                                 {
912                                         if (c == '*')
913                                         {
914                                                 dtmfidx = 0;
915                                                 dtmfbuf[dtmfidx] = 0;
916                                                 time(&dtmf_time);
917                                                 continue;
918                                         } 
919                                         else if ((c != '#') && (dtmfidx >= 0))
920                                         {
921                                                 time(&dtmf_time);
922                                                 if (dtmfidx < MAXDTMF)
923                                                 {
924                                                         dtmfbuf[dtmfidx++] = c;
925                                                         dtmfbuf[dtmfidx] = 0;
926                                                 }
927                                                 if (dtmfidx == FUNCTION_LEN)
928                                                 {
929                                                         process_dtmf(dtmfbuf,myrpt);
930                                                         dtmfbuf[0] = 0;
931                                                         dtmfidx = -1;
932                                                         continue;
933                                                 }
934                                         }
935                                 }
936                                 else
937                                 {
938                                         if ((!myrpt->callmode) && (c == '*'))
939                                         {
940                                                 myrpt->callmode = 1;
941                                                 myrpt->cidx = 0;
942                                                 myrpt->exten[myrpt->cidx] = 0;
943                                                 pthread_attr_init(&attr);
944                                                 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
945                                                 pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *)myrpt);
946                                                 continue;
947                                         }
948                                 }
949                                 if (myrpt->callmode && (c == '#'))
950                                 {
951                                         myrpt->callmode = 0;
952                                         pthread_attr_init(&attr);
953                                         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
954                                         pthread_create(&myrpt->rpt_term_thread,&attr,rpt_term,(void *) myrpt);
955                                         continue;
956                                 }
957                                 if (myrpt->callmode == 1)
958                                 {
959                                         myrpt->exten[myrpt->cidx++] = c;
960                                         myrpt->exten[myrpt->cidx] = 0;
961                                         /* if this exists */
962                                         if (ast_exists_extension(myrpt->pchannel,myrpt->ourcontext,myrpt->exten,1,NULL))
963                                         {
964                                                 myrpt->callmode = 2;
965                                                 pthread_attr_init(&attr);
966                                                 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
967                                                 pthread_create(&myrpt->rpt_proc_thread,&attr,rpt_proc,(void *) myrpt);
968                                         }
969                                         /* if can continue, do so */
970                                         if (ast_canmatch_extension(myrpt->pchannel,myrpt->ourcontext,myrpt->exten,1,NULL)) continue;
971                                         /* call has failed, inform user */
972                                         myrpt->callmode = 4;
973                                         continue;
974                                 }
975                                 if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
976                                 {
977                                         myrpt->mydtmf = f->subclass;
978                                 }
979                         }                                               
980                         else if (f->frametype == AST_FRAME_CONTROL)
981                         {
982                                 if (f->subclass == AST_CONTROL_HANGUP)
983                                 {
984                                         if (debug) printf("@@@@ rpt:Hung Up\n");
985                                         ast_frfree(f);
986                                         break;
987                                 }
988                                 /* if RX key */
989                                 if (f->subclass == AST_CONTROL_RADIO_KEY)
990                                 {
991                                         if (debug) printf("@@@@ rx key\n");
992                                         keyed = 1;
993                                 }
994                                 /* if RX un-key */
995                                 if (f->subclass == AST_CONTROL_RADIO_UNKEY)
996                                 {
997                                         if (debug) printf("@@@@ rx un-key\n");
998                                         keyed = 0;
999                                         if (myrpt->remotemode != REM_OFF)
1000                                         {
1001                                                 pthread_attr_init(&attr);
1002                                                 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1003                                                 pthread_create(&myrpt->rpt_proc_thread,&attr,rpt_remote_telemetry,(void *) myrpt);
1004                                         }
1005                                 }
1006                         }
1007                         ast_frfree(f);
1008                         continue;
1009                 }
1010                 if (who == myrpt->pchannel) /* if it was a read from pseudo */
1011                 {
1012                         f = ast_read(myrpt->pchannel);
1013                         if (!f)
1014                         {
1015                                 if (debug) printf("@@@@ rpt:Hung Up\n");
1016                                 break;
1017                         }
1018                         if (f->frametype == AST_FRAME_VOICE)
1019                         {
1020                                 ast_write(myrpt->txchannel,f);
1021                                 if (myrpt->remotemode == REM_TX)
1022                                         ast_write(myrpt->rem_txchannel,f);
1023                         }
1024                         if (f->frametype == AST_FRAME_CONTROL)
1025                         {
1026                                 if (f->subclass == AST_CONTROL_HANGUP)
1027                                 {
1028                                         if (debug) printf("@@@@ rpt:Hung Up\n");
1029                                         ast_frfree(f);
1030                                         break;
1031                                 }
1032                         }
1033                         ast_frfree(f);
1034                         continue;
1035                 }
1036                 if (who == myrpt->txchannel) /* if it was a read from tx */
1037                 {
1038                         f = ast_read(myrpt->txchannel);
1039                         if (!f)
1040                         {
1041                                 if (debug) printf("@@@@ rpt:Hung Up\n");
1042                                 break;
1043                         }
1044                         if (f->frametype == AST_FRAME_CONTROL)
1045                         {
1046                                 if (f->subclass == AST_CONTROL_HANGUP)
1047                                 {
1048                                         if (debug) printf("@@@@ rpt:Hung Up\n");
1049                                         ast_frfree(f);
1050                                         break;
1051                                 }
1052                         }
1053                         ast_frfree(f);
1054                         continue;
1055                 }
1056                 if (who == myrpt->rem_rxchannel) /* if it was a read from rx */
1057                 {
1058                         f = ast_read(myrpt->rem_rxchannel);
1059                         if (!f)
1060                         {
1061                                 if (debug) printf("@@@@ rpt:Hung Up\n");
1062                                 break;
1063                         }
1064                         if (f->frametype == AST_FRAME_CONTROL)
1065                         {
1066                                 if (f->subclass == AST_CONTROL_HANGUP)
1067                                 {
1068                                         if (debug) printf("@@@@ rpt:Hung Up\n");
1069                                         ast_frfree(f);
1070                                         break;
1071                                 }
1072                                 /* if RX key */
1073                                 if (f->subclass == AST_CONTROL_RADIO_KEY)
1074                                 {
1075                                         if (debug) printf("@@@@ remote rx key\n");
1076                                         if (!myrpt->remotetx)
1077                                         {
1078                                                 myrpt->remoterx = 1;
1079                                                 ci.chan = 0;
1080                                                 ci.confno = myrpt->pconf;
1081                                                 ci.confmode = ZT_CONF_CONF | ZT_CONF_TALKER;
1082                                                 /* Put on conf */
1083                                                 if (ioctl(myrpt->rem_rxchannel->fds[0],ZT_SETCONF,&ci) == -1)
1084                                                 {
1085                                                         ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
1086                                                         pthread_exit(NULL);
1087                                                 }
1088                                         }
1089                                 }
1090                                 /* if RX un-key */
1091                                 if (f->subclass == AST_CONTROL_RADIO_UNKEY)
1092                                 {
1093                                         if (debug) printf("@@@@ remote rx un-key\n");
1094                                         if (!myrpt->remotetx) 
1095                                         {
1096                                                 myrpt->remoterx = 0;
1097                                                 ci.chan = 0;
1098                                                 ci.confno = 0;
1099                                                 ci.confmode = 0;
1100                                                 /* Take off conf */
1101                                                 if (ioctl(myrpt->rem_rxchannel->fds[0],ZT_SETCONF,&ci) == -1)
1102                                                 {
1103                                                         ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
1104                                                         pthread_exit(NULL);
1105                                                 }
1106                                         }
1107                                 }
1108                         }
1109                         ast_frfree(f);
1110                         continue;
1111                 }
1112                 if (who == myrpt->rem_txchannel) /* if it was a read from remote tx */
1113                 {
1114                         f = ast_read(myrpt->rem_txchannel);
1115                         if (!f)
1116                         {
1117                                 if (debug) printf("@@@@ rpt:Hung Up\n");
1118                                 break;
1119                         }
1120                         if (f->frametype == AST_FRAME_CONTROL)
1121                         {
1122                                 if (f->subclass == AST_CONTROL_HANGUP)
1123                                 {
1124                                         if (debug) printf("@@@@ rpt:Hung Up\n");
1125                                         ast_frfree(f);
1126                                         break;
1127                                 }
1128                         }
1129                         ast_frfree(f);
1130                         continue;
1131                 }
1132
1133         }
1134         ast_hangup(myrpt->pchannel);
1135         ast_hangup(myrpt->rxchannel);
1136         if (myrpt->txchannel != myrpt->rxchannel) ast_hangup(myrpt->txchannel);
1137         if (myrpt->rem_rxchannel)
1138         {
1139                 ast_hangup(myrpt->rem_rxchannel);
1140                 if (myrpt->rem_txchannel != myrpt->rem_rxchannel) 
1141                         ast_hangup(myrpt->rem_txchannel);
1142         }
1143         if (debug) printf("@@@@ rpt:Hung up channel\n");
1144         pthread_exit(NULL);
1145         return NULL;
1146 }
1147
1148 static void *rpt_master(void *ignore)
1149 {
1150 struct  ast_config *cfg;
1151 char *this,*val;
1152 int     i,n;
1153
1154         /* start with blank config */
1155         memset(&rpt_vars,0,sizeof(rpt_vars));
1156
1157         cfg = ast_load("rpt.conf");
1158         if (!cfg) {
1159                 ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf.  Radio Repeater disabled.\n");
1160                 pthread_exit(NULL);
1161         }
1162
1163         /* go thru all the specified repeaters */
1164         this = NULL;
1165         n = 0;
1166         while((this = ast_category_browse(cfg,this)) != NULL)
1167         {
1168                 ast_log(LOG_DEBUG,"Loading config for repeater %s\n",this);
1169                 rpt_vars[n].name = this;
1170                 rpt_vars[n].rxchanname = ast_variable_retrieve(cfg,this,"rxchannel");
1171                 rpt_vars[n].txchanname = ast_variable_retrieve(cfg,this,"txchannel");
1172                 rpt_vars[n].rem_rxchanname = ast_variable_retrieve(cfg,this,"remote_rxchannel");
1173                 rpt_vars[n].rem_txchanname = ast_variable_retrieve(cfg,this,"remote_txchannel");
1174                 rpt_vars[n].ourcontext = ast_variable_retrieve(cfg,this,"context");
1175                 if (!rpt_vars[n].ourcontext) rpt_vars[n].ourcontext = this;
1176                 rpt_vars[n].ourcallerid = ast_variable_retrieve(cfg,this,"callerid");
1177                 rpt_vars[n].acctcode = ast_variable_retrieve(cfg,this,"accountcode");
1178                 rpt_vars[n].idrecording = ast_variable_retrieve(cfg,this,"idrecording");
1179                 val = ast_variable_retrieve(cfg,this,"hangtime");
1180                 if (val) rpt_vars[n].hangtime = atoi(val);
1181                         else rpt_vars[n].hangtime = HANGTIME;
1182                 val = ast_variable_retrieve(cfg,this,"totime");
1183                 if (val) rpt_vars[n].totime = atoi(val);
1184                         else rpt_vars[n].totime = TOTIME;
1185                 val = ast_variable_retrieve(cfg,this,"idtime");
1186                 if (val) rpt_vars[n].idtime = atoi(val);
1187                         else rpt_vars[n].idtime = IDTIME;
1188                 val = ast_variable_retrieve(cfg,this,"simple");
1189                 if (val) rpt_vars[n].simple = ast_true(val); 
1190                         else rpt_vars[n].simple = 0;
1191                 rpt_vars[n].tonezone = ast_variable_retrieve(cfg,this,"tonezone");
1192                 n++;
1193         }
1194         ast_log(LOG_DEBUG, "Total of %d repeaters configured.\n",n);
1195         /* start em all */
1196         for(i = 0; i < n; i++)
1197         {
1198                 if (!rpt_vars[i].rxchanname)
1199                 {
1200                         ast_log(LOG_WARNING,"Did not specify rxchanname for repeater %s\n",rpt_vars[i].name);
1201                         pthread_exit(NULL);
1202                 }
1203                 if (!rpt_vars[i].idrecording)
1204                 {
1205                         ast_log(LOG_WARNING,"Did not specify idrecording for repeater %s\n",rpt_vars[i].name);
1206                         pthread_exit(NULL);
1207                 }
1208                 pthread_create(&rpt_vars[i].rpt_id_thread,NULL,rpt,(void *) &rpt_vars[i]);
1209         }
1210         /* wait for first one to die (should be never) */
1211         pthread_join(rpt_vars[0].rpt_id_thread,NULL);
1212         pthread_exit(NULL);
1213 }
1214
1215 int unload_module(void)
1216 {
1217         STANDARD_HANGUP_LOCALUSERS;
1218         return 0;
1219 }
1220
1221 int load_module(void)
1222 {
1223         pthread_create(&rpt_master_thread,NULL,rpt_master,NULL);
1224         return 0;
1225 }
1226
1227 char *description(void)
1228 {
1229         return tdesc;
1230 }
1231
1232 int usecount(void)
1233 {
1234         int res;
1235         STANDARD_USECOUNT(res);
1236         return res;
1237 }
1238
1239 char *key()
1240 {
1241         return ASTERISK_GPL_KEY;
1242 }