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