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