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