Allowed proper tx/rx signal exclusivity for simplex repeater modes
[asterisk/asterisk.git] / apps / app_rpt.c
1 /* #define OLD_ASTERISK */
2 /*
3  * Asterisk -- An open source telephony toolkit.
4  *
5  * Copyright (C) 2002-2005, Jim Dixon, WB6NIL
6  *
7  * Jim Dixon, WB6NIL <jim@lambdatel.com>
8  * Serious contributions by Steve RoDgers, WA6ZFT <hwstar@rodgers.sdcoxmail.com>
9  *
10  * See http://www.asterisk.org for more information about
11  * the Asterisk project. Please do not directly contact
12  * any of the maintainers of this project for assistance;
13  * the project provides a web site, mailing lists and IRC
14  * channels for your use.
15  *
16  * This program is free software, distributed under the terms of
17  * the GNU General Public License Version 2. See the LICENSE file
18  * at the top of the source tree.
19  */
20
21 /*! \file
22  *
23  * \brief Radio Repeater / Remote Base program 
24  *  version 0.48 06/13/06
25  * 
26  * \author Jim Dixon, WB6NIL <jim@lambdatel.com>
27  *
28  * \note Serious contributions by Steve RoDgers, WA6ZFT <hwstar@rodgers.sdcoxmail.com>
29  * 
30  * See http://www.zapatatelephony.org/app_rpt.html
31  *
32  *
33  * Repeater / Remote Functions:
34  * "Simple" Mode:  * - autopatch access, # - autopatch hangup
35  * Normal mode:
36  * See the function list in rpt.conf (autopatchup, autopatchdn)
37  * autopatchup can optionally take comma delimited setting=value pairs:
38  *  
39  *
40  * context=string               :       Override default context with "string"
41  * dialtime=ms                  :       Specify the max number of milliseconds between phone number digits (1000 milliseconds = 1 second)
42  * farenddisconnect=1           :       Automatically disconnect when called party hangs up
43  * noct=1                       :       Don't send repeater courtesy tone during autopatch calls
44  * quiet=1                      :       Don't send dial tone, or connect messages. Do not send patch down message when called party hangs up
45  *
46  *
47  * Example: 123=autopatchup,dialtime=20000,noct=1,farenddisconnect=1
48  *
49  *  To send an asterisk (*) while dialing or talking on phone,
50  *  use the autopatch acess code.
51  *
52  *
53  * status cmds:
54  *
55  *  1 - Force ID
56  *  2 - Give Time of Day
57  *  3 - Give software Version
58  *
59  * cop (control operator) cmds:
60  *
61  *  1 - System warm boot
62  *  2 - System enable
63  *  3 - System disable
64  *  4 - Test Tone On
65  *  5 - Dump System Variables on Console (debug)
66  *  6 - PTT (phone mode only)
67  *
68  * ilink cmds:
69  *
70  *  1 - Disconnect specified link
71  *  2 - Connect specified link -- monitor only
72  *  3 - Connect specified link -- tranceive
73  *  4 - Enter command mode on specified link
74  *  5 - System status
75  *  6 - Disconnect all links
76  *
77  * remote cmds:
78  *
79  *  1 - Recall Memory MM  (*000-*099) (Gets memory from rpt.conf)
80  *  2 - Set VFO MMMMM*KKK*O   (Mhz digits, Khz digits, Offset)
81  *  3 - Set Rx PL Tone HHH*D*
82  *  4 - Set Tx PL Tone HHH*D* (Not currently implemented with DHE RBI-1)
83  *  5 - Link Status (long)
84  *  6 - Set operating mode M (FM, USB, LSB, AM, etc)
85  *  100 - RX PL off (Default)
86  *  101 - RX PL On
87  *  102 - TX PL Off (Default)
88  *  103 - TX PL On
89  *  104 - Low Power
90  *  105 - Med Power
91  *  106 - Hi Power
92  *  107 - Bump Down 20 Hz
93  *  108 - Bump Down 100 Hz
94  *  109 - Bump Down 500 Hz
95  *  110 - Bump Up 20 Hz
96  *  111 - Bump Up 100 Hz
97  *  112 - Bump Up 500 Hz
98  *  113 - Scan Down Slow
99  *  114 - Scan Down Medium
100  *  115 - Scan Down Fast
101  *  116 - Scan Up Slow
102  *  117 - Scan Up Medium
103  *  118 - Scan Up Fast
104  *  119 - Transmit allowing auto-tune
105  *  140 - Link Status (brief)
106  *
107  *
108  *
109  * 'duplex' modes:  (defaults to duplex=2)
110  *
111  * 0 - Only remote links key Tx and no main repeat audio.
112  * 1 - Everything other then main Rx keys Tx, no main repeat audio.
113  * 2 - Normal mode
114  * 3 - Normal except no main repeat audio.
115  * 4 - Normal except no main repeat audio during autopatch only
116  *
117 */
118
119 /*** MODULEINFO
120         <depend>zaptel</depend>
121         <defaultenabled>no</defaultenabled>
122  ***/
123
124 /* Un-comment the following to include support for MDC-1200 digital tone
125    signalling protocol (using KA6SQG's GPL'ed implementation) */
126 /* #include "mdc_decode.c" */
127
128 /* Un-comment the following to include support for notch filters in the
129    rx audio stream (using Tony Fisher's mknotch (mkfilter) implementation) */
130 /* #include "rpt_notch.c" */
131
132 /* maximum digits in DTMF buffer, and seconds after * for DTMF command timeout */
133
134 #define MAXDTMF 32
135 #define MAXMACRO 2048
136 #define MACROTIME 100
137 #define MACROPTIME 500
138 #define DTMF_TIMEOUT 3
139
140 #ifdef  __RPT_NOTCH
141 #define MAXFILTERS 10
142 #endif
143
144 #define DISC_TIME 10000  /* report disc after 10 seconds of no connect */
145 #define MAX_RETRIES 5
146
147 #define REDUNDANT_TX_TIME 2000
148
149 #define RETRY_TIMER_MS 5000
150
151 #define MAXPEERSTR 31
152 #define MAXREMSTR 15
153
154 #define DELIMCHR ','
155 #define QUOTECHR 34
156
157 #define NODES "nodes"
158 #define MEMORY "memory"
159 #define MACRO "macro"
160 #define FUNCTIONS "functions"
161 #define TELEMETRY "telemetry"
162 #define MORSE "morse"
163 #define FUNCCHAR '*'
164 #define ENDCHAR '#'
165
166 #define DEFAULT_IOBASE 0x378
167
168 #define MAXCONNECTTIME 5000
169
170 #define MAXNODESTR 300
171
172 #define MAXPATCHCONTEXT 100
173
174 #define ACTIONSIZE 32
175
176 #define TELEPARAMSIZE 256
177
178 #define REM_SCANTIME 100
179
180
181 enum {REM_OFF,REM_MONITOR,REM_TX};
182
183 enum{ID,PROC,TERM,COMPLETE,UNKEY,REMDISC,REMALREADY,REMNOTFOUND,REMGO,
184         CONNECTED,CONNFAIL,STATUS,TIMEOUT,ID1, STATS_TIME,
185         STATS_VERSION, IDTALKOVER, ARB_ALPHA, TEST_TONE, REV_PATCH,
186         TAILMSG, MACRO_NOTFOUND, MACRO_BUSY, LASTNODEKEY};
187
188 enum {REM_SIMPLEX,REM_MINUS,REM_PLUS};
189
190 enum {REM_LOWPWR,REM_MEDPWR,REM_HIPWR};
191
192 enum {DC_INDETERMINATE, DC_REQ_FLUSH, DC_ERROR, DC_COMPLETE, DC_DOKEY};
193
194 enum {SOURCE_RPT, SOURCE_LNK, SOURCE_RMT, SOURCE_PHONE, SOURCE_DPHONE};
195
196 enum {DLY_TELEM, DLY_ID, DLY_UNKEY, DLY_CALLTERM};
197
198 enum {REM_MODE_FM,REM_MODE_USB,REM_MODE_LSB,REM_MODE_AM};
199
200 enum {HF_SCAN_OFF,HF_SCAN_DOWN_SLOW,HF_SCAN_DOWN_QUICK,
201       HF_SCAN_DOWN_FAST,HF_SCAN_UP_SLOW,HF_SCAN_UP_QUICK,HF_SCAN_UP_FAST};
202
203 #include "asterisk.h"
204
205 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
206
207 #include <signal.h>
208 #include <stdio.h>
209 #include <unistd.h>
210 #include <string.h>
211 #include <stdlib.h>
212 #include <search.h>
213 #include <sys/types.h>
214 #include <sys/stat.h>
215 #include <errno.h>
216 #include <dirent.h>
217 #include <ctype.h>
218 #include <sys/stat.h>
219 #include <sys/time.h>
220 #include <sys/file.h>
221 #include <sys/ioctl.h>
222 #include <sys/io.h>
223 #include <math.h>
224 #include <tonezone.h>
225 #include <linux/zaptel.h>
226 #include <netinet/in.h>
227 #include <arpa/inet.h>
228
229 #include "asterisk/utils.h"
230 #include "asterisk/lock.h"
231 #include "asterisk/file.h"
232 #include "asterisk/logger.h"
233 #include "asterisk/channel.h"
234 #include "asterisk/callerid.h"
235 #include "asterisk/pbx.h"
236 #include "asterisk/module.h"
237 #include "asterisk/translate.h"
238 #include "asterisk/features.h"
239 #include "asterisk/options.h"
240 #include "asterisk/cli.h"
241 #include "asterisk/config.h"
242 #include "asterisk/say.h"
243 #include "asterisk/localtime.h"
244
245 static  char *tdesc = "Radio Repeater / Remote Base  version 0.48  06/13/2006";
246
247 static char *app = "Rpt";
248
249 static char *synopsis = "Radio Repeater/Remote Base Control System";
250
251 static char *descrip = 
252 "  Rpt(nodename[|options]):  Radio Remote Link or Remote Base Link Endpoint Process.\n"
253 "\n"
254 "    Not specifying an option puts it in normal endpoint mode (where source\n"
255 "    IP and nodename are verified).\n"
256 "\n"
257 "    Options are as follows:\n"
258 "\n"
259 "        X - Normal endpoint mode WITHOUT security check. Only specify\n"
260 "            this if you have checked security already (like with an IAX2\n"
261 "            user/password or something).\n"
262 "\n"
263 "        Rannounce-string[|timeout[|timeout-destination]] - Amateur Radio\n"
264 "            Reverse Autopatch. Caller is put on hold, and announcement (as\n"
265 "            specified by the 'announce-string') is played on radio system.\n"
266 "            Users of radio system can access autopatch, dial specified\n"
267 "            code, and pick up call. Announce-string is list of names of\n"
268 "            recordings, or \"PARKED\" to substitute code for un-parking,\n"
269 "            or \"NODE\" to substitute node number.\n"
270 "\n"
271 "        P - Phone Control mode. This allows a regular phone user to have\n"
272 "            full control and audio access to the radio system. For the\n"
273 "            user to have DTMF control, the 'phone_functions' parameter\n"
274 "            must be specified for the node in 'rpt.conf'. An additional\n"
275 "            function (cop,6) must be listed so that PTT control is available.\n"
276 "\n"
277 "        D - Dumb Phone Control mode. This allows a regular phone user to\n"
278 "            have full control and audio access to the radio system. In this\n"
279 "            mode, the PTT is activated for the entire length of the call.\n"
280 "            For the user to have DTMF control (not generally recomended in\n"
281 "            this mode), the 'dphone_functions' parameter must be specified\n"
282 "            for the node in 'rpt.conf'. Otherwise no DTMF control will be\n"
283 "            available to the phone user.\n"
284 "\n";
285
286 static int debug = 0;  /* FIXME Set this >0 for extra debug output */
287 static int nrpts = 0;
288
289 char *discstr = "!!DISCONNECT!!";
290 static char *remote_rig_ft897="ft897";
291 static char *remote_rig_rbi="rbi";
292
293 #ifdef  OLD_ASTERISK
294 STANDARD_LOCAL_USER;
295 #endif
296
297 LOCAL_USER_DECL;
298
299 #define MSWAIT 200
300 #define HANGTIME 5000
301 #define TOTIME 180000
302 #define IDTIME 300000
303 #define MAXRPTS 20
304 #define MAX_STAT_LINKS 32
305 #define POLITEID 30000
306 #define FUNCTDELAY 1500
307
308 static  pthread_t rpt_master_thread;
309
310 struct rpt;
311
312 struct rpt_link
313 {
314         struct rpt_link *next;
315         struct rpt_link *prev;
316         char    mode;                   /* 1 if in tx mode */
317         char    isremote;
318         char    phonemode;
319         char    name[MAXNODESTR];       /* identifier (routing) string */
320         char    lasttx;
321         char    lastrx;
322         char    connected;
323         char    hasconnected;
324         char    outbound;
325         char    disced;
326         char    killme;
327         long    elaptime;
328         long    disctime;
329         long    retrytimer;
330         long    retxtimer;
331         int     retries;
332         int     reconnects;
333         long long connecttime;
334         struct ast_channel *chan;       
335         struct ast_channel *pchan;      
336 } ;
337
338 struct rpt_lstat
339 {
340         struct  rpt_lstat *next;
341         struct  rpt_lstat *prev;
342         char    peer[MAXPEERSTR];
343         char    name[MAXNODESTR];
344         char    mode;
345         char    outbound;
346         char    reconnects;
347         long long       connecttime;
348 } ;
349
350 struct rpt_tele
351 {
352         struct rpt_tele *next;
353         struct rpt_tele *prev;
354         struct rpt *rpt;
355         struct ast_channel *chan;
356         int     mode;
357         struct rpt_link mylink;
358         char param[TELEPARAMSIZE];
359         pthread_t threadid;
360 } ;
361
362 struct function_table_tag
363 {
364         char action[ACTIONSIZE];
365         int (*function)(struct rpt *myrpt, char *param, char *digitbuf, 
366                 int command_source, struct rpt_link *mylink);
367 } ;
368
369 /* Used to store the morse code patterns */
370
371 struct morse_bits
372 {                 
373         int len;
374         int ddcomb;
375 } ;
376
377 struct telem_defaults
378 {
379         char name[20];
380         char value[80];
381 } ;
382
383
384 static struct rpt
385 {
386         ast_mutex_t lock;
387         struct ast_config *cfg;
388         char reload;
389
390         char *name;
391         char *rxchanname;
392         char *txchanname;
393         char *remote;
394
395         struct {
396
397                 char *ourcontext;
398                 char *ourcallerid;
399                 char *acctcode;
400                 char *ident;
401                 char *tonezone;
402                 char simple;
403                 char *functions;
404                 char *link_functions;
405                 char *phone_functions;
406                 char *dphone_functions;
407                 char *nodes;
408                 int hangtime;
409                 int totime;
410                 int idtime;
411                 int tailmessagetime;
412                 int tailsquashedtime;
413                 int duplex;
414                 int politeid;
415                 char *tailmessages[500];
416                 int tailmessagemax;
417                 char    *memory;
418                 char    *macro;
419                 char    *startupmacro;
420                 int iobase;
421                 char funcchar;
422                 char endchar;
423                 char    nobusyout;
424         } p;
425         struct rpt_link links;
426         int unkeytocttimer;
427         char keyed;
428         char exttx;
429         char localtx;
430         char remoterx;
431         char remotetx;
432         char remoteon;
433         char tounkeyed;
434         char tonotify;
435         char enable;
436         char dtmfbuf[MAXDTMF];
437         char macrobuf[MAXMACRO];
438         char rem_dtmfbuf[MAXDTMF];
439         char lastdtmfcommand[MAXDTMF];
440         char cmdnode[50];
441         struct ast_channel *rxchannel,*txchannel;
442         struct ast_channel *pchannel,*txpchannel, *remchannel;
443         struct rpt_tele tele;
444         struct timeval lasttv,curtv;
445         pthread_t rpt_call_thread,rpt_thread;
446         time_t dtmf_time,rem_dtmf_time,dtmf_time_rem;
447         int tailtimer,totimer,idtimer,txconf,conf,callmode,cidx,scantimer,tmsgtimer,skedtimer;
448         int mustid,tailid;
449         int tailevent;
450         int telemrefcount;
451         int dtmfidx,rem_dtmfidx;
452         int dailytxtime,dailykerchunks,totalkerchunks,dailykeyups,totalkeyups,timeouts;
453         int totalexecdcommands, dailyexecdcommands;
454         long    retxtimer;
455         long long totaltxtime;
456         char mydtmf;
457         char exten[AST_MAX_EXTENSION];
458         char freq[MAXREMSTR],rxpl[MAXREMSTR],txpl[MAXREMSTR];
459         char offset;
460         char powerlevel;
461         char txplon;
462         char rxplon;
463         char remmode;
464         char tunerequest;
465         char hfscanmode;
466         int hfscanstatus;
467         char lastlinknode[MAXNODESTR];
468         char stopgen;
469         char patchfarenddisconnect;
470         char patchnoct;
471         char patchquiet;
472         char patchcontext[MAXPATCHCONTEXT];
473         int patchdialtime;
474         int macro_longest;
475         int phone_longestfunc;
476         int dphone_longestfunc;
477         int link_longestfunc;
478         int longestfunc;
479         int longestnode;
480         int threadrestarts;             
481         int tailmessagen;
482         time_t disgorgetime;
483         time_t lastthreadrestarttime;
484         long    macrotimer;
485         char    lastnodewhichkeyedusup[MAXNODESTR];
486 #ifdef  __RPT_NOTCH
487         struct rptfilter
488         {
489                 char    desc[100];
490                 float   x0;
491                 float   x1;
492                 float   x2;
493                 float   y0;
494                 float   y1;
495                 float   y2;
496                 float   gain;
497                 float   const0;
498                 float   const1;
499                 float   const2;
500         } filters[MAXFILTERS];
501 #endif
502 #ifdef  _MDC_DECODE_H_
503         mdc_decoder_t *mdc;
504         unsigned short lastunit;
505 #endif
506 } rpt_vars[MAXRPTS];    
507
508
509 #ifdef  APP_RPT_LOCK_DEBUG
510
511 #warning COMPILING WITH LOCK-DEBUGGING ENABLED!!
512
513 #define MAXLOCKTHREAD 100
514
515 #define rpt_mutex_lock(x) _rpt_mutex_lock(x,myrpt,__LINE__)
516 #define rpt_mutex_unlock(x) _rpt_mutex_unlock(x,myrpt,__LINE__)
517
518 struct lockthread
519 {
520         pthread_t id;
521         int lockcount;
522         int lastlock;
523         int lastunlock;
524 } lockthreads[MAXLOCKTHREAD];
525
526
527 struct by_lightning
528 {
529         int line;
530         struct timeval tv;
531         struct rpt *rpt;
532         struct lockthread lockthread;
533 } lock_ring[32];
534
535
536 int lock_ring_index = 0;
537
538 AST_MUTEX_DEFINE_STATIC(locklock);
539
540 static struct lockthread *get_lockthread(pthread_t id)
541 {
542 int     i;
543
544         for(i = 0; i < MAXLOCKTHREAD; i++)
545         {
546                 if (lockthreads[i].id == id) return(&lockthreads[i]);
547         }
548         return(NULL);
549 }
550
551 static struct lockthread *put_lockthread(pthread_t id)
552 {
553 int     i;
554
555         for(i = 0; i < MAXLOCKTHREAD; i++)
556         {
557                 if (lockthreads[i].id == id)
558                         return(&lockthreads[i]);
559         }
560         for(i = 0; i < MAXLOCKTHREAD; i++)
561         {
562                 if (!lockthreads[i].id)
563                 {
564                         lockthreads[i].lockcount = 0;
565                         lockthreads[i].lastlock = 0;
566                         lockthreads[i].lastunlock = 0;
567                         lockthreads[i].id = id;
568                         return(&lockthreads[i]);
569                 }
570         }
571         return(NULL);
572 }
573
574
575 static void rpt_mutex_spew(void)
576 {
577         struct by_lightning lock_ring_copy[32];
578         int lock_ring_index_copy;
579         int i,j;
580         long long diff;
581         char a[100];
582         struct timeval lasttv;
583
584         ast_mutex_lock(&locklock);
585         memcpy(&lock_ring_copy, &lock_ring, sizeof(lock_ring_copy));
586         lock_ring_index_copy = lock_ring_index;
587         ast_mutex_unlock(&locklock);
588
589         lasttv.tv_sec = lasttv.tv_usec = 0;
590         for(i = 0 ; i < 32 ; i++)
591         {
592                 j = (i + lock_ring_index_copy) % 32;
593                 strftime(a,sizeof(a) - 1,"%m/%d/%Y %H:%M:%S",
594                         localtime(&lock_ring_copy[j].tv.tv_sec));
595                 diff = 0;
596                 if(lasttv.tv_sec)
597                 {
598                         diff = (lock_ring_copy[j].tv.tv_sec - lasttv.tv_sec)
599                                 * 1000000;
600                         diff += (lock_ring_copy[j].tv.tv_usec - lasttv.tv_usec);
601                 }
602                 lasttv.tv_sec = lock_ring_copy[j].tv.tv_sec;
603                 lasttv.tv_usec = lock_ring_copy[j].tv.tv_usec;
604                 if (!lock_ring_copy[j].tv.tv_sec) continue;
605                 if (lock_ring_copy[j].line < 0)
606                 {
607                         ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] UNLOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
608                                 i - 31,-lock_ring_copy[j].line,lock_ring_copy[j].rpt->name,(int) lock_ring_copy[j].lockthread.id,diff,a,(int)lock_ring_copy[j].tv.tv_usec);
609                 }
610                 else
611                 {
612                         ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] LOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
613                                 i - 31,lock_ring_copy[j].line,lock_ring_copy[j].rpt->name,(int) lock_ring_copy[j].lockthread.id,diff,a,(int)lock_ring_copy[j].tv.tv_usec);
614                 }
615         }
616 }
617
618
619 static void _rpt_mutex_lock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
620 {
621 struct lockthread *t;
622 pthread_t id;
623
624         id = pthread_self();
625         ast_mutex_lock(&locklock);
626         t = put_lockthread(id);
627         if (!t)
628         {
629                 ast_mutex_unlock(&locklock);
630                 return;
631         }
632         if (t->lockcount)
633         {
634                 int lastline = t->lastlock;
635                 ast_mutex_unlock(&locklock);
636                 ast_log(LOG_NOTICE,"rpt_mutex_lock: Double lock request line %d node %s pid %x, last lock was line %d\n",line,myrpt->name,(int) t->id,lastline);
637                 rpt_mutex_spew();
638                 return;
639         }
640         t->lastlock = line;
641         t->lockcount = 1;
642         gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
643         lock_ring[lock_ring_index].rpt = myrpt;
644         memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
645         lock_ring[lock_ring_index++].line = line;
646         if(lock_ring_index == 32)
647                 lock_ring_index = 0;
648         ast_mutex_unlock(&locklock);
649         ast_mutex_lock(lockp);
650 }
651
652
653 static void _rpt_mutex_unlock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
654 {
655 struct lockthread *t;
656 pthread_t id;
657
658         id = pthread_self();
659         ast_mutex_lock(&locklock);
660         t = put_lockthread(id);
661         if (!t)
662         {
663                 ast_mutex_unlock(&locklock);
664                 return;
665         }
666         if (!t->lockcount)
667         {
668                 int lastline = t->lastunlock;
669                 ast_mutex_unlock(&locklock);
670                 ast_log(LOG_NOTICE,"rpt_mutex_lock: Double un-lock request line %d node %s pid %x, last un-lock was line %d\n",line,myrpt->name,(int) t->id,lastline);
671                 rpt_mutex_spew();
672                 return;
673         }
674         t->lastunlock = line;
675         t->lockcount = 0;
676         gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
677         lock_ring[lock_ring_index].rpt = myrpt;
678         memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
679         lock_ring[lock_ring_index++].line = -line;
680         if(lock_ring_index == 32)
681                 lock_ring_index = 0;
682         ast_mutex_unlock(&locklock);
683         ast_mutex_unlock(lockp);
684 }
685
686 #else  /* APP_RPT_LOCK_DEBUG */
687
688 #define rpt_mutex_lock(x) ast_mutex_lock(x)
689 #define rpt_mutex_unlock(x) ast_mutex_unlock(x)
690
691 #endif  /* APP_RPT_LOCK_DEBUG */
692
693 /*
694 * CLI extensions
695 */
696
697 /* Debug mode */
698 static int rpt_do_debug(int fd, int argc, char *argv[]);
699 static int rpt_do_dump(int fd, int argc, char *argv[]);
700 static int rpt_do_stats(int fd, int argc, char *argv[]);
701 static int rpt_do_lstats(int fd, int argc, char *argv[]);
702 static int rpt_do_reload(int fd, int argc, char *argv[]);
703 static int rpt_do_restart(int fd, int argc, char *argv[]);
704
705 static char debug_usage[] =
706 "Usage: rpt debug level {0-7}\n"
707 "       Enables debug messages in app_rpt\n";
708
709 static char dump_usage[] =
710 "Usage: rpt dump <nodename>\n"
711 "       Dumps struct debug info to log\n";
712
713 static char dump_stats[] =
714 "Usage: rpt stats <nodename>\n"
715 "       Dumps node statistics to console\n";
716
717 static char dump_lstats[] =
718 "Usage: rpt lstats <nodename>\n"
719 "       Dumps link statistics to console\n";
720
721 static char reload_usage[] =
722 "Usage: rpt reload\n"
723 "       Reloads app_rpt running config parameters\n";
724
725 static char restart_usage[] =
726 "Usage: rpt restart\n"
727 "       Restarts app_rpt\n";
728
729 static struct ast_cli_entry  cli_debug =
730         { { "rpt", "debug", "level" }, rpt_do_debug, 
731                 "Enable app_rpt debugging", debug_usage };
732
733 static struct ast_cli_entry  cli_dump =
734         { { "rpt", "dump" }, rpt_do_dump,
735                 "Dump app_rpt structs for debugging", dump_usage };
736
737 static struct ast_cli_entry  cli_stats =
738         { { "rpt", "stats" }, rpt_do_stats,
739                 "Dump node statistics", dump_stats };
740
741 static struct ast_cli_entry  cli_lstats =
742         { { "rpt", "lstats" }, rpt_do_lstats,
743                 "Dump link statistics", dump_lstats };
744
745 static struct ast_cli_entry  cli_reload =
746         { { "rpt", "reload" }, rpt_do_reload,
747                 "Reload app_rpt config", reload_usage };
748
749 static struct ast_cli_entry  cli_restart =
750         { { "rpt", "restart" }, rpt_do_restart,
751                 "Restart app_rpt", restart_usage };
752
753 /*
754 * Telemetry defaults
755 */
756
757
758 static struct telem_defaults tele_defs[] = {
759         {"ct1","|t(350,0,100,3072)(500,0,100,3072)(660,0,100,3072)"},
760         {"ct2","|t(660,880,150,3072)"},
761         {"ct3","|t(440,0,150,3072)"},
762         {"ct4","|t(550,0,150,3072)"},
763         {"ct5","|t(660,0,150,3072)"},
764         {"ct6","|t(880,0,150,3072)"},
765         {"ct7","|t(660,440,150,3072)"},
766         {"ct8","|t(700,1100,150,3072)"},
767         {"remotemon","|t(1600,0,75,2048)"},
768         {"remotetx","|t(2000,0,75,2048)(0,0,75,0)(1600,0,75,2048)"},
769         {"cmdmode","|t(900,904,200,2048)"},
770         {"functcomplete","|t(1000,0,100,2048)(0,0,100,0)(1000,0,100,2048)"}
771 } ;
772
773 /*
774 * Forward decl's - these suppress compiler warnings when funcs coded further down the file than thier invokation
775 */
776
777 static int setrbi(struct rpt *myrpt);
778
779
780
781 /*
782 * Define function protos for function table here
783 */
784
785 static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
786 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
787 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
788 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
789 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
790 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
791 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
792 /*
793 * Function table
794 */
795
796 static struct function_table_tag function_table[] = {
797         {"cop", function_cop},
798         {"autopatchup", function_autopatchup},
799         {"autopatchdn", function_autopatchdn},
800         {"ilink", function_ilink},
801         {"status", function_status},
802         {"remote", function_remote},
803         {"macro", function_macro}
804 } ;
805
806 /*
807 * Break up a delimited string into a table of substrings
808 *
809 * str - delimited string ( will be modified )
810 * strp- list of pointers to substrings (this is built by this function), NULL will be placed at end of list
811 * limit- maximum number of substrings to process
812 */
813         
814
815
816 static int finddelim(char *str, char *strp[], int limit)
817 {
818 int     i,l,inquo;
819
820         inquo = 0;
821         i = 0;
822         strp[i++] = str;
823         if (!*str)
824            {
825                 strp[0] = 0;
826                 return(0);
827            }
828         for(l = 0; *str && (l < limit) ; str++)
829            {
830                 if (*str == QUOTECHR)
831                    {
832                         if (inquo)
833                            {
834                                 *str = 0;
835                                 inquo = 0;
836                            }
837                         else
838                            {
839                                 strp[i - 1] = str + 1;
840                                 inquo = 1;
841                            }
842                 }
843                 if ((*str == DELIMCHR) && (!inquo))
844                 {
845                         *str = 0;
846                         l++;
847                         strp[i++] = str + 1;
848                 }
849            }
850         strp[i] = 0;
851         return(i);
852
853 }
854
855 /*
856 * Match a keyword in a list, and return index of string plus 1 if there was a match,
857 * else return 0. If param is passed in non-null, then it will be set to the first character past the match
858 */
859
860 static int matchkeyword(char *string, char **param, char *keywords[])
861 {
862 int     i,ls;
863         for( i = 0 ; keywords[i] ; i++){
864                 ls = strlen(keywords[i]);
865                 if(!ls){
866                         *param = NULL;
867                         return 0;
868                 }
869                 if(!strncmp(string, keywords[i], ls)){
870                         if(param)
871                                 *param = string + ls;
872                         return i + 1; 
873                 }
874         }
875         param = NULL;
876         return 0;
877 }
878
879 /*
880 * Skip characters in string which are in charlist, and return a pointer to the
881 * first non-matching character
882 */
883
884 static char *skipchars(char *string, char *charlist)
885 {
886 int i;  
887         while(*string){
888                 for(i = 0; charlist[i] ; i++){
889                         if(*string == charlist[i]){
890                                 string++;
891                                 break;
892                         }
893                 }
894                 if(!charlist[i])
895                         return string;
896         }
897         return string;
898 }       
899                                         
900
901
902 static int myatoi(char *str)
903 {
904 int     ret;
905
906         if (str == NULL) return -1;
907         /* leave this %i alone, non-base-10 input is useful here */
908         if (sscanf(str,"%i",&ret) != 1) return -1;
909         return ret;
910 }
911
912
913 #ifdef  __RPT_NOTCH
914
915 /* rpt filter routine */
916 static void rpt_filter(struct rpt *myrpt, volatile short *buf, int len)
917 {
918 int     i,j;
919 struct  rptfilter *f;
920
921         for(i = 0; i < len; i++)
922         {
923                 for(j = 0; j < MAXFILTERS; j++)
924                 {
925                         f = &myrpt->filters[j];
926                         if (!*f->desc) continue;
927                         f->x0 = f->x1; f->x1 = f->x2;
928                         f->x2 = ((float)buf[i]) / f->gain;
929                         f->y0 = f->y1; f->y1 = f->y2;
930                         f->y2 =   (f->x0 + f->x2) +   f->const0 * f->x1
931                                      + (f->const1 * f->y0) + (f->const2 * f->y1);
932                         buf[i] = (short)f->y2;
933                 }
934         }
935 }
936
937 #endif
938
939 /* Retrieve an int from a config file */
940                                                                                 
941 static int retrieve_astcfgint(struct rpt *myrpt,char *category, char *name, int min, int max, int defl)
942 {
943         char *var;
944         int ret;
945                                                                                 
946         var = ast_variable_retrieve(myrpt->cfg, category, name);
947         if(var){
948                 ret = myatoi(var);
949                 if(ret < min)
950                         ret = min;
951                 if(ret > max)
952                         ret = max;
953         }
954         else
955                 ret = defl;
956         return ret;
957 }
958
959
960 static void load_rpt_vars(int n,int init)
961 {
962 char *this,*val;
963 int     j,longestnode;
964 struct ast_variable *vp;
965 struct ast_config *cfg;
966 #ifdef  __RPT_NOTCH
967 int     i;
968 char *strs[100];
969 #endif
970
971         if (option_verbose > 2)
972                 ast_verbose(VERBOSE_PREFIX_3 "%s config for repeater %s\n",
973                         (init) ? "Loading initial" : "Re-Loading",rpt_vars[n].name);
974         ast_mutex_lock(&rpt_vars[n].lock);
975         if (rpt_vars[n].cfg) ast_config_destroy(rpt_vars[n].cfg);
976         cfg = ast_config_load("rpt.conf");
977         if (!cfg) {
978                 ast_mutex_unlock(&rpt_vars[n].lock);
979                 ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf.  Radio Repeater disabled.\n");
980                 pthread_exit(NULL);
981         }
982         rpt_vars[n].cfg = cfg; 
983         this = rpt_vars[n].name;
984         memset(&rpt_vars[n].p,0,sizeof(rpt_vars[n].p));
985         if (init)
986         {
987                 char *cp;
988                 int savearea = (char *)&rpt_vars[n].p - (char *)&rpt_vars[n];
989
990                 cp = (char *) &rpt_vars[n].p;
991                 memset(cp + sizeof(rpt_vars[n].p),0,
992                         sizeof(rpt_vars[n]) - (sizeof(rpt_vars[n].p) + savearea));
993                 rpt_vars[n].tele.next = &rpt_vars[n].tele;
994                 rpt_vars[n].tele.prev = &rpt_vars[n].tele;
995                 rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
996                 rpt_vars[n].tailmessagen = 0;
997         }
998 #ifdef  __RPT_NOTCH
999         /* zot out filters stuff */
1000         memset(&rpt_vars[n].filters,0,sizeof(rpt_vars[n].filters));
1001 #endif
1002         val = ast_variable_retrieve(cfg,this,"context");
1003         if (val) rpt_vars[n].p.ourcontext = val;
1004         else rpt_vars[n].p.ourcontext = this;
1005         val = ast_variable_retrieve(cfg,this,"callerid");
1006         if (val) rpt_vars[n].p.ourcallerid = val;
1007         val = ast_variable_retrieve(cfg,this,"accountcode");
1008         if (val) rpt_vars[n].p.acctcode = val;
1009         val = ast_variable_retrieve(cfg,this,"idrecording");
1010         if (val) rpt_vars[n].p.ident = val;
1011         val = ast_variable_retrieve(cfg,this,"hangtime");
1012         if (val) rpt_vars[n].p.hangtime = atoi(val);
1013                 else rpt_vars[n].p.hangtime = HANGTIME;
1014         val = ast_variable_retrieve(cfg,this,"totime");
1015         if (val) rpt_vars[n].p.totime = atoi(val);
1016                 else rpt_vars[n].p.totime = TOTIME;
1017         rpt_vars[n].p.tailmessagetime = retrieve_astcfgint(&rpt_vars[n],this, "tailmessagetime", 0, 2400000, 0);                
1018         rpt_vars[n].p.tailsquashedtime = retrieve_astcfgint(&rpt_vars[n],this, "tailsquashedtime", 0, 2400000, 0);              
1019         rpt_vars[n].p.duplex = retrieve_astcfgint(&rpt_vars[n],this,"duplex",0,4,2);
1020         rpt_vars[n].p.idtime = retrieve_astcfgint(&rpt_vars[n],this, "idtime", 60000, 2400000, IDTIME); /* Enforce a min max */
1021         rpt_vars[n].p.politeid = retrieve_astcfgint(&rpt_vars[n],this, "politeid", 30000, 300000, POLITEID); /* Enforce a min max */
1022         val = ast_variable_retrieve(cfg,this,"tonezone");
1023         if (val) rpt_vars[n].p.tonezone = val;
1024         rpt_vars[n].p.tailmessages[0] = 0;
1025         rpt_vars[n].p.tailmessagemax = 0;
1026         val = ast_variable_retrieve(cfg,this,"tailmessagelist");
1027         if (val) rpt_vars[n].p.tailmessagemax = finddelim(val, rpt_vars[n].p.tailmessages, 500);
1028         val = ast_variable_retrieve(cfg,this,"memory");
1029         if (!val) val = MEMORY;
1030         rpt_vars[n].p.memory = val;
1031         val = ast_variable_retrieve(cfg,this,"macro");
1032         if (!val) val = MACRO;
1033         rpt_vars[n].p.macro = val;
1034         val = ast_variable_retrieve(cfg,this,"startup_macro");
1035         if (val) rpt_vars[n].p.startupmacro = val;
1036         val = ast_variable_retrieve(cfg,this,"iobase");
1037         /* do not use atoi() here, we need to be able to have
1038                 the input specified in hex or decimal so we use
1039                 sscanf with a %i */
1040         if ((!val) || (sscanf(val,"%i",&rpt_vars[n].p.iobase) != 1))
1041         rpt_vars[n].p.iobase = DEFAULT_IOBASE;
1042         val = ast_variable_retrieve(cfg,this,"functions");
1043         if (!val)
1044                 {
1045                         val = FUNCTIONS;
1046                         rpt_vars[n].p.simple = 1;
1047                 } 
1048         rpt_vars[n].p.functions = val;
1049         val =  ast_variable_retrieve(cfg,this,"link_functions");
1050         if (val) rpt_vars[n].p.link_functions = val;
1051         else 
1052                 rpt_vars[n].p.link_functions = rpt_vars[n].p.functions;
1053         val = ast_variable_retrieve(cfg,this,"phone_functions");
1054         if (val) rpt_vars[n].p.phone_functions = val;
1055         val = ast_variable_retrieve(cfg,this,"dphone_functions");
1056         if (val) rpt_vars[n].p.dphone_functions = val;
1057         val = ast_variable_retrieve(cfg,this,"funcchar");
1058         if (!val) rpt_vars[n].p.funcchar = FUNCCHAR; else 
1059                 rpt_vars[n].p.funcchar = *val;          
1060         val = ast_variable_retrieve(cfg,this,"endchar");
1061         if (!val) rpt_vars[n].p.endchar = ENDCHAR; else 
1062                 rpt_vars[n].p.endchar = *val;           
1063         val = ast_variable_retrieve(cfg,this,"nobusyout");
1064         if (val) rpt_vars[n].p.nobusyout = ast_true(val);
1065         val = ast_variable_retrieve(cfg,this,"nodes");
1066         if (!val) val = NODES;
1067         rpt_vars[n].p.nodes = val;
1068 #ifdef  __RPT_NOTCH
1069         val = ast_variable_retrieve(cfg,this,"rxnotch");
1070         if (val) {
1071                 i = finddelim(val,strs,MAXFILTERS * 2);
1072                 i &= ~1; /* force an even number, rounded down */
1073                 if (i >= 2) for(j = 0; j < i; j += 2)
1074                 {
1075                         rpt_mknotch(atof(strs[j]),atof(strs[j + 1]),
1076                           &rpt_vars[n].filters[j >> 1].gain,
1077                             &rpt_vars[n].filters[j >> 1].const0,
1078                                 &rpt_vars[n].filters[j >> 1].const1,
1079                                     &rpt_vars[n].filters[j >> 1].const2);
1080                         sprintf(rpt_vars[n].filters[j >> 1].desc,"%s Hz, BW = %s",
1081                                 strs[j],strs[j + 1]);
1082                 }
1083
1084         }
1085 #endif
1086         longestnode = 0;
1087
1088         vp = ast_variable_browse(cfg, rpt_vars[n].p.nodes);
1089                 
1090         while(vp){
1091                 j = strlen(vp->name);
1092                 if (j > longestnode)
1093                         longestnode = j;
1094                 vp = vp->next;
1095         }
1096
1097         rpt_vars[n].longestnode = longestnode;
1098                 
1099         /*
1100         * For this repeater, Determine the length of the longest function 
1101         */
1102         rpt_vars[n].longestfunc = 0;
1103         vp = ast_variable_browse(cfg, rpt_vars[n].p.functions);
1104         while(vp){
1105                 j = strlen(vp->name);
1106                 if (j > rpt_vars[n].longestfunc)
1107                         rpt_vars[n].longestfunc = j;
1108                 vp = vp->next;
1109         }
1110         /*
1111         * For this repeater, Determine the length of the longest function 
1112         */
1113         rpt_vars[n].link_longestfunc = 0;
1114         vp = ast_variable_browse(cfg, rpt_vars[n].p.link_functions);
1115         while(vp){
1116                 j = strlen(vp->name);
1117                 if (j > rpt_vars[n].link_longestfunc)
1118                         rpt_vars[n].link_longestfunc = j;
1119                 vp = vp->next;
1120         }
1121         rpt_vars[n].phone_longestfunc = 0;
1122         if (rpt_vars[n].p.phone_functions)
1123         {
1124                 vp = ast_variable_browse(cfg, rpt_vars[n].p.phone_functions);
1125                 while(vp){
1126                         j = strlen(vp->name);
1127                         if (j > rpt_vars[n].phone_longestfunc)
1128                                 rpt_vars[n].phone_longestfunc = j;
1129                         vp = vp->next;
1130                 }
1131         }
1132         rpt_vars[n].dphone_longestfunc = 0;
1133         if (rpt_vars[n].p.dphone_functions)
1134         {
1135                 vp = ast_variable_browse(cfg, rpt_vars[n].p.dphone_functions);
1136                 while(vp){
1137                         j = strlen(vp->name);
1138                         if (j > rpt_vars[n].dphone_longestfunc)
1139                                 rpt_vars[n].dphone_longestfunc = j;
1140                         vp = vp->next;
1141                 }
1142         }
1143         rpt_vars[n].macro_longest = 1;
1144         vp = ast_variable_browse(cfg, rpt_vars[n].p.macro);
1145         while(vp){
1146                 j = strlen(vp->name);
1147                 if (j > rpt_vars[n].macro_longest)
1148                         rpt_vars[n].macro_longest = j;
1149                 vp = vp->next;
1150         }
1151         ast_mutex_unlock(&rpt_vars[n].lock);
1152 }
1153
1154 /*
1155 * Enable or disable debug output at a given level at the console
1156 */
1157                                                                                                                                  
1158 static int rpt_do_debug(int fd, int argc, char *argv[])
1159 {
1160         int newlevel;
1161
1162         if (argc != 4)
1163                 return RESULT_SHOWUSAGE;
1164         newlevel = myatoi(argv[3]);
1165         if((newlevel < 0) || (newlevel > 7))
1166                 return RESULT_SHOWUSAGE;
1167         if(newlevel)
1168                 ast_cli(fd, "app_rpt Debugging enabled, previous level: %d, new level: %d\n", debug, newlevel);
1169         else
1170                 ast_cli(fd, "app_rpt Debugging disabled\n");
1171
1172         debug = newlevel;                                                                                                                          
1173         return RESULT_SUCCESS;
1174 }
1175
1176 /*
1177 * Dump rpt struct debugging onto console
1178 */
1179                                                                                                                                  
1180 static int rpt_do_dump(int fd, int argc, char *argv[])
1181 {
1182         int i;
1183
1184         if (argc != 3)
1185                 return RESULT_SHOWUSAGE;
1186
1187         for(i = 0; i < nrpts; i++)
1188         {
1189                 if (!strcmp(argv[2],rpt_vars[i].name))
1190                 {
1191                         rpt_vars[i].disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
1192                         ast_cli(fd, "app_rpt struct dump requested for node %s\n",argv[2]);
1193                         return RESULT_SUCCESS;
1194                 }
1195         }
1196         return RESULT_FAILURE;
1197 }
1198
1199 /*
1200 * Dump statistics onto console
1201 */
1202
1203 static int rpt_do_stats(int fd, int argc, char *argv[])
1204 {
1205         int i,j;
1206         int dailytxtime, dailykerchunks;
1207         int totalkerchunks, dailykeyups, totalkeyups, timeouts;
1208         int totalexecdcommands, dailyexecdcommands, hours, minutes, seconds;
1209         long long totaltxtime;
1210         struct  rpt_link *l;
1211         char *listoflinks[MAX_STAT_LINKS];      
1212         char *lastnodewhichkeyedusup, *lastdtmfcommand;
1213         char *tot_state, *ider_state, *patch_state;
1214         char *reverse_patch_state, *enable_state, *input_signal, *called_number;
1215         struct rpt *myrpt;
1216
1217         static char *not_applicable = "N/A";
1218
1219         if(argc != 3)
1220                 return RESULT_SHOWUSAGE;
1221
1222         for(i = 0 ; i <= MAX_STAT_LINKS; i++)
1223                 listoflinks[i] = NULL;
1224
1225         tot_state = ider_state = 
1226         patch_state = reverse_patch_state = 
1227         input_signal = called_number = 
1228         lastdtmfcommand = not_applicable;
1229
1230         for(i = 0; i < nrpts; i++)
1231         {
1232                 if (!strcmp(argv[2],rpt_vars[i].name)){
1233                         /* Make a copy of all stat variables while locked */
1234                         myrpt = &rpt_vars[i];
1235                         rpt_mutex_lock(&myrpt->lock); /* LOCK */
1236
1237                         dailytxtime = myrpt->dailytxtime;
1238                         totaltxtime = myrpt->totaltxtime;
1239                         dailykeyups = myrpt->dailykeyups;
1240                         totalkeyups = myrpt->totalkeyups;
1241                         dailykerchunks = myrpt->dailykerchunks;
1242                         totalkerchunks = myrpt->totalkerchunks;
1243                         dailyexecdcommands = myrpt->dailyexecdcommands;
1244                         totalexecdcommands = myrpt->totalexecdcommands;
1245                         timeouts = myrpt->timeouts;
1246
1247                         /* Traverse the list of connected nodes */
1248                         reverse_patch_state = "DOWN";
1249                         j = 0;
1250                         l = myrpt->links.next;
1251                         while(l != &myrpt->links){
1252                                 if (l->name[0] == '0'){ /* Skip '0' nodes */
1253                                         reverse_patch_state = "UP";
1254                                         l = l->next;
1255                                         continue;
1256                                 }
1257                                 listoflinks[j] = ast_strdupa(l->name);
1258                                 if(listoflinks[j])
1259                                         j++;
1260                                 l = l->next;
1261                         }
1262
1263                         lastnodewhichkeyedusup = ast_strdupa(myrpt->lastnodewhichkeyedusup);                    
1264                         if((!lastnodewhichkeyedusup) || (!strlen(lastnodewhichkeyedusup)))
1265                                 lastnodewhichkeyedusup = not_applicable;
1266
1267                         if(myrpt->keyed)
1268                                 input_signal = "YES";
1269                         else
1270                                 input_signal = "NO";
1271
1272                         if(myrpt->enable)
1273                                 enable_state = "YES";
1274                         else
1275                                 enable_state = "NO";
1276
1277                         if(!myrpt->totimer)
1278                                 tot_state = "TIMED OUT!";
1279                         else if(myrpt->totimer != myrpt->p.totime)
1280                                 tot_state = "ARMED";
1281                         else
1282                                 tot_state = "RESET";
1283
1284                         if(myrpt->tailid)
1285                                 ider_state = "QUEUED IN TAIL";
1286                         else if(myrpt->mustid)
1287                                 ider_state = "QUEUED FOR CLEANUP";
1288                         else
1289                                 ider_state = "CLEAN";
1290
1291                         switch(myrpt->callmode){
1292                                 case 1:
1293                                         patch_state = "DIALING";
1294                                         break;
1295                                 case 2:
1296                                         patch_state = "CONNECTING";
1297                                         break;
1298                                 case 3:
1299                                         patch_state = "UP";
1300                                         break;
1301
1302                                 case 4:
1303                                         patch_state = "CALL FAILED";
1304                                         break;
1305
1306                                 default:
1307                                         patch_state = "DOWN";
1308                         }
1309
1310                         if(strlen(myrpt->exten)){
1311                                 called_number = ast_strdupa(myrpt->exten);
1312                                 if(!called_number)
1313                                         called_number = not_applicable;
1314                         }
1315
1316                         if(strlen(myrpt->lastdtmfcommand)){
1317                                 lastdtmfcommand = ast_strdupa(myrpt->lastdtmfcommand);
1318                                 if(!lastdtmfcommand)
1319                                         lastdtmfcommand = not_applicable;
1320                         }
1321
1322                         rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
1323
1324                         ast_cli(fd, "************************ NODE %s STATISTICS *************************\n\n", myrpt->name);
1325                         ast_cli(fd, "Signal on input..................................: %s\n", input_signal);
1326                         ast_cli(fd, "Transmitter enabled..............................: %s\n", enable_state);
1327                         ast_cli(fd, "Time out timer state.............................: %s\n", tot_state);
1328                         ast_cli(fd, "Time outs since system initialization............: %d\n", timeouts);
1329                         ast_cli(fd, "Identifier state.................................: %s\n", ider_state);
1330                         ast_cli(fd, "Kerchunks today..................................: %d\n", dailykerchunks);
1331                         ast_cli(fd, "Kerchunks since system initialization............: %d\n", totalkerchunks);
1332                         ast_cli(fd, "Keyups today.....................................: %d\n", dailykeyups);
1333                         ast_cli(fd, "Keyups since system initialization...............: %d\n", totalkeyups);
1334                         ast_cli(fd, "DTMF commands today..............................: %d\n", dailyexecdcommands);
1335                         ast_cli(fd, "DTMF commands since system initialization........: %d\n", totalexecdcommands);
1336                         ast_cli(fd, "Last DTMF command executed.......................: %s\n", lastdtmfcommand);
1337
1338                         hours = dailytxtime/3600000;
1339                         dailytxtime %= 3600000;
1340                         minutes = dailytxtime/60000;
1341                         dailytxtime %= 60000;
1342                         seconds = dailytxtime/1000;
1343                         dailytxtime %= 1000;
1344
1345                         ast_cli(fd, "TX time today ...................................: %02d:%02d:%02d.%d\n",
1346                                 hours, minutes, seconds, dailytxtime);
1347
1348                         hours = (int) totaltxtime/3600000;
1349                         totaltxtime %= 3600000;
1350                         minutes = (int) totaltxtime/60000;
1351                         totaltxtime %= 60000;
1352                         seconds = (int)  totaltxtime/1000;
1353                         totaltxtime %= 1000;
1354
1355                         ast_cli(fd, "TX time since system initialization..............: %02d:%02d:%02d.%d\n",
1356                                  hours, minutes, seconds, (int) totaltxtime);
1357                         ast_cli(fd, "Nodes currently connected to us..................: ");
1358                         for(j = 0 ;; j++){
1359                                 if(!listoflinks[j]){
1360                                         if(!j){
1361                                                 ast_cli(fd,"<NONE>");
1362                                         }
1363                                         break;
1364                                 }
1365                                 ast_cli(fd, "%s", listoflinks[j]);
1366                                 if(j % 4 == 3){
1367                                         ast_cli(fd, "\n");
1368                                         ast_cli(fd, "                                                 : ");
1369                                 }
1370                                 else{
1371                                         if(listoflinks[j + 1])
1372                                                 ast_cli(fd, ", ");
1373                                 }
1374                         }
1375                         ast_cli(fd,"\n");
1376
1377                         ast_cli(fd, "Last node which transmitted to us................: %s\n", lastnodewhichkeyedusup);
1378                         ast_cli(fd, "Autopatch state..................................: %s\n", patch_state);
1379                         ast_cli(fd, "Autopatch called number..........................: %s\n", called_number);
1380                         ast_cli(fd, "Reverse patch/IAXRPT connected...................: %s\n\n", reverse_patch_state);
1381
1382                         return RESULT_SUCCESS;
1383                 }
1384         }
1385         return RESULT_FAILURE;
1386 }
1387
1388 /*
1389 * Link stats function
1390 */
1391
1392 static int rpt_do_lstats(int fd, int argc, char *argv[])
1393 {
1394         int i,j;
1395         struct rpt *myrpt;
1396         struct rpt_link *l;
1397         struct rpt_lstat *s,*t;
1398         struct rpt_lstat s_head;
1399         if(argc != 3)
1400                 return RESULT_SHOWUSAGE;
1401
1402         s = NULL;
1403         s_head.next = &s_head;
1404         s_head.prev = &s_head;
1405
1406         for(i = 0; i < nrpts; i++)
1407         {
1408                 if (!strcmp(argv[2],rpt_vars[i].name)){
1409                         /* Make a copy of all stat variables while locked */
1410                         myrpt = &rpt_vars[i];
1411                         rpt_mutex_lock(&myrpt->lock); /* LOCK */
1412                         /* Traverse the list of connected nodes */
1413                         j = 0;
1414                         l = myrpt->links.next;
1415                         while(l != &myrpt->links){
1416                                 if (l->name[0] == '0'){ /* Skip '0' nodes */
1417                                         l = l->next;
1418                                         continue;
1419                                 }
1420                                 if((s = (struct rpt_lstat *) malloc(sizeof(struct rpt_lstat))) == NULL){
1421                                         ast_log(LOG_ERROR, "Malloc failed in rpt_do_lstats\n");
1422                                         rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
1423                                         return RESULT_FAILURE;
1424                                 }
1425                                 memset(s, 0, sizeof(struct rpt_lstat));
1426                                 strncpy(s->name, l->name, MAXREMSTR - 1);
1427                                 pbx_substitute_variables_helper(l->chan, "${IAXPEER(CURRENTCHANNEL)}", s->peer, MAXPEERSTR - 1);
1428                                 s->mode = l->mode;
1429                                 s->outbound = l->outbound;
1430                                 s->reconnects = l->reconnects;
1431                                 s->connecttime = l->connecttime;
1432                                 insque((struct qelem *) s, (struct qelem *) s_head.next);
1433                                 l = l->next;
1434                         }
1435                         rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
1436                         ast_cli(fd, "NODE      PEER                RECONNECTS  DIRECTION  CONNECT TIME\n");
1437                         ast_cli(fd, "----      ----                ----------  ---------  ------------\n");
1438
1439                         for(s = s_head.next; s != &s_head; s = s->next){
1440                                 int hours, minutes, seconds;
1441                                 long long connecttime = s->connecttime;
1442                                 char conntime[31];
1443                                 hours = (int) connecttime/3600000;
1444                                 connecttime %= 3600000;
1445                                 minutes = (int) connecttime/60000;
1446                                 connecttime %= 60000;
1447                                 seconds = (int)  connecttime/1000;
1448                                 connecttime %= 1000;
1449                                 snprintf(conntime, 30, "%02d:%02d:%02d.%d",
1450                                         hours, minutes, seconds, (int) connecttime);
1451                                 conntime[30] = 0;
1452                                 ast_cli(fd, "%-10s%-20s%-12d%-11s%-30s\n",
1453                                         s->name, s->peer, s->reconnects, (s->outbound)? "OUT":"IN", conntime);
1454                         }       
1455                         /* destroy our local link queue */
1456                         s = s_head.next;
1457                         while(s != &s_head){
1458                                 t = s;
1459                                 s = s->next;
1460                                 remque((struct qelem *)t);
1461                                 free(t);
1462                         }                       
1463                         return RESULT_SUCCESS;
1464                 }
1465         }
1466         return RESULT_FAILURE;
1467 }
1468
1469 /*
1470 * reload vars 
1471 */
1472                                                                                                                                  
1473 static int rpt_do_reload(int fd, int argc, char *argv[])
1474 {
1475 int     n;
1476
1477         if (argc > 2) return RESULT_SHOWUSAGE;
1478
1479         for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
1480
1481         return RESULT_FAILURE;
1482 }
1483
1484 /*
1485 * restart app_rpt
1486 */
1487                                                                                                                                  
1488 static int rpt_do_restart(int fd, int argc, char *argv[])
1489 {
1490 int     i;
1491
1492         if (argc > 2) return RESULT_SHOWUSAGE;
1493         for(i = 0; i < nrpts; i++)
1494         {
1495                 if (rpt_vars[i].rxchannel) ast_softhangup(rpt_vars[i].rxchannel,AST_SOFTHANGUP_DEV);
1496         }
1497         return RESULT_FAILURE;
1498 }
1499
1500 static int play_tone_pair(struct ast_channel *chan, int f1, int f2, int duration, int amplitude)
1501 {
1502         int res;
1503
1504         if ((res = ast_tonepair_start(chan, f1, f2, duration, amplitude)))
1505                 return res;
1506                                                                                                                                             
1507         while(chan->generatordata) {
1508                 if (ast_safe_sleep(chan,1)) return -1;
1509         }
1510
1511         return 0;
1512 }
1513
1514 static int play_tone(struct ast_channel *chan, int freq, int duration, int amplitude)
1515 {
1516         return play_tone_pair(chan, freq, 0, duration, amplitude);
1517 }
1518
1519 static int play_silence(struct ast_channel *chan, int duration)
1520 {
1521         return play_tone_pair(chan, 0, 0, duration, 0);
1522 }
1523
1524
1525 static int send_morse(struct ast_channel *chan, char *string, int speed, int freq, int amplitude)
1526 {
1527
1528 static struct morse_bits mbits[] = {
1529                 {0, 0}, /* SPACE */
1530                 {0, 0}, 
1531                 {6, 18},/* " */
1532                 {0, 0},
1533                 {7, 72},/* $ */
1534                 {0, 0},
1535                 {0, 0},
1536                 {6, 30},/* ' */
1537                 {5, 13},/* ( */
1538                 {6, 29},/* ) */
1539                 {0, 0},
1540                 {5, 10},/* + */
1541                 {6, 51},/* , */
1542                 {6, 33},/* - */
1543                 {6, 42},/* . */
1544                 {5, 9}, /* / */
1545                 {5, 31},/* 0 */
1546                 {5, 30},/* 1 */
1547                 {5, 28},/* 2 */
1548                 {5, 24},/* 3 */
1549                 {5, 16},/* 4 */
1550                 {5, 0}, /* 5 */
1551                 {5, 1}, /* 6 */
1552                 {5, 3}, /* 7 */
1553                 {5, 7}, /* 8 */
1554                 {5, 15},/* 9 */
1555                 {6, 7}, /* : */
1556                 {6, 21},/* ; */
1557                 {0, 0},
1558                 {5, 33},/* = */
1559                 {0, 0},
1560                 {6, 12},/* ? */
1561                 {0, 0},
1562                 {2, 2}, /* A */
1563                 {4, 1}, /* B */
1564                 {4, 5}, /* C */
1565                 {3, 1}, /* D */
1566                 {1, 0}, /* E */
1567                 {4, 4}, /* F */
1568                 {3, 3}, /* G */
1569                 {4, 0}, /* H */
1570                 {2, 0}, /* I */
1571                 {4, 14},/* J */
1572                 {3, 5}, /* K */
1573                 {4, 2}, /* L */
1574                 {2, 3}, /* M */
1575                 {2, 1}, /* N */
1576                 {3, 7}, /* O */
1577                 {4, 6}, /* P */
1578                 {4, 11},/* Q */
1579                 {3, 2}, /* R */
1580                 {3, 0}, /* S */
1581                 {1, 1}, /* T */
1582                 {3, 4}, /* U */
1583                 {4, 8}, /* V */
1584                 {3, 6}, /* W */
1585                 {4, 9}, /* X */
1586                 {4, 13},/* Y */
1587                 {4, 3}  /* Z */
1588         };
1589
1590
1591         int dottime;
1592         int dashtime;
1593         int intralettertime;
1594         int interlettertime;
1595         int interwordtime;
1596         int len, ddcomb;
1597         int res;
1598         int c;
1599         int i;
1600         int flags;
1601                         
1602         res = 0;
1603         
1604         /* Approximate the dot time from the speed arg. */
1605         
1606         dottime = 900/speed;
1607         
1608         /* Establish timing releationships */
1609         
1610         dashtime = 3 * dottime;
1611         intralettertime = dottime;
1612         interlettertime = dottime * 4 ;
1613         interwordtime = dottime * 7;
1614         
1615         for(;(*string) && (!res); string++){
1616         
1617                 c = *string;
1618                 
1619                 /* Convert lower case to upper case */
1620                 
1621                 if((c >= 'a') && (c <= 'z'))
1622                         c -= 0x20;
1623                 
1624                 /* Can't deal with any char code greater than Z, skip it */
1625                 
1626                 if(c  > 'Z')
1627                         continue;
1628                 
1629                 /* If space char, wait the inter word time */
1630                                         
1631                 if(c == ' '){
1632                         if(!res)
1633                                 res = play_silence(chan, interwordtime);
1634                         continue;
1635                 }
1636                 
1637                 /* Subtract out control char offset to match our table */
1638                 
1639                 c -= 0x20;
1640                 
1641                 /* Get the character data */
1642                 
1643                 len = mbits[c].len;
1644                 ddcomb = mbits[c].ddcomb;
1645                 
1646                 /* Send the character */
1647                 
1648                 for(; len ; len--){
1649                         if(!res)
1650                                 res = play_tone(chan, freq, (ddcomb & 1) ? dashtime : dottime, amplitude);
1651                         if(!res)
1652                                 res = play_silence(chan, intralettertime);
1653                         ddcomb >>= 1;
1654                 }
1655                 
1656                 /* Wait the interletter time */
1657                 
1658                 if(!res)
1659                         res = play_silence(chan, interlettertime - intralettertime);
1660         }
1661         
1662         /* Wait for all the frames to be sent */
1663         
1664         if (!res) 
1665                 res = ast_waitstream(chan, "");
1666         ast_stopstream(chan);
1667         
1668         /*
1669         * Wait for the zaptel driver to physically write the tone blocks to the hardware
1670         */
1671
1672         for(i = 0; i < 20 ; i++){
1673                 flags =  ZT_IOMUX_WRITEEMPTY | ZT_IOMUX_NOWAIT; 
1674                 res = ioctl(chan->fds[0], ZT_IOMUX, &flags);
1675                 if(flags & ZT_IOMUX_WRITEEMPTY)
1676                         break;
1677                 if( ast_safe_sleep(chan, 50)){
1678                         res = -1;
1679                         break;
1680                 }
1681         }
1682
1683         
1684         return res;
1685 }
1686
1687 static int send_tone_telemetry(struct ast_channel *chan, char *tonestring)
1688 {
1689         char *stringp;
1690         char *tonesubset;
1691         int f1,f2;
1692         int duration;
1693         int amplitude;
1694         int res;
1695         int i;
1696         int flags;
1697         
1698         res = 0;
1699         
1700         stringp = ast_strdupa(tonestring);
1701
1702         for(;tonestring;){
1703                 tonesubset = strsep(&stringp,")");
1704                 if(!tonesubset)
1705                         break;
1706                 if(sscanf(tonesubset,"(%d,%d,%d,%d", &f1, &f2, &duration, &amplitude) != 4)
1707                         break;
1708                 res = play_tone_pair(chan, f1, f2, duration, amplitude);
1709                 if(res)
1710                         break;
1711         }
1712         if(!res)
1713                 res = play_tone_pair(chan, 0, 0, 100, 0); /* This is needed to ensure the last tone segment is timed correctly */
1714         
1715         if (!res) 
1716                 res = ast_waitstream(chan, "");
1717         ast_stopstream(chan);
1718
1719         /*
1720         * Wait for the zaptel driver to physically write the tone blocks to the hardware
1721         */
1722
1723         for(i = 0; i < 20 ; i++){
1724                 flags =  ZT_IOMUX_WRITEEMPTY | ZT_IOMUX_NOWAIT; 
1725                 res = ioctl(chan->fds[0], ZT_IOMUX, &flags);
1726                 if(flags & ZT_IOMUX_WRITEEMPTY)
1727                         break;
1728                 if( ast_safe_sleep(chan, 50)){
1729                         res = -1;
1730                         break;
1731                 }
1732         }
1733                 
1734         return res;
1735                 
1736 }
1737         
1738
1739 static int sayfile(struct ast_channel *mychannel,char *fname)
1740 {
1741 int     res;
1742
1743         res = ast_streamfile(mychannel, fname, mychannel->language);
1744         if (!res) 
1745                 res = ast_waitstream(mychannel, "");
1746         else
1747                  ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1748         ast_stopstream(mychannel);
1749         return res;
1750 }
1751
1752 static int saycharstr(struct ast_channel *mychannel,char *str)
1753 {
1754 int     res;
1755
1756         res = ast_say_character_str(mychannel,str,NULL,mychannel->language);
1757         if (!res) 
1758                 res = ast_waitstream(mychannel, "");
1759         else
1760                  ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1761         ast_stopstream(mychannel);
1762         return res;
1763 }
1764
1765 static int saynum(struct ast_channel *mychannel, int num)
1766 {
1767         int res;
1768         res = ast_say_number(mychannel, num, NULL, mychannel->language, NULL);
1769         if(!res)
1770                 res = ast_waitstream(mychannel, "");
1771         else
1772                 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1773         ast_stopstream(mychannel);
1774         return res;
1775 }
1776
1777
1778 static int telem_any(struct rpt *myrpt,struct ast_channel *chan, char *entry)
1779 {
1780         int res;
1781         char c;
1782         
1783         static int morsespeed;
1784         static int morsefreq;
1785         static int morseampl;
1786         static int morseidfreq = 0;
1787         static int morseidampl;
1788         static char mcat[] = MORSE;
1789         
1790         res = 0;
1791         
1792         if(!morseidfreq){ /* Get the morse parameters if not already loaded */
1793                 morsespeed = retrieve_astcfgint(myrpt, mcat, "speed", 5, 20, 20);
1794                 morsefreq = retrieve_astcfgint(myrpt, mcat, "frequency", 300, 3000, 800);
1795                 morseampl = retrieve_astcfgint(myrpt, mcat, "amplitude", 200, 8192, 4096);
1796                 morseidampl = retrieve_astcfgint(myrpt, mcat, "idamplitude", 200, 8192, 2048);
1797                 morseidfreq = retrieve_astcfgint(myrpt, mcat, "idfrequency", 300, 3000, 330);   
1798         }
1799         
1800         /* Is it a file, or a tone sequence? */
1801                         
1802         if(entry[0] == '|'){
1803                 c = entry[1];
1804                 if((c >= 'a')&&(c <= 'z'))
1805                         c -= 0x20;
1806         
1807                 switch(c){
1808                         case 'I': /* Morse ID */
1809                                 res = send_morse(chan, entry + 2, morsespeed, morseidfreq, morseidampl);
1810                                 break;
1811                         
1812                         case 'M': /* Morse Message */
1813                                 res = send_morse(chan, entry + 2, morsespeed, morsefreq, morseampl);
1814                                 break;
1815                         
1816                         case 'T': /* Tone sequence */
1817                                 res = send_tone_telemetry(chan, entry + 2);
1818                                 break;
1819                         default:
1820                                 res = -1;
1821                 }
1822         }
1823         else
1824                 res = sayfile(chan, entry); /* File */
1825         return res;
1826 }
1827
1828 /*
1829 * This function looks up a telemetry name in the config file, and does a telemetry response as configured.
1830 *
1831 * 4 types of telemtry are handled: Morse ID, Morse Message, Tone Sequence, and a File containing a recording.
1832 */
1833
1834 static int telem_lookup(struct rpt *myrpt,struct ast_channel *chan, char *node, char *name)
1835 {
1836         
1837         int res;
1838         int i;
1839         char *entry;
1840         char *telemetry;
1841         char *telemetry_save;
1842
1843         res = 0;
1844         telemetry_save = NULL;
1845         entry = NULL;
1846         
1847         /* Retrieve the section name for telemetry from the node section */
1848         telemetry = ast_variable_retrieve(myrpt->cfg, node, TELEMETRY);
1849         if(telemetry ){
1850                 telemetry_save = ast_strdupa(telemetry);
1851                 if(!telemetry_save){
1852                         ast_log(LOG_WARNING,"ast_strdupa() failed in telem_lookup()\n");
1853                         return res;
1854                 }
1855                 entry = ast_variable_retrieve(myrpt->cfg, telemetry_save, name);
1856         }
1857         
1858         /* Try to look up the telemetry name */ 
1859
1860         if(!entry){
1861                 /* Telemetry name wasn't found in the config file, use the default */
1862                 for(i = 0; i < sizeof(tele_defs)/sizeof(struct telem_defaults) ; i++){
1863                         if(!strcasecmp(tele_defs[i].name, name))
1864                                 entry = tele_defs[i].value;
1865                 }
1866         }
1867         if(entry){      
1868                 if(strlen(entry))
1869                         telem_any(myrpt,chan, entry);
1870         }
1871         else{
1872                 res = -1;
1873         }
1874         return res;
1875 }
1876
1877 /*
1878 * Retrieve a wait interval
1879 */
1880
1881 static int get_wait_interval(struct rpt *myrpt, int type)
1882 {
1883         int interval;
1884         char *wait_times;
1885         char *wait_times_save;
1886                                                                                                                   
1887         wait_times_save = NULL;
1888         wait_times = ast_variable_retrieve(myrpt->cfg, myrpt->name, "wait_times");
1889                                                                                                                   
1890         if(wait_times){
1891                 wait_times_save = ast_strdupa(wait_times);
1892                 if(!wait_times_save){
1893                         ast_log(LOG_WARNING, "Out of memory in wait_interval()\n");
1894                         wait_times = NULL;
1895                 }
1896         }
1897                                                                                                                   
1898         switch(type){
1899                 case DLY_TELEM:
1900                         if(wait_times)
1901                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "telemwait", 500, 5000, 1000);
1902                         else
1903                                 interval = 1000;
1904                         break;
1905                                                                                                                   
1906                 case DLY_ID:
1907                         if(wait_times)
1908                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "idwait",250,5000,500);
1909                         else
1910                                 interval = 500;
1911                         break;
1912                                                                                                                   
1913                 case DLY_UNKEY:
1914                         if(wait_times)
1915                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "unkeywait",500,5000,1000);
1916                         else
1917                                 interval = 1000;
1918                         break;
1919                                                                                                                   
1920                 case DLY_CALLTERM:
1921                         if(wait_times)
1922                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "calltermwait",500,5000,1500);
1923                         else
1924                                 interval = 1500;
1925                         break;
1926                                                                                                                   
1927                 default:
1928                         return 0;
1929         }
1930         return interval;
1931 }                                                                                                                  
1932
1933
1934 /*
1935 * Wait a configurable interval of time 
1936 */
1937
1938
1939 static void wait_interval(struct rpt *myrpt, int type, struct ast_channel *chan)
1940 {
1941         int interval;
1942         interval = get_wait_interval(myrpt, type);
1943         if(debug)
1944                 ast_log(LOG_NOTICE," Delay interval = %d\n", interval);
1945         if(interval)
1946                 ast_safe_sleep(chan,interval);
1947         if(debug)
1948                 ast_log(LOG_NOTICE,"Delay complete\n");
1949         return;
1950 }
1951
1952
1953 static void *rpt_tele_thread(void *this)
1954 {
1955 ZT_CONFINFO ci;  /* conference info */
1956 int     res = 0,haslink,hastx,hasremote,imdone = 0, unkeys_queued, x;
1957 struct  rpt_tele *mytele = (struct rpt_tele *)this;
1958 struct  rpt_tele *tlist;
1959 struct  rpt *myrpt;
1960 struct  rpt_link *l,*m,linkbase;
1961 struct  ast_channel *mychannel;
1962 int vmajor, vminor;
1963 char *p,*ct,*ct_copy,*ident, *nodename;
1964 time_t t;
1965 struct tm localtm;
1966
1967         /* get a pointer to myrpt */
1968         myrpt = mytele->rpt;
1969
1970         /* Snag copies of a few key myrpt variables */
1971         rpt_mutex_lock(&myrpt->lock);
1972         nodename = ast_strdupa(myrpt->name);
1973         ident = ast_strdupa(myrpt->p.ident);
1974         rpt_mutex_unlock(&myrpt->lock);
1975         
1976         /* allocate a pseudo-channel thru asterisk */
1977         mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
1978         if (!mychannel)
1979         {
1980                 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
1981                 rpt_mutex_lock(&myrpt->lock);
1982                 remque((struct qelem *)mytele);
1983                 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
1984                 rpt_mutex_unlock(&myrpt->lock);
1985                 free(mytele);           
1986                 pthread_exit(NULL);
1987         }
1988         rpt_mutex_lock(&myrpt->lock);
1989         mytele->chan = mychannel; /* Save a copy of the channel so we can access it externally if need be */
1990         rpt_mutex_unlock(&myrpt->lock);
1991         
1992         /* make a conference for the tx */
1993         ci.chan = 0;
1994         /* If there's an ID queued, or tail message queued, */
1995         /* only connect the ID audio to the local tx conference so */
1996         /* linked systems can't hear it */
1997         ci.confno = (((mytele->mode == ID) || (mytele->mode == IDTALKOVER) || (mytele->mode == UNKEY) || 
1998                 (mytele->mode == TAILMSG)) ?
1999                         myrpt->txconf : myrpt->conf);
2000         ci.confmode = ZT_CONF_CONFANN;
2001         /* first put the channel on the conference in announce mode */
2002         if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
2003         {
2004                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2005                 rpt_mutex_lock(&myrpt->lock);
2006                 remque((struct qelem *)mytele);
2007                 rpt_mutex_unlock(&myrpt->lock);
2008                 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
2009                 free(mytele);           
2010                 ast_hangup(mychannel);
2011                 pthread_exit(NULL);
2012         }
2013         ast_stopstream(mychannel);
2014         switch(mytele->mode)
2015         {
2016
2017             case ID:
2018             case ID1:
2019                 /* wait a bit */
2020                 wait_interval(myrpt, (mytele->mode == ID) ? DLY_ID : DLY_TELEM,mychannel);
2021                 res = telem_any(myrpt,mychannel, ident); 
2022                 imdone=1;       
2023                 break;
2024                 
2025             case TAILMSG:
2026                 res = ast_streamfile(mychannel, myrpt->p.tailmessages[myrpt->tailmessagen], mychannel->language); 
2027                 break;
2028                 
2029             case IDTALKOVER:
2030                 p = ast_variable_retrieve(myrpt->cfg, nodename, "idtalkover");
2031                 if(p)
2032                         res = telem_any(myrpt,mychannel, p); 
2033                 imdone=1;       
2034                 break;
2035                         
2036             case PROC:
2037                 /* wait a little bit longer */
2038                 wait_interval(myrpt, DLY_TELEM, mychannel);
2039                 res = telem_lookup(myrpt, mychannel, myrpt->name, "patchup");
2040                 if(res < 0){ /* Then default message */
2041                         res = ast_streamfile(mychannel, "rpt/callproceeding", mychannel->language);
2042                 }
2043                 break;
2044             case TERM:
2045                 /* wait a little bit longer */
2046                 wait_interval(myrpt, DLY_CALLTERM, mychannel);
2047                 res = telem_lookup(myrpt, mychannel, myrpt->name, "patchdown");
2048                 if(res < 0){ /* Then default message */
2049                         res = ast_streamfile(mychannel, "rpt/callterminated", mychannel->language);
2050                 }
2051                 break;
2052             case COMPLETE:
2053                 /* wait a little bit */
2054                 wait_interval(myrpt, DLY_TELEM, mychannel);
2055                 res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
2056                 break;
2057             case MACRO_NOTFOUND:
2058                 /* wait a little bit */
2059                 wait_interval(myrpt, DLY_TELEM, mychannel);
2060                 res = ast_streamfile(mychannel, "rpt/macro_notfound", mychannel->language);
2061                 break;
2062             case MACRO_BUSY:
2063                 /* wait a little bit */
2064                 wait_interval(myrpt, DLY_TELEM, mychannel);
2065                 res = ast_streamfile(mychannel, "rpt/macro_busy", mychannel->language);
2066                 break;
2067             case UNKEY:
2068                 if(myrpt->patchnoct && myrpt->callmode){ /* If no CT during patch configured, then don't send one */
2069                         imdone = 1;
2070                         break;
2071                 }
2072                         
2073                 /*
2074                 * Reset the Unkey to CT timer
2075                 */
2076
2077                 x = get_wait_interval(myrpt, DLY_UNKEY);
2078                 rpt_mutex_lock(&myrpt->lock);
2079                 myrpt->unkeytocttimer = x; /* Must be protected as it is changed below */
2080                 rpt_mutex_unlock(&myrpt->lock);
2081
2082                 /*
2083                 * If there's one already queued, don't do another
2084                 */
2085
2086                 tlist = myrpt->tele.next;
2087                 unkeys_queued = 0;
2088                 if (tlist != &myrpt->tele)
2089                 {
2090                         rpt_mutex_lock(&myrpt->lock);
2091                         while(tlist != &myrpt->tele){
2092                                 if (tlist->mode == UNKEY) unkeys_queued++;
2093                                 tlist = tlist->next;
2094                         }
2095                         rpt_mutex_unlock(&myrpt->lock);
2096                 }
2097                 if( unkeys_queued > 1){
2098                         imdone = 1;
2099                         break;
2100                 }
2101
2102                 /* Wait for the telemetry timer to expire */
2103                 /* Periodically check the timer since it can be re-initialized above */
2104                 while(myrpt->unkeytocttimer)
2105                 {
2106                         int ctint;
2107                         if(myrpt->unkeytocttimer > 100)
2108                                 ctint = 100;
2109                         else
2110                                 ctint = myrpt->unkeytocttimer;
2111                         ast_safe_sleep(mychannel, ctint);
2112                         rpt_mutex_lock(&myrpt->lock);
2113                         if(myrpt->unkeytocttimer < ctint)
2114                                 myrpt->unkeytocttimer = 0;
2115                         else
2116                                 myrpt->unkeytocttimer -= ctint;
2117                         rpt_mutex_unlock(&myrpt->lock);
2118                 }
2119         
2120                 /*
2121                 * Now, the carrier on the rptr rx should be gone. 
2122                 * If it re-appeared, then forget about sending the CT
2123                 */
2124                 if(myrpt->keyed){
2125                         imdone = 1;
2126                         break;
2127                 }
2128                 
2129                 rpt_mutex_lock(&myrpt->lock); /* Update the kerchunk counters */
2130                 myrpt->dailykerchunks++;
2131                 myrpt->totalkerchunks++;
2132                 rpt_mutex_unlock(&myrpt->lock);
2133         
2134                 haslink = 0;
2135                 hastx = 0;
2136                 hasremote = 0;          
2137                 l = myrpt->links.next;
2138                 if (l != &myrpt->links)
2139                 {
2140                         rpt_mutex_lock(&myrpt->lock);
2141                         while(l != &myrpt->links)
2142                         {
2143                                 if (l->name[0] == '0')
2144                                 {
2145                                         l = l->next;
2146                                         continue;
2147                                 }
2148                                 haslink = 1;
2149                                 if (l->mode) {
2150                                         hastx++;
2151                                         if (l->isremote) hasremote++;
2152                                 }
2153                                 l = l->next;
2154                         }
2155                         rpt_mutex_unlock(&myrpt->lock);
2156                 }
2157                 if (haslink)
2158                 {
2159
2160                         res = telem_lookup(myrpt,mychannel, myrpt->name, (!hastx) ? "remotemon" : "remotetx");
2161                         if(res)
2162                                 ast_log(LOG_WARNING, "telem_lookup:remotexx failed on %s\n", mychannel->name);
2163                         
2164                 
2165                         /* if in remote cmd mode, indicate it */
2166                         if (myrpt->cmdnode[0])
2167                         {
2168                                 ast_safe_sleep(mychannel,200);
2169                                 res = telem_lookup(myrpt,mychannel, myrpt->name, "cmdmode");
2170                                 if(res)
2171                                         ast_log(LOG_WARNING, "telem_lookup:cmdmode failed on %s\n", mychannel->name);
2172                                 ast_stopstream(mychannel);
2173                         }
2174                 }
2175                 else if((ct = ast_variable_retrieve(myrpt->cfg, nodename, "unlinkedct"))){ /* Unlinked Courtesy Tone */
2176                         ct_copy = ast_strdupa(ct);
2177                         res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
2178                         if(res)
2179                                 ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);               
2180                 }       
2181                 if (hasremote && (!myrpt->cmdnode[0]))
2182                 {
2183                         /* set for all to hear */
2184                         ci.chan = 0;
2185                         ci.confno = myrpt->conf;
2186                         ci.confmode = ZT_CONF_CONFANN;
2187                         /* first put the channel on the conference in announce mode */
2188                         if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
2189                         {
2190                                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2191                                 rpt_mutex_lock(&myrpt->lock);
2192                                 remque((struct qelem *)mytele);
2193                                 rpt_mutex_unlock(&myrpt->lock);
2194                                 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
2195                                 free(mytele);           
2196                                 ast_hangup(mychannel);
2197                                 pthread_exit(NULL);
2198                         }
2199                         if((ct = ast_variable_retrieve(myrpt->cfg, nodename, "remotect"))){ /* Unlinked Courtesy Tone */
2200                                 ast_safe_sleep(mychannel,200);
2201                                 ct_copy = ast_strdupa(ct);
2202                                 res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
2203                                 if(res)
2204                                         ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);               
2205                         }       
2206                 }
2207 #ifdef  _MDC_DECODE_H_
2208                 if (myrpt->lastunit)
2209                 {
2210                         char mystr[10];
2211
2212                         ast_safe_sleep(mychannel,200);
2213                         /* set for all to hear */
2214                         ci.chan = 0;
2215                         ci.confno = myrpt->txconf;
2216                         ci.confmode = ZT_CONF_CONFANN;
2217                         /* first put the channel on the conference in announce mode */
2218                         if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
2219                         {
2220                                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2221                                 rpt_mutex_lock(&myrpt->lock);
2222                                 remque((struct qelem *)mytele);
2223                                 rpt_mutex_unlock(&myrpt->lock);
2224                                 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
2225                                 free(mytele);           
2226                                 ast_hangup(mychannel);
2227                                 pthread_exit(NULL);
2228                         }
2229                         sprintf(mystr,"%04x",myrpt->lastunit);
2230                         myrpt->lastunit = 0;
2231                         ast_say_character_str(mychannel,mystr,NULL,mychannel->language);
2232                         break;
2233                 }
2234 #endif
2235                 imdone = 1;
2236                 break;
2237             case REMDISC:
2238                 /* wait a little bit */
2239                 wait_interval(myrpt, DLY_TELEM, mychannel);
2240                 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
2241                 if (!res) 
2242                         res = ast_waitstream(mychannel, "");
2243                 else
2244                          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2245                 ast_stopstream(mychannel);
2246                 ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
2247                 res = ast_streamfile(mychannel, ((mytele->mylink.connected) ? 
2248                         "rpt/remote_disc" : "rpt/remote_busy"), mychannel->language);
2249                 break;
2250             case REMALREADY:
2251                 /* wait a little bit */
2252                 wait_interval(myrpt, DLY_TELEM, mychannel);
2253                 res = ast_streamfile(mychannel, "rpt/remote_already", mychannel->language);
2254                 break;
2255             case REMNOTFOUND:
2256                 /* wait a little bit */
2257                 wait_interval(myrpt, DLY_TELEM, mychannel);
2258                 res = ast_streamfile(mychannel, "rpt/remote_notfound", mychannel->language);
2259                 break;
2260             case REMGO:
2261                 /* wait a little bit */
2262                 wait_interval(myrpt, DLY_TELEM, mychannel);
2263                 res = ast_streamfile(mychannel, "rpt/remote_go", mychannel->language);
2264                 break;
2265             case CONNECTED:
2266                 /* wait a little bit */
2267                 wait_interval(myrpt, DLY_TELEM,  mychannel);
2268                 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
2269                 if (!res) 
2270                         res = ast_waitstream(mychannel, "");
2271                 else
2272                          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2273                 ast_stopstream(mychannel);
2274                 ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
2275                 res = ast_streamfile(mychannel, "rpt/connected", mychannel->language);
2276                 break;
2277             case CONNFAIL:
2278                 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
2279                 if (!res) 
2280                         res = ast_waitstream(mychannel, "");
2281                 else
2282                          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2283                 ast_stopstream(mychannel);
2284                 ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
2285                 res = ast_streamfile(mychannel, "rpt/connection_failed", mychannel->language);
2286                 break;
2287             case STATUS:
2288                 /* wait a little bit */
2289                 wait_interval(myrpt, DLY_TELEM, mychannel);
2290                 hastx = 0;
2291                 linkbase.next = &linkbase;
2292                 linkbase.prev = &linkbase;
2293                 rpt_mutex_lock(&myrpt->lock);
2294                 /* make our own list of links */
2295                 l = myrpt->links.next;
2296                 while(l != &myrpt->links)
2297                 {
2298                         if (l->name[0] == '0')
2299                         {
2300                                 l = l->next;
2301                                 continue;
2302                         }
2303                         m = malloc(sizeof(struct rpt_link));
2304                         if (!m)
2305                         {
2306                                 ast_log(LOG_WARNING, "Cannot alloc memory on %s\n", mychannel->name);
2307                                 remque((struct qelem *)mytele);
2308                                 rpt_mutex_unlock(&myrpt->lock);
2309                                 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
2310                                 free(mytele);           
2311                                 ast_hangup(mychannel);
2312                                 pthread_exit(NULL);
2313                         }
2314                         memcpy(m,l,sizeof(struct rpt_link));
2315                         m->next = m->prev = NULL;
2316                         insque((struct qelem *)m,(struct qelem *)linkbase.next);
2317                         l = l->next;
2318                 }
2319                 rpt_mutex_unlock(&myrpt->lock);
2320                 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
2321                 if (!res) 
2322                         res = ast_waitstream(mychannel, "");
2323                 else
2324                          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2325                 ast_stopstream(mychannel);
2326                 ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
2327                 if (!res) 
2328                         res = ast_waitstream(mychannel, "");
2329                 else
2330                          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2331                 ast_stopstream(mychannel);
2332                 if (myrpt->callmode)
2333                 {
2334                         hastx = 1;
2335                         res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
2336                         if (!res) 
2337                                 res = ast_waitstream(mychannel, "");
2338                         else
2339                                  ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2340                         ast_stopstream(mychannel);
2341                 }
2342                 l = linkbase.next;
2343                 while(l != &linkbase)
2344                 {
2345                         hastx = 1;
2346                         res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
2347                         if (!res) 
2348                                 res = ast_waitstream(mychannel, "");
2349                         else
2350                                 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2351                         ast_stopstream(mychannel);
2352                         ast_say_character_str(mychannel,l->name,NULL,mychannel->language);
2353                         if (!res) 
2354                                 res = ast_waitstream(mychannel, "");
2355                         else
2356                                  ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2357                         ast_stopstream(mychannel);
2358                         res = ast_streamfile(mychannel, ((l->mode) ? 
2359                                 "rpt/tranceive" : "rpt/monitor"), mychannel->language);
2360                         if (!res) 
2361                                 res = ast_waitstream(mychannel, "");
2362                         else
2363                                 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2364                         ast_stopstream(mychannel);
2365                         l = l->next;
2366                 }                       
2367                 if (!hastx)
2368                 {
2369                         res = ast_streamfile(mychannel, "rpt/repeat_only", mychannel->language);
2370                         if (!res) 
2371                                 res = ast_waitstream(mychannel, "");
2372                         else
2373                                  ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2374                         ast_stopstream(mychannel);
2375                 }
2376                 /* destroy our local link queue */
2377                 l = linkbase.next;
2378                 while(l != &linkbase)
2379                 {
2380                         m = l;
2381                         l = l->next;
2382                         remque((struct qelem *)m);
2383                         free(m);
2384                 }                       
2385                 imdone = 1;
2386                 break;
2387
2388             case LASTNODEKEY: /* Identify last node which keyed us up */
2389                 rpt_mutex_lock(&myrpt->lock);
2390                 if(myrpt->lastnodewhichkeyedusup)
2391                         p = ast_strdupa(myrpt->lastnodewhichkeyedusup); /* Make a local copy of the node name */
2392                 else
2393                         p = NULL;
2394                 rpt_mutex_unlock(&myrpt->lock);
2395                 if(!p){
2396                         imdone = 1; /* no node previously keyed us up, or the node which did has been disconnected */
2397                         break;
2398                 }
2399                 wait_interval(myrpt, DLY_TELEM, mychannel);
2400                 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
2401                 if (!res) 
2402                         res = ast_waitstream(mychannel, "");
2403                 else
2404                          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2405                 ast_stopstream(mychannel);
2406                 ast_say_character_str(mychannel, p, NULL, mychannel->language);
2407                 if (!res) 
2408                         res = ast_waitstream(mychannel, "");
2409                 else
2410                         ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2411                 ast_stopstream(mychannel);
2412                 imdone = 1;
2413                 break;          
2414
2415             case TIMEOUT:
2416                 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
2417                 if (!res) 
2418                         res = ast_waitstream(mychannel, "");
2419                 else
2420                          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2421                 ast_stopstream(mychannel);
2422                 ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
2423                 res = ast_streamfile(mychannel, "rpt/timeout", mychannel->language);
2424                 break;
2425                 
2426             case STATS_TIME:
2427                 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
2428                 t = time(NULL);
2429                 localtime_r(&t, &localtm);
2430                 /* Say the phase of the day is before the time */
2431                 if((localtm.tm_hour >= 0) && (localtm.tm_hour < 12))
2432                         p = "rpt/goodmorning";
2433                 else if((localtm.tm_hour >= 12) && (localtm.tm_hour < 18))
2434                         p = "rpt/goodafternoon";
2435                 else
2436                         p = "rpt/goodevening";
2437                 if (sayfile(mychannel,p) == -1)
2438                 {
2439                         imdone = 1;
2440                         break;
2441                 }
2442                 /* Say the time is ... */               
2443                 if (sayfile(mychannel,"rpt/thetimeis") == -1)
2444                 {
2445                         imdone = 1;
2446                         break;
2447                 }
2448                 /* Say the time */                              
2449                 res = ast_say_time(mychannel, t, "", mychannel->language);
2450                 if (!res) 
2451                         res = ast_waitstream(mychannel, "");
2452                 ast_stopstream(mychannel);              
2453                 imdone = 1;
2454                 break;
2455             case STATS_VERSION:
2456                 p = strstr(tdesc, "version");   
2457                 if(!p)
2458                         break;  
2459                 if(sscanf(p, "version %d.%d", &vmajor, &vminor) != 2)
2460                         break;
2461                 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
2462                 /* Say "version" */
2463                 if (sayfile(mychannel,"rpt/version") == -1)
2464                 {
2465                         imdone = 1;
2466                         break;
2467                 }
2468                 if(!res) /* Say "X" */
2469                         ast_say_number(mychannel, vmajor, "", mychannel->language, (char *) NULL);
2470                 if (!res) 
2471                         res = ast_waitstream(mychannel, "");
2472                 ast_stopstream(mychannel);      
2473                 if (saycharstr(mychannel,".") == -1)
2474                 {
2475                         imdone = 1;
2476                         break;
2477                 }
2478                 if(!res) /* Say "Y" */
2479                         ast_say_number(mychannel, vminor, "", mychannel->language, (char *) NULL);
2480                 if (!res){
2481                         res = ast_waitstream(mychannel, "");
2482                         ast_stopstream(mychannel);
2483                 }       
2484                 else
2485                          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2486                 imdone = 1;
2487                 break;
2488             case ARB_ALPHA:
2489                 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
2490                 if(mytele->param)
2491                         saycharstr(mychannel, mytele->param);
2492                 imdone = 1;
2493                 break;
2494             case REV_PATCH:
2495                 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
2496                 if(mytele->param) {
2497
2498                         /* Parts of this section taken from app_parkandannounce */
2499                         char *tpl_working, *tpl_current;
2500                         char *tmp[100], *myparm;
2501                         int looptemp=0,i=0, dres = 0;
2502         
2503
2504                         tpl_working = strdupa(mytele->param);
2505                         myparm = strsep(&tpl_working,",");
2506                         tpl_current=strsep(&tpl_working, ":");
2507
2508                         while(tpl_current && looptemp < sizeof(tmp)) {
2509                                 tmp[looptemp]=tpl_current;
2510                                 looptemp++;
2511                                 tpl_current=strsep(&tpl_working,":");
2512                         }
2513
2514                         for(i=0; i<looptemp; i++) {
2515                                 if(!strcmp(tmp[i], "PARKED")) {
2516                                         ast_say_digits(mychannel, atoi(myparm), "", mychannel->language);
2517                                 } else if(!strcmp(tmp[i], "NODE")) {
2518                                         ast_say_digits(mychannel, atoi(myrpt->name), "", mychannel->language);
2519                                 } else {
2520                                         dres = ast_streamfile(mychannel, tmp[i], mychannel->language);
2521                                         if(!dres) {
2522                                                 dres = ast_waitstream(mychannel, "");
2523                                         } else {
2524                                                 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", tmp[i], mychannel->name);
2525                                                 dres = 0;
2526                                         }
2527                                 }
2528                         }
2529                 }
2530                 imdone = 1;
2531                 break;
2532             case TEST_TONE:
2533                 imdone = 1;
2534                 myrpt->stopgen = 0;
2535                 if ((res = ast_tonepair_start(mychannel, 1004.0, 0, 99999999, 7200.0))) 
2536                         break;
2537                 while(mychannel->generatordata && (!myrpt->stopgen)) {
2538                         if (ast_safe_sleep(mychannel,1)) break;
2539                         imdone = 1;
2540                         }
2541                 break;
2542             default:
2543                 break;
2544         }
2545         myrpt->stopgen = 0;
2546         if (!imdone)
2547         {
2548                 if (!res) 
2549                         res = ast_waitstream(mychannel, "");
2550                 else {
2551                         ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2552                         res = 0;
2553                 }
2554         }
2555         ast_stopstream(mychannel);
2556         rpt_mutex_lock(&myrpt->lock);
2557         if (mytele->mode == TAILMSG)
2558         {
2559                 if (!res)
2560                 {
2561                         myrpt->tailmessagen++;
2562                         if(myrpt->tailmessagen >= myrpt->p.tailmessagemax) myrpt->tailmessagen = 0;
2563                 }
2564                 else
2565                 {
2566                         myrpt->tmsgtimer = myrpt->p.tailsquashedtime;
2567                 }
2568         }
2569         remque((struct qelem *)mytele);
2570         rpt_mutex_unlock(&myrpt->lock);
2571         free(mytele);           
2572         ast_hangup(mychannel);
2573 #ifdef  APP_RPT_LOCK_DEBUG
2574         {
2575                 struct lockthread *t;
2576
2577                 sleep(5);
2578                 ast_mutex_lock(&locklock);
2579                 t = get_lockthread(pthread_self());
2580                 if (t) memset(t,0,sizeof(struct lockthread));
2581                 ast_mutex_unlock(&locklock);
2582         }                       
2583 #endif
2584         pthread_exit(NULL);
2585 }
2586
2587 static void rpt_telemetry(struct rpt *myrpt,int mode, void *data)
2588 {
2589 struct rpt_tele *tele;
2590 struct rpt_link *mylink = (struct rpt_link *) data;
2591 int res;
2592 pthread_attr_t attr;
2593
2594         tele = malloc(sizeof(struct rpt_tele));
2595         if (!tele)
2596         {
2597                 ast_log(LOG_WARNING, "Unable to allocate memory\n");
2598                 pthread_exit(NULL);
2599                 return;
2600         }
2601         /* zero it out */
2602         memset((char *)tele,0,sizeof(struct rpt_tele));
2603         tele->rpt = myrpt;
2604         tele->mode = mode;
2605         rpt_mutex_lock(&myrpt->lock);
2606         if((mode == CONNFAIL) || (mode == REMDISC) || (mode == CONNECTED)){
2607                 memset(&tele->mylink,0,sizeof(struct rpt_link));
2608                 if (mylink){
2609                         memcpy(&tele->mylink,mylink,sizeof(struct rpt_link));
2610                 }
2611         }
2612         else if ((mode == ARB_ALPHA) || (mode == REV_PATCH)) {
2613                 strncpy(tele->param, (char *) data, TELEPARAMSIZE - 1);
2614                 tele->param[TELEPARAMSIZE - 1] = 0;
2615         }
2616         insque((struct qelem *)tele, (struct qelem *)myrpt->tele.next);
2617         rpt_mutex_unlock(&myrpt->lock);
2618         pthread_attr_init(&attr);
2619         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2620         res = ast_pthread_create(&tele->threadid,&attr,rpt_tele_thread,(void *) tele);
2621         if(res < 0){
2622                 rpt_mutex_lock(&myrpt->lock);
2623                 remque((struct qlem *) tele); /* We don't like stuck transmitters, remove it from the queue */
2624                 rpt_mutex_unlock(&myrpt->lock); 
2625                 ast_log(LOG_WARNING, "Could not create telemetry thread: %s",strerror(res));
2626         }
2627         return;
2628 }
2629
2630 static void *rpt_call(void *this)
2631 {
2632 ZT_CONFINFO ci;  /* conference info */
2633 struct  rpt *myrpt = (struct rpt *)this;
2634 int     res;
2635 struct  ast_frame wf;
2636 int stopped,congstarted,dialtimer,lastcidx,aborted;
2637 struct ast_channel *mychannel,*genchannel;
2638
2639
2640         myrpt->mydtmf = 0;
2641         /* allocate a pseudo-channel thru asterisk */
2642         mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
2643         if (!mychannel)
2644         {
2645                 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
2646                 pthread_exit(NULL);
2647         }
2648         ci.chan = 0;
2649         ci.confno = myrpt->conf; /* use the pseudo conference */
2650         ci.confmode = ZT_CONF_REALANDPSEUDO | ZT_CONF_TALKER | ZT_CONF_LISTENER
2651                 | ZT_CONF_PSEUDO_TALKER | ZT_CONF_PSEUDO_LISTENER; 
2652         /* first put the channel on the conference */
2653         if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
2654         {
2655                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2656                 ast_hangup(mychannel);
2657                 myrpt->callmode = 0;
2658                 pthread_exit(NULL);
2659         }
2660         /* allocate a pseudo-channel thru asterisk */
2661         genchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
2662         if (!genchannel)
2663         {
2664                 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
2665                 ast_hangup(mychannel);
2666                 pthread_exit(NULL);
2667         }
2668         ci.chan = 0;
2669         ci.confno = myrpt->conf;
2670         ci.confmode = ZT_CONF_REALANDPSEUDO | ZT_CONF_TALKER | ZT_CONF_LISTENER
2671                 | ZT_CONF_PSEUDO_TALKER | ZT_CONF_PSEUDO_LISTENER; 
2672         /* first put the channel on the conference */
2673         if (ioctl(genchannel->fds[0],ZT_SETCONF,&ci) == -1)
2674         {
2675                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2676                 ast_hangup(mychannel);
2677                 ast_hangup(genchannel);
2678                 myrpt->callmode = 0;
2679                 pthread_exit(NULL);
2680         }
2681         if (myrpt->p.tonezone && (tone_zone_set_zone(mychannel->fds[0],myrpt->p.tonezone) == -1))
2682         {
2683                 ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
2684                 ast_hangup(mychannel);
2685                 ast_hangup(genchannel);
2686                 myrpt->callmode = 0;
2687                 pthread_exit(NULL);
2688         }
2689         if (myrpt->p.tonezone && (tone_zone_set_zone(genchannel->fds[0],myrpt->p.tonezone) == -1))
2690         {
2691                 ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
2692                 ast_hangup(mychannel);
2693                 ast_hangup(genchannel);
2694                 myrpt->callmode = 0;
2695                 pthread_exit(NULL);
2696         }
2697         /* start dialtone if patchquiet is 0. Special patch modes don't send dial tone */
2698         if ((!myrpt->patchquiet) && (tone_zone_play_tone(mychannel->fds[0],ZT_TONE_DIALTONE) < 0))
2699         {
2700                 ast_log(LOG_WARNING, "Cannot start dialtone\n");
2701                 ast_hangup(mychannel);
2702                 ast_hangup(genchannel);
2703                 myrpt->callmode = 0;
2704                 pthread_exit(NULL);
2705         }
2706         stopped = 0;
2707         congstarted = 0;
2708         dialtimer = 0;
2709         lastcidx = 0;
2710         aborted = 0;
2711
2712
2713         while ((myrpt->callmode == 1) || (myrpt->callmode == 4))
2714         {
2715
2716                 if((myrpt->patchdialtime)&&(myrpt->callmode == 1)&&(myrpt->cidx != lastcidx)){
2717                         dialtimer = 0;
2718                         lastcidx = myrpt->cidx;
2719                 }               
2720
2721                 if((myrpt->patchdialtime)&&(dialtimer >= myrpt->patchdialtime)){ 
2722                         rpt_mutex_lock(&myrpt->lock);
2723                         aborted = 1;
2724                         myrpt->callmode = 0;
2725                         rpt_mutex_unlock(&myrpt->lock);
2726                         break;
2727                 }
2728         
2729                 if ((!myrpt->patchquiet) && (!stopped) && (myrpt->callmode == 1) && (myrpt->cidx > 0))
2730                 {
2731                         stopped = 1;
2732                         /* stop dial tone */
2733                         tone_zone_play_tone(mychannel->fds[0],-1);
2734                 }
2735                 if (myrpt->callmode == 4)
2736                 {
2737                         if(!congstarted){
2738                                 congstarted = 1;
2739                                 /* start congestion tone */
2740                                 tone_zone_play_tone(mychannel->fds[0],ZT_TONE_CONGESTION);
2741                         }
2742                 }
2743                 res = ast_safe_sleep(mychannel, MSWAIT);
2744                 if (res < 0)
2745                 {
2746                         ast_hangup(mychannel);
2747                         ast_hangup(genchannel);
2748                         rpt_mutex_lock(&myrpt->lock);
2749                         myrpt->callmode = 0;
2750                         rpt_mutex_unlock(&myrpt->lock);
2751                         pthread_exit(NULL);
2752                 }
2753                 dialtimer += MSWAIT;
2754         }
2755         /* stop any tone generation */
2756         tone_zone_play_tone(mychannel->fds[0],-1);
2757         /* end if done */
2758         if (!myrpt->callmode)
2759         {
2760                 ast_hangup(mychannel);
2761                 ast_hangup(genchannel);
2762                 rpt_mutex_lock(&myrpt->lock);
2763                 myrpt->callmode = 0;
2764                 rpt_mutex_unlock(&myrpt->lock);
2765                 if((!myrpt->patchquiet) && aborted)
2766                         rpt_telemetry(myrpt, TERM, NULL);
2767                 pthread_exit(NULL);                     
2768         }
2769
2770         if (myrpt->p.ourcallerid && *myrpt->p.ourcallerid){
2771                 char *name, *loc, *instr;
2772                 instr = strdup(myrpt->p.ourcallerid);
2773                 if(instr){
2774                         ast_callerid_parse(instr, &name, &loc);
2775                         if(loc){
2776                                 if(mychannel->cid.cid_num)
2777                                         free(mychannel->cid.cid_num);
2778                                 mychannel->cid.cid_num = strdup(loc);
2779                         }
2780                         if(name){
2781                                 if(mychannel->cid.cid_name)
2782                                         free(mychannel->cid.cid_name);
2783                                 mychannel->cid.cid_name = strdup(name);
2784                         }
2785                         free(instr);
2786                 }
2787         }
2788
2789         strncpy(mychannel->exten, myrpt->exten, sizeof(mychannel->exten) - 1);
2790         strncpy(mychannel->context, myrpt->patchcontext, sizeof(mychannel->context) - 1);
2791         
2792         if (myrpt->p.acctcode)
2793                 strncpy((char *)mychannel->accountcode, myrpt->p.acctcode, sizeof(mychannel->accountcode) - 1);
2794         mychannel->priority = 1;
2795         ast_channel_undefer_dtmf(mychannel);
2796         if (ast_pbx_start(mychannel) < 0)
2797         {
2798                 ast_log(LOG_WARNING, "Unable to start PBX!!\n");
2799                 ast_hangup(mychannel);
2800                 ast_hangup(genchannel);
2801                 rpt_mutex_lock(&myrpt->lock);
2802                 myrpt->callmode = 0;
2803                 rpt_mutex_unlock(&myrpt->lock);
2804                 pthread_exit(NULL);
2805         }
2806         usleep(10000);
2807         rpt_mutex_lock(&myrpt->lock);
2808         myrpt->callmode = 3;
2809         /* set appropriate conference for the pseudo */
2810         ci.chan = 0;
2811         ci.confno = myrpt->conf;
2812         ci.confmode = (myrpt->p.duplex == 2) ? ZT_CONF_CONFANNMON :
2813                 (ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER);
2814         /* first put the channel on the conference in announce mode */
2815         if (ioctl(myrpt->pchannel->fds[0],ZT_SETCONF,&ci) == -1)
2816         {
2817                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2818                 ast_hangup(mychannel);
2819                 ast_hangup(genchannel);
2820                 myrpt->callmode = 0;
2821                 pthread_exit(NULL);
2822         }
2823         while(myrpt->callmode)
2824         {
2825                 if ((!mychannel->pbx) && (myrpt->callmode != 4))
2826                 {
2827                         if(myrpt->patchfarenddisconnect){ /* If patch is setup for far end disconnect */
2828                                 myrpt->callmode = 0;
2829                                 if(!myrpt->patchquiet){
2830                                         rpt_mutex_unlock(&myrpt->lock);
2831                                         rpt_telemetry(myrpt, TERM, NULL);
2832                                         rpt_mutex_lock(&myrpt->lock);
2833                                 }
2834                         }
2835                         else{ /* Send congestion until patch is downed by command */
2836                                 myrpt->callmode = 4;
2837                                 rpt_mutex_unlock(&myrpt->lock);
2838                                 /* start congestion tone */
2839                                 tone_zone_play_tone(genchannel->fds[0],ZT_TONE_CONGESTION);
2840                                 rpt_mutex_lock(&myrpt->lock);
2841                         }
2842                 }
2843                 if (myrpt->mydtmf)
2844                 {
2845                         wf.frametype = AST_FRAME_DTMF;
2846                         wf.subclass = myrpt->mydtmf;
2847                         wf.offset = 0;
2848                         wf.mallocd = 0;
2849                         wf.data = NULL;
2850                         wf.datalen = 0;
2851                         wf.samples = 0;
2852                         rpt_mutex_unlock(&myrpt->lock);
2853                         ast_write(genchannel,&wf); 
2854                         rpt_mutex_lock(&myrpt->lock);
2855                         myrpt->mydtmf = 0;
2856                 }
2857                 rpt_mutex_unlock(&myrpt->lock);
2858                 usleep(MSWAIT * 1000);
2859                 rpt_mutex_lock(&myrpt->lock);
2860         }
2861         rpt_mutex_unlock(&myrpt->lock);
2862         tone_zone_play_tone(genchannel->fds[0],-1);
2863         if (mychannel->pbx) ast_softhangup(mychannel,AST_SOFTHANGUP_DEV);
2864         ast_hangup(genchannel);
2865         rpt_mutex_lock(&myrpt->lock);
2866         myrpt->callmode = 0;
2867         rpt_mutex_unlock(&myrpt->lock);
2868         /* set appropriate conference for the pseudo */
2869         ci.chan = 0;
2870         ci.confno = myrpt->conf;
2871         ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? ZT_CONF_CONFANNMON :
2872                 (ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER);
2873         /* first put the channel on the conference in announce mode */
2874         if (ioctl(myrpt->pchannel->fds[0],ZT_SETCONF,&ci) == -1)
2875         {
2876                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2877         }
2878         pthread_exit(NULL);
2879 }
2880
2881 static void send_link_dtmf(struct rpt *myrpt,char c)
2882 {
2883 char    str[300];
2884 struct  ast_frame wf;
2885 struct  rpt_link *l;
2886
2887         snprintf(str, sizeof(str), "D %s %s %d %c", myrpt->cmdnode, myrpt->name, ++(myrpt->dtmfidx), c);
2888         wf.frametype = AST_FRAME_TEXT;
2889         wf.subclass = 0;
2890         wf.offset = 0;
2891         wf.mallocd = 1;
2892         wf.datalen = strlen(str) + 1;
2893         wf.samples = 0;
2894         l = myrpt->links.next;
2895         /* first, see if our dude is there */
2896         while(l != &myrpt->links)
2897         {
2898                 if (l->name[0] == '0') 
2899                 {
2900                         l = l->next;
2901                         continue;
2902                 }
2903                 /* if we found it, write it and were done */
2904                 if (!strcmp(l->name,myrpt->cmdnode))
2905                 {
2906                         wf.data = strdup(str);
2907                         if (l->chan) ast_write(l->chan,&wf);
2908                         return;
2909                 }
2910                 l = l->next;
2911         }
2912         l = myrpt->links.next;
2913         /* if not, give it to everyone */
2914         while(l != &myrpt->links)
2915         {
2916                 wf.data = strdup(str);
2917                 if (l->chan) ast_write(l->chan,&wf);
2918                 l = l->next;
2919         }
2920         return;
2921 }
2922
2923 /*
2924 * Internet linking function 
2925 */
2926
2927 static int function_ilink(struct rpt *myrpt, char *param, char *digits, int command_source, struct rpt_link *mylink)
2928 {
2929
2930         char *val, *s, *s1, *s2, *tele;
2931         char tmp[300], deststr[300] = "",modechange = 0;
2932         char digitbuf[MAXNODESTR];
2933         struct rpt_link *l;
2934         int reconnects = 0;
2935         ZT_CONFINFO ci;  /* conference info */
2936
2937         if(!param)
2938                 return DC_ERROR;
2939                 
2940                         
2941         if (!myrpt->enable)
2942                 return DC_ERROR;
2943
2944         strncpy(digitbuf,digits,MAXNODESTR - 1);
2945
2946         if(debug)
2947                 printf("@@@@ ilink param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
2948                 
2949         switch(myatoi(param)){
2950                 case 1: /* Link off */
2951                         if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
2952                                 strcpy(digitbuf,myrpt->lastlinknode);
2953                         val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
2954                         if (!val){
2955                                 if(strlen(digitbuf) >= myrpt->longestnode)
2956                                         return DC_ERROR;
2957                                 break;
2958                         }
2959                         strncpy(tmp,val,sizeof(tmp) - 1);
2960                         s = tmp;
2961                         s1 = strsep(&s,",");
2962                         s2 = strsep(&s,",");
2963                         rpt_mutex_lock(&myrpt->lock);
2964                         l = myrpt->links.next;
2965                         /* try to find this one in queue */
2966                         while(l != &myrpt->links){
2967                                 if (l->name[0] == '0') 
2968                                 {
2969                                         l = l->next;
2970                                         continue;
2971                                 }
2972                                 /* if found matching string */
2973                                 if (!strcmp(l->name, digitbuf))
2974                                         break;
2975                                 l = l->next;
2976                         }
2977                         if (l != &myrpt->links){ /* if found */
2978                                 struct  ast_frame wf;
2979                                 strncpy(myrpt->lastlinknode,digitbuf,MAXNODESTR - 1);
2980                                 l->retries = MAX_RETRIES + 1;
2981                                 l->disced = 1;
2982                                 rpt_mutex_unlock(&myrpt->lock);
2983                                 wf.frametype = AST_FRAME_TEXT;
2984                                 wf.subclass = 0;
2985                                 wf.offset = 0;
2986                                 wf.mallocd = 1;
2987                                 wf.datalen = strlen(discstr) + 1;
2988                                 wf.samples = 0;
2989                                 wf.data = strdup(discstr);
2990                                 if (l->chan)
2991                                 {
2992                                         ast_write(l->chan,&wf);
2993                                         if (ast_safe_sleep(l->chan,250) == -1) return DC_ERROR;
2994                                         ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
2995                                 }
2996                                 rpt_telemetry(myrpt, COMPLETE, NULL);
2997                                 return DC_COMPLETE;
2998                         }
2999                         rpt_mutex_unlock(&myrpt->lock); 
3000                         return DC_COMPLETE;
3001                 case 2: /* Link Monitor */
3002                         if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
3003                                 strcpy(digitbuf,myrpt->lastlinknode);
3004                         val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
3005                         if (!val){
3006                                 if(strlen(digitbuf) >= myrpt->longestnode)
3007                                         return DC_ERROR;
3008                                 break;
3009                         }
3010                         strncpy(tmp,val,sizeof(tmp) - 1);
3011                         s = tmp;
3012                         s1 = strsep(&s,",");
3013                         s2 = strsep(&s,",");
3014                         rpt_mutex_lock(&myrpt->lock);
3015                         l = myrpt->links.next;
3016                         /* try to find this one in queue */
3017                         while(l != &myrpt->links){
3018                                 if (l->name[0] == '0') 
3019                                 {
3020                                         l = l->next;
3021                                         continue;
3022                                 }
3023                                 /* if found matching string */
3024                                 if (!strcmp(l->name, digitbuf))
3025                                         break;
3026                                 l = l->next;
3027                         }
3028                         /* if found */
3029                         if (l != &myrpt->links) 
3030                         {
3031                                 /* if already in this mode, just ignore */
3032                                 if ((!l->mode) || (!l->chan)) {
3033                                         rpt_mutex_unlock(&myrpt->lock);
3034                                         rpt_telemetry(myrpt,REMALREADY,NULL);
3035                                         return DC_COMPLETE;
3036                                         
3037                                 }
3038                                 reconnects = l->reconnects;
3039                                 rpt_mutex_unlock(&myrpt->lock);
3040                                 if (l->chan) ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
3041                                 l->retries = MAX_RETRIES + 1;
3042                                 l->disced = 2;
3043                                 modechange = 1;
3044                         } else
3045                                 rpt_mutex_unlock(&myrpt->lock);
3046                         strncpy(myrpt->lastlinknode,digitbuf,MAXNODESTR - 1);
3047                         /* establish call in monitor mode */
3048                         l = malloc(sizeof(struct rpt_link));
3049                         if (!l){
3050                                 ast_log(LOG_WARNING, "Unable to malloc\n");
3051                                 return DC_ERROR;
3052                         }
3053                         /* zero the silly thing */
3054                         memset((char *)l,0,sizeof(struct rpt_link));
3055                         snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
3056                         tele = strchr(deststr,'/');
3057                         if (!tele){
3058                                 fprintf(stderr,"link2:Dial number (%s) must be in format tech/number\n",deststr);
3059                                 return DC_ERROR;
3060                         }
3061                         *tele++ = 0;
3062                         l->isremote = (s && ast_true(s));
3063                         strncpy(l->name, digitbuf, MAXNODESTR - 1);
3064                         l->chan = ast_request(deststr,AST_FORMAT_SLINEAR,tele,NULL);
3065                         if (modechange) l->connected = 1;
3066                         if (l->chan){
3067                                 ast_set_read_format(l->chan,AST_FORMAT_SLINEAR);
3068                                 ast_set_write_format(l->chan,AST_FORMAT_SLINEAR);
3069                                 l->chan->whentohangup = 0;
3070                                 l->chan->appl = "Apprpt";
3071                                 l->chan->data = "(Remote Rx)";
3072                                 if (option_verbose > 2)
3073                                         ast_verbose(VERBOSE_PREFIX_3 "rpt (remote) initiating call to %s/%s on %s\n",
3074                                                 deststr,tele,l->chan->name);
3075                                 if(l->chan->cid.cid_num)
3076                                         free(l->chan->cid.cid_num);
3077                                 l->chan->cid.cid_num = strdup(myrpt->name);
3078                                 ast_call(l->chan,tele,0);
3079                         }
3080                         else
3081                         {
3082                                 rpt_telemetry(myrpt,CONNFAIL,l);
3083                                 free(l);
3084                                 if (option_verbose > 2)
3085                                         ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
3086                                                 deststr,tele,l->chan->name);
3087                                 return DC_ERROR;
3088                         }
3089                         /* allocate a pseudo-channel thru asterisk */
3090                         l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
3091                         if (!l->pchan){
3092  &nbs