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