Mon May 14 04:42:51 2007

Asterisk developer's documentation


app_rpt.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2002-2005, Jim Dixon, WB6NIL
00005  *
00006  * Jim Dixon, WB6NIL <jim@lambdatel.com>
00007  * Serious contributions by Steve RoDgers, WA6ZFT <hwstar@rodgers.sdcoxmail.com>
00008  *
00009  * See http://www.asterisk.org for more information about
00010  * the Asterisk project. Please do not directly contact
00011  * any of the maintainers of this project for assistance;
00012  * the project provides a web site, mailing lists and IRC
00013  * channels for your use.
00014  *
00015  * This program is free software, distributed under the terms of
00016  * the GNU General Public License Version 2. See the LICENSE file
00017  * at the top of the source tree.
00018  */
00019 
00020 /*! \file
00021  *
00022  * \brief Radio Repeater / Remote Base program 
00023  *  version 0.48 06/13/06
00024  * 
00025  * \author Jim Dixon, WB6NIL <jim@lambdatel.com>
00026  *
00027  * \note Serious contributions by Steve RoDgers, WA6ZFT <hwstar@rodgers.sdcoxmail.com>
00028  * 
00029  * See http://www.zapatatelephony.org/app_rpt.html
00030  *
00031  *
00032  * Repeater / Remote Functions:
00033  * "Simple" Mode:  * - autopatch access, # - autopatch hangup
00034  * Normal mode:
00035  * See the function list in rpt.conf (autopatchup, autopatchdn)
00036  * autopatchup can optionally take comma delimited setting=value pairs:
00037  *  
00038  *
00039  * context=string    :  Override default context with "string"
00040  * dialtime=ms       :  Specify the max number of milliseconds between phone number digits (1000 milliseconds = 1 second)
00041  * farenddisconnect=1      :  Automatically disconnect when called party hangs up
00042  * noct=1         :  Don't send repeater courtesy tone during autopatch calls
00043  * quiet=1        :  Don't send dial tone, or connect messages. Do not send patch down message when called party hangs up
00044  *
00045  *
00046  * Example: 123=autopatchup,dialtime=20000,noct=1,farenddisconnect=1
00047  *
00048  *  To send an asterisk (*) while dialing or talking on phone,
00049  *  use the autopatch acess code.
00050  *
00051  *
00052  * status cmds:
00053  *
00054  *  1 - Force ID
00055  *  2 - Give Time of Day
00056  *  3 - Give software Version
00057  *
00058  * cop (control operator) cmds:
00059  *
00060  *  1 - System warm boot
00061  *  2 - System enable
00062  *  3 - System disable
00063  *  4 - Test Tone On
00064  *  5 - Dump System Variables on Console (debug)
00065  *  6 - PTT (phone mode only)
00066  *
00067  * ilink cmds:
00068  *
00069  *  1 - Disconnect specified link
00070  *  2 - Connect specified link -- monitor only
00071  *  3 - Connect specified link -- tranceive
00072  *  4 - Enter command mode on specified link
00073  *  5 - System status
00074  *  6 - Disconnect all links
00075  *
00076  * remote cmds:
00077  *
00078  *  1 - Recall Memory MM  (*000-*099) (Gets memory from rpt.conf)
00079  *  2 - Set VFO MMMMM*KKK*O   (Mhz digits, Khz digits, Offset)
00080  *  3 - Set Rx PL Tone HHH*D*
00081  *  4 - Set Tx PL Tone HHH*D* (Not currently implemented with DHE RBI-1)
00082  *  5 - Link Status (long)
00083  *  6 - Set operating mode M (FM, USB, LSB, AM, etc)
00084  *  100 - RX PL off (Default)
00085  *  101 - RX PL On
00086  *  102 - TX PL Off (Default)
00087  *  103 - TX PL On
00088  *  104 - Low Power
00089  *  105 - Med Power
00090  *  106 - Hi Power
00091  *  107 - Bump Down 20 Hz
00092  *  108 - Bump Down 100 Hz
00093  *  109 - Bump Down 500 Hz
00094  *  110 - Bump Up 20 Hz
00095  *  111 - Bump Up 100 Hz
00096  *  112 - Bump Up 500 Hz
00097  *  113 - Scan Down Slow
00098  *  114 - Scan Down Medium
00099  *  115 - Scan Down Fast
00100  *  116 - Scan Up Slow
00101  *  117 - Scan Up Medium
00102  *  118 - Scan Up Fast
00103  *  119 - Transmit allowing auto-tune
00104  *  140 - Link Status (brief)
00105  *
00106  *
00107  *
00108  * 'duplex' modes:  (defaults to duplex=2)
00109  *
00110  * 0 - Only remote links key Tx and no main repeat audio.
00111  * 1 - Everything other then main Rx keys Tx, no main repeat audio.
00112  * 2 - Normal mode
00113  * 3 - Normal except no main repeat audio.
00114  * 4 - Normal except no main repeat audio during autopatch only
00115  *
00116 */
00117 
00118 /*** MODULEINFO
00119    <depend>zaptel</depend>
00120    <depend>tonezone</depend>
00121  ***/
00122 
00123 /* Un-comment the following to include support for MDC-1200 digital tone
00124    signalling protocol (using KA6SQG's GPL'ed implementation) */
00125 /* #include "mdc_decode.c" */
00126 
00127 /* Un-comment the following to include support for notch filters in the
00128    rx audio stream (using Tony Fisher's mknotch (mkfilter) implementation) */
00129 /* #include "rpt_notch.c" */
00130 
00131 /* maximum digits in DTMF buffer, and seconds after * for DTMF command timeout */
00132 
00133 #define  MAXDTMF 32
00134 #define  MAXMACRO 2048
00135 #define  MACROTIME 100
00136 #define  MACROPTIME 500
00137 #define  DTMF_TIMEOUT 3
00138 
00139 #ifdef   __RPT_NOTCH
00140 #define  MAXFILTERS 10
00141 #endif
00142 
00143 #define  DISC_TIME 10000  /* report disc after 10 seconds of no connect */
00144 #define  MAX_RETRIES 5
00145 
00146 #define  REDUNDANT_TX_TIME 2000
00147 
00148 #define  RETRY_TIMER_MS 5000
00149 
00150 #define MAXPEERSTR 31
00151 #define  MAXREMSTR 15
00152 
00153 #define  DELIMCHR ','
00154 #define  QUOTECHR 34
00155 
00156 #define  NODES "nodes"
00157 #define MEMORY "memory"
00158 #define MACRO "macro"
00159 #define  FUNCTIONS "functions"
00160 #define TELEMETRY "telemetry"
00161 #define MORSE "morse"
00162 #define  FUNCCHAR '*'
00163 #define  ENDCHAR '#'
00164 
00165 #define  DEFAULT_IOBASE 0x378
00166 
00167 #define  MAXCONNECTTIME 5000
00168 
00169 #define MAXNODESTR 300
00170 
00171 #define MAXPATCHCONTEXT 100
00172 
00173 #define ACTIONSIZE 32
00174 
00175 #define TELEPARAMSIZE 256
00176 
00177 #define REM_SCANTIME 100
00178 
00179 
00180 enum {REM_OFF,REM_MONITOR,REM_TX};
00181 
00182 enum{ID,PROC,TERM,COMPLETE,UNKEY,REMDISC,REMALREADY,REMNOTFOUND,REMGO,
00183    CONNECTED,CONNFAIL,STATUS,TIMEOUT,ID1, STATS_TIME,
00184    STATS_VERSION, IDTALKOVER, ARB_ALPHA, TEST_TONE, REV_PATCH,
00185    TAILMSG, MACRO_NOTFOUND, MACRO_BUSY, LASTNODEKEY};
00186 
00187 enum {REM_SIMPLEX,REM_MINUS,REM_PLUS};
00188 
00189 enum {REM_LOWPWR,REM_MEDPWR,REM_HIPWR};
00190 
00191 enum {DC_INDETERMINATE, DC_REQ_FLUSH, DC_ERROR, DC_COMPLETE, DC_DOKEY};
00192 
00193 enum {SOURCE_RPT, SOURCE_LNK, SOURCE_RMT, SOURCE_PHONE, SOURCE_DPHONE};
00194 
00195 enum {DLY_TELEM, DLY_ID, DLY_UNKEY, DLY_CALLTERM};
00196 
00197 enum {REM_MODE_FM,REM_MODE_USB,REM_MODE_LSB,REM_MODE_AM};
00198 
00199 enum {HF_SCAN_OFF,HF_SCAN_DOWN_SLOW,HF_SCAN_DOWN_QUICK,
00200       HF_SCAN_DOWN_FAST,HF_SCAN_UP_SLOW,HF_SCAN_UP_QUICK,HF_SCAN_UP_FAST};
00201 
00202 #include "asterisk.h"
00203 
00204 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
00205 
00206 #include <signal.h>
00207 #include <stdio.h>
00208 #include <unistd.h>
00209 #include <string.h>
00210 #include <stdlib.h>
00211 #include <search.h>
00212 #include <sys/types.h>
00213 #include <sys/stat.h>
00214 #include <errno.h>
00215 #include <dirent.h>
00216 #include <ctype.h>
00217 #include <sys/stat.h>
00218 #include <sys/time.h>
00219 #include <sys/file.h>
00220 #include <sys/ioctl.h>
00221 #include <sys/io.h>
00222 #include <math.h>
00223 #include <zaptel/zaptel.h>
00224 #include <zaptel/tonezone.h>
00225 #include <netinet/in.h>
00226 #include <arpa/inet.h>
00227 
00228 #include "asterisk/utils.h"
00229 #include "asterisk/lock.h"
00230 #include "asterisk/file.h"
00231 #include "asterisk/logger.h"
00232 #include "asterisk/channel.h"
00233 #include "asterisk/callerid.h"
00234 #include "asterisk/pbx.h"
00235 #include "asterisk/module.h"
00236 #include "asterisk/translate.h"
00237 #include "asterisk/features.h"
00238 #include "asterisk/options.h"
00239 #include "asterisk/cli.h"
00240 #include "asterisk/config.h"
00241 #include "asterisk/say.h"
00242 #include "asterisk/localtime.h"
00243 
00244 static char *app = "Rpt";
00245 
00246 static char *synopsis = "Radio Repeater/Remote Base Control System";
00247 
00248 static char *descrip = 
00249 "  Rpt(nodename[|options]):  Radio Remote Link or Remote Base Link Endpoint Process.\n"
00250 "\n"
00251 "    Not specifying an option puts it in normal endpoint mode (where source\n"
00252 "    IP and nodename are verified).\n"
00253 "\n"
00254 "    Options are as follows:\n"
00255 "\n"
00256 "        X - Normal endpoint mode WITHOUT security check. Only specify\n"
00257 "            this if you have checked security already (like with an IAX2\n"
00258 "            user/password or something).\n"
00259 "\n"
00260 "        Rannounce-string[|timeout[|timeout-destination]] - Amateur Radio\n"
00261 "            Reverse Autopatch. Caller is put on hold, and announcement (as\n"
00262 "            specified by the 'announce-string') is played on radio system.\n"
00263 "            Users of radio system can access autopatch, dial specified\n"
00264 "            code, and pick up call. Announce-string is list of names of\n"
00265 "            recordings, or \"PARKED\" to substitute code for un-parking,\n"
00266 "            or \"NODE\" to substitute node number.\n"
00267 "\n"
00268 "        P - Phone Control mode. This allows a regular phone user to have\n"
00269 "            full control and audio access to the radio system. For the\n"
00270 "            user to have DTMF control, the 'phone_functions' parameter\n"
00271 "            must be specified for the node in 'rpt.conf'. An additional\n"
00272 "            function (cop,6) must be listed so that PTT control is available.\n"
00273 "\n"
00274 "        D - Dumb Phone Control mode. This allows a regular phone user to\n"
00275 "            have full control and audio access to the radio system. In this\n"
00276 "            mode, the PTT is activated for the entire length of the call.\n"
00277 "            For the user to have DTMF control (not generally recomended in\n"
00278 "            this mode), the 'dphone_functions' parameter must be specified\n"
00279 "            for the node in 'rpt.conf'. Otherwise no DTMF control will be\n"
00280 "            available to the phone user.\n"
00281 "\n";
00282 
00283 static unsigned int vmajor = 0;
00284 static unsigned int vminor = 47;
00285 
00286 static int debug = 0;  /* FIXME Set this >0 for extra debug output */
00287 static int nrpts = 0;
00288 
00289 char *discstr = "!!DISCONNECT!!";
00290 static char *remote_rig_ft897="ft897";
00291 static char *remote_rig_rbi="rbi";
00292 
00293 #ifdef   OLD_ASTERISK
00294 STANDARD_LOCAL_USER;
00295 #endif
00296 
00297 
00298 #define  MSWAIT 200
00299 #define  HANGTIME 5000
00300 #define  TOTIME 180000
00301 #define  IDTIME 300000
00302 #define  MAXRPTS 20
00303 #define MAX_STAT_LINKS 32
00304 #define POLITEID 30000
00305 #define FUNCTDELAY 1500
00306 
00307 static  pthread_t rpt_master_thread;
00308 
00309 struct rpt;
00310 
00311 struct rpt_link
00312 {
00313    struct rpt_link *next;
00314    struct rpt_link *prev;
00315    char  mode;       /* 1 if in tx mode */
00316    char  isremote;
00317    char  phonemode;
00318    char  name[MAXNODESTR]; /* identifier (routing) string */
00319    char  lasttx;
00320    char  lastrx;
00321    char  connected;
00322    char  hasconnected;
00323    char  outbound;
00324    char  disced;
00325    char  killme;
00326    long  elaptime;
00327    long  disctime;
00328    long  retrytimer;
00329    long  retxtimer;
00330    int   retries;
00331    int   reconnects;
00332    long long connecttime;
00333    struct ast_channel *chan;  
00334    struct ast_channel *pchan; 
00335 } ;
00336 
00337 struct rpt_lstat
00338 {
00339    struct   rpt_lstat *next;
00340    struct   rpt_lstat *prev;
00341    char  peer[MAXPEERSTR];
00342    char  name[MAXNODESTR];
00343    char  mode;
00344    char  outbound;
00345    char  reconnects;
00346    long long   connecttime;
00347 } ;
00348 
00349 struct rpt_tele
00350 {
00351    struct rpt_tele *next;
00352    struct rpt_tele *prev;
00353    struct rpt *rpt;
00354    struct ast_channel *chan;
00355    int   mode;
00356    struct rpt_link mylink;
00357    char param[TELEPARAMSIZE];
00358    pthread_t threadid;
00359 } ;
00360 
00361 struct function_table_tag
00362 {
00363    char action[ACTIONSIZE];
00364    int (*function)(struct rpt *myrpt, char *param, char *digitbuf, 
00365       int command_source, struct rpt_link *mylink);
00366 } ;
00367 
00368 /* Used to store the morse code patterns */
00369 
00370 struct morse_bits
00371 {       
00372    int len;
00373    int ddcomb;
00374 } ;
00375 
00376 struct telem_defaults
00377 {
00378    char name[20];
00379    char value[80];
00380 } ;
00381 
00382 
00383 static struct rpt
00384 {
00385    ast_mutex_t lock;
00386    struct ast_config *cfg;
00387    char reload;
00388 
00389    char *name;
00390    char *rxchanname;
00391    char *txchanname;
00392    char *remote;
00393 
00394    struct {
00395 
00396       const char *ourcontext;
00397       const char *ourcallerid;
00398       const char *acctcode;
00399       const char *ident;
00400       char *tonezone;
00401       char simple;
00402       const char *functions;
00403       const char *link_functions;
00404       const char *phone_functions;
00405       const char *dphone_functions;
00406       const char *nodes;
00407       int hangtime;
00408       int totime;
00409       int idtime;
00410       int tailmessagetime;
00411       int tailsquashedtime;
00412       int duplex;
00413       int politeid;
00414       char *tailmessages[500];
00415       int tailmessagemax;
00416       const char  *memory;
00417       const char  *macro;
00418       const char  *startupmacro;
00419       int iobase;
00420       char funcchar;
00421       char endchar;
00422       char  nobusyout;
00423    } p;
00424    struct rpt_link links;
00425    int unkeytocttimer;
00426    char keyed;
00427    char exttx;
00428    char localtx;
00429    char remoterx;
00430    char remotetx;
00431    char remoteon;
00432    char tounkeyed;
00433    char tonotify;
00434    char enable;
00435    char dtmfbuf[MAXDTMF];
00436    char macrobuf[MAXMACRO];
00437    char rem_dtmfbuf[MAXDTMF];
00438    char lastdtmfcommand[MAXDTMF];
00439    char cmdnode[50];
00440    struct ast_channel *rxchannel,*txchannel;
00441    struct ast_channel *pchannel,*txpchannel, *remchannel;
00442    struct rpt_tele tele;
00443    struct timeval lasttv,curtv;
00444    pthread_t rpt_call_thread,rpt_thread;
00445    time_t dtmf_time,rem_dtmf_time,dtmf_time_rem;
00446    int tailtimer,totimer,idtimer,txconf,conf,callmode,cidx,scantimer,tmsgtimer,skedtimer;
00447    int mustid,tailid;
00448    int tailevent;
00449    int telemrefcount;
00450    int dtmfidx,rem_dtmfidx;
00451    int dailytxtime,dailykerchunks,totalkerchunks,dailykeyups,totalkeyups,timeouts;
00452    int totalexecdcommands, dailyexecdcommands;
00453    long  retxtimer;
00454    long long totaltxtime;
00455    char mydtmf;
00456    char exten[AST_MAX_EXTENSION];
00457    char freq[MAXREMSTR],rxpl[MAXREMSTR],txpl[MAXREMSTR];
00458    char offset;
00459    char powerlevel;
00460    char txplon;
00461    char rxplon;
00462    char remmode;
00463    char tunerequest;
00464    char hfscanmode;
00465    int hfscanstatus;
00466    char lastlinknode[MAXNODESTR];
00467    char stopgen;
00468    char patchfarenddisconnect;
00469    char patchnoct;
00470    char patchquiet;
00471    char patchcontext[MAXPATCHCONTEXT];
00472    int patchdialtime;
00473    int macro_longest;
00474    int phone_longestfunc;
00475    int dphone_longestfunc;
00476    int link_longestfunc;
00477    int longestfunc;
00478    int longestnode;
00479    int threadrestarts;     
00480    int tailmessagen;
00481    time_t disgorgetime;
00482    time_t lastthreadrestarttime;
00483    long  macrotimer;
00484    char  lastnodewhichkeyedusup[MAXNODESTR];
00485 #ifdef   __RPT_NOTCH
00486    struct rptfilter
00487    {
00488       char  desc[100];
00489       float x0;
00490       float x1;
00491       float x2;
00492       float y0;
00493       float y1;
00494       float y2;
00495       float gain;
00496       float const0;
00497       float const1;
00498       float const2;
00499    } filters[MAXFILTERS];
00500 #endif
00501 #ifdef   _MDC_DECODE_H_
00502    mdc_decoder_t *mdc;
00503    unsigned short lastunit;
00504 #endif
00505 } rpt_vars[MAXRPTS]; 
00506 
00507 
00508 #ifdef   APP_RPT_LOCK_DEBUG
00509 
00510 #warning COMPILING WITH LOCK-DEBUGGING ENABLED!!
00511 
00512 #define  MAXLOCKTHREAD 100
00513 
00514 #define rpt_mutex_lock(x) _rpt_mutex_lock(x,myrpt,__LINE__)
00515 #define rpt_mutex_unlock(x) _rpt_mutex_unlock(x,myrpt,__LINE__)
00516 
00517 struct lockthread
00518 {
00519    pthread_t id;
00520    int lockcount;
00521    int lastlock;
00522    int lastunlock;
00523 } lockthreads[MAXLOCKTHREAD];
00524 
00525 
00526 struct by_lightning
00527 {
00528    int line;
00529    struct timeval tv;
00530    struct rpt *rpt;
00531    struct lockthread lockthread;
00532 } lock_ring[32];
00533 
00534 
00535 int lock_ring_index = 0;
00536 
00537 AST_MUTEX_DEFINE_STATIC(locklock);
00538 
00539 static struct lockthread *get_lockthread(pthread_t id)
00540 {
00541 int   i;
00542 
00543    for(i = 0; i < MAXLOCKTHREAD; i++)
00544    {
00545       if (lockthreads[i].id == id) return(&lockthreads[i]);
00546    }
00547    return(NULL);
00548 }
00549 
00550 static struct lockthread *put_lockthread(pthread_t id)
00551 {
00552 int   i;
00553 
00554    for(i = 0; i < MAXLOCKTHREAD; i++)
00555    {
00556       if (lockthreads[i].id == id)
00557          return(&lockthreads[i]);
00558    }
00559    for(i = 0; i < MAXLOCKTHREAD; i++)
00560    {
00561       if (!lockthreads[i].id)
00562       {
00563          lockthreads[i].lockcount = 0;
00564          lockthreads[i].lastlock = 0;
00565          lockthreads[i].lastunlock = 0;
00566          lockthreads[i].id = id;
00567          return(&lockthreads[i]);
00568       }
00569    }
00570    return(NULL);
00571 }
00572 
00573 
00574 static void rpt_mutex_spew(void)
00575 {
00576    struct by_lightning lock_ring_copy[32];
00577    int lock_ring_index_copy;
00578    int i,j;
00579    long long diff;
00580    char a[100];
00581    struct timeval lasttv;
00582 
00583    ast_mutex_lock(&locklock);
00584    memcpy(&lock_ring_copy, &lock_ring, sizeof(lock_ring_copy));
00585    lock_ring_index_copy = lock_ring_index;
00586    ast_mutex_unlock(&locklock);
00587 
00588    lasttv.tv_sec = lasttv.tv_usec = 0;
00589    for(i = 0 ; i < 32 ; i++)
00590    {
00591       j = (i + lock_ring_index_copy) % 32;
00592       strftime(a,sizeof(a) - 1,"%m/%d/%Y %H:%M:%S",
00593          localtime(&lock_ring_copy[j].tv.tv_sec));
00594       diff = 0;
00595       if(lasttv.tv_sec)
00596       {
00597          diff = (lock_ring_copy[j].tv.tv_sec - lasttv.tv_sec)
00598             * 1000000;
00599          diff += (lock_ring_copy[j].tv.tv_usec - lasttv.tv_usec);
00600       }
00601       lasttv.tv_sec = lock_ring_copy[j].tv.tv_sec;
00602       lasttv.tv_usec = lock_ring_copy[j].tv.tv_usec;
00603       if (!lock_ring_copy[j].tv.tv_sec) continue;
00604       if (lock_ring_copy[j].line < 0)
00605       {
00606          ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] UNLOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
00607             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);
00608       }
00609       else
00610       {
00611          ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] LOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
00612             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);
00613       }
00614    }
00615 }
00616 
00617 
00618 static void _rpt_mutex_lock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
00619 {
00620 struct lockthread *t;
00621 pthread_t id;
00622 
00623    id = pthread_self();
00624    ast_mutex_lock(&locklock);
00625    t = put_lockthread(id);
00626    if (!t)
00627    {
00628       ast_mutex_unlock(&locklock);
00629       return;
00630    }
00631    if (t->lockcount)
00632    {
00633       int lastline = t->lastlock;
00634       ast_mutex_unlock(&locklock);
00635       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);
00636       rpt_mutex_spew();
00637       return;
00638    }
00639    t->lastlock = line;
00640    t->lockcount = 1;
00641    gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
00642    lock_ring[lock_ring_index].rpt = myrpt;
00643    memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
00644    lock_ring[lock_ring_index++].line = line;
00645    if(lock_ring_index == 32)
00646       lock_ring_index = 0;
00647    ast_mutex_unlock(&locklock);
00648    ast_mutex_lock(lockp);
00649 }
00650 
00651 
00652 static void _rpt_mutex_unlock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
00653 {
00654 struct lockthread *t;
00655 pthread_t id;
00656 
00657    id = pthread_self();
00658    ast_mutex_lock(&locklock);
00659    t = put_lockthread(id);
00660    if (!t)
00661    {
00662       ast_mutex_unlock(&locklock);
00663       return;
00664    }
00665    if (!t->lockcount)
00666    {
00667       int lastline = t->lastunlock;
00668       ast_mutex_unlock(&locklock);
00669       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);
00670       rpt_mutex_spew();
00671       return;
00672    }
00673    t->lastunlock = line;
00674    t->lockcount = 0;
00675    gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
00676    lock_ring[lock_ring_index].rpt = myrpt;
00677    memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
00678    lock_ring[lock_ring_index++].line = -line;
00679    if(lock_ring_index == 32)
00680       lock_ring_index = 0;
00681    ast_mutex_unlock(&locklock);
00682    ast_mutex_unlock(lockp);
00683 }
00684 
00685 #else  /* APP_RPT_LOCK_DEBUG */
00686 
00687 #define rpt_mutex_lock(x) ast_mutex_lock(x)
00688 #define rpt_mutex_unlock(x) ast_mutex_unlock(x)
00689 
00690 #endif  /* APP_RPT_LOCK_DEBUG */
00691 
00692 /*
00693 * CLI extensions
00694 */
00695 
00696 /* Debug mode */
00697 static int rpt_do_debug(int fd, int argc, char *argv[]);
00698 static int rpt_do_dump(int fd, int argc, char *argv[]);
00699 static int rpt_do_stats(int fd, int argc, char *argv[]);
00700 static int rpt_do_lstats(int fd, int argc, char *argv[]);
00701 static int rpt_do_reload(int fd, int argc, char *argv[]);
00702 static int rpt_do_restart(int fd, int argc, char *argv[]);
00703 
00704 static char debug_usage[] =
00705 "Usage: rpt debug level {0-7}\n"
00706 "       Enables debug messages in app_rpt\n";
00707 
00708 static char dump_usage[] =
00709 "Usage: rpt dump <nodename>\n"
00710 "       Dumps struct debug info to log\n";
00711 
00712 static char dump_stats[] =
00713 "Usage: rpt stats <nodename>\n"
00714 "       Dumps node statistics to console\n";
00715 
00716 static char dump_lstats[] =
00717 "Usage: rpt lstats <nodename>\n"
00718 "       Dumps link statistics to console\n";
00719 
00720 static char reload_usage[] =
00721 "Usage: rpt reload\n"
00722 "       Reloads app_rpt running config parameters\n";
00723 
00724 static char restart_usage[] =
00725 "Usage: rpt restart\n"
00726 "       Restarts app_rpt\n";
00727 
00728 static struct ast_cli_entry cli_rpt[] = {
00729    { { "rpt", "debug", "level" },
00730    rpt_do_debug, "Enable app_rpt debugging",
00731    debug_usage },
00732 
00733         { { "rpt", "dump" },
00734    rpt_do_dump, "Dump app_rpt structs for debugging",
00735    dump_usage },
00736 
00737         { { "rpt", "stats" },
00738    rpt_do_stats, "Dump node statistics",
00739    dump_stats },
00740         { { "rpt", "lstats" },
00741    rpt_do_lstats, "Dump link statistics",
00742    dump_lstats },
00743 
00744         { { "rpt", "reload" },
00745    rpt_do_reload, "Reload app_rpt config",
00746    reload_usage },
00747 
00748         { { "rpt", "restart" },
00749    rpt_do_restart, "Restart app_rpt",
00750    restart_usage },
00751 };
00752 
00753 /*
00754 * Telemetry defaults
00755 */
00756 
00757 
00758 static struct telem_defaults tele_defs[] = {
00759    {"ct1","|t(350,0,100,3072)(500,0,100,3072)(660,0,100,3072)"},
00760    {"ct2","|t(660,880,150,3072)"},
00761    {"ct3","|t(440,0,150,3072)"},
00762    {"ct4","|t(550,0,150,3072)"},
00763    {"ct5","|t(660,0,150,3072)"},
00764    {"ct6","|t(880,0,150,3072)"},
00765    {"ct7","|t(660,440,150,3072)"},
00766    {"ct8","|t(700,1100,150,3072)"},
00767    {"remotemon","|t(1600,0,75,2048)"},
00768    {"remotetx","|t(2000,0,75,2048)(0,0,75,0)(1600,0,75,2048)"},
00769    {"cmdmode","|t(900,904,200,2048)"},
00770    {"functcomplete","|t(1000,0,100,2048)(0,0,100,0)(1000,0,100,2048)"}
00771 } ;
00772 
00773 /*
00774 * Forward decl's - these suppress compiler warnings when funcs coded further down the file than their invocation
00775 */
00776 
00777 static int setrbi(struct rpt *myrpt);
00778 
00779 
00780 
00781 /*
00782 * Define function protos for function table here
00783 */
00784 
00785 static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
00786 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
00787 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
00788 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
00789 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
00790 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
00791 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
00792 /*
00793 * Function table
00794 */
00795 
00796 static struct function_table_tag function_table[] = {
00797    {"cop", function_cop},
00798    {"autopatchup", function_autopatchup},
00799    {"autopatchdn", function_autopatchdn},
00800    {"ilink", function_ilink},
00801    {"status", function_status},
00802    {"remote", function_remote},
00803    {"macro", function_macro}
00804 } ;
00805 
00806 /*
00807 * Break up a delimited string into a table of substrings
00808 *
00809 * str - delimited string ( will be modified )
00810 * strp- list of pointers to substrings (this is built by this function), NULL will be placed at end of list
00811 * limit- maximum number of substrings to process
00812 */
00813    
00814 
00815 
00816 static int finddelim(char *str, char *strp[], int limit)
00817 {
00818 int     i,l,inquo;
00819 
00820         inquo = 0;
00821         i = 0;
00822         strp[i++] = str;
00823         if (!*str)
00824            {
00825                 strp[0] = 0;
00826                 return(0);
00827            }
00828         for(l = 0; *str && (l < limit) ; str++)
00829            {
00830                 if (*str == QUOTECHR)
00831                    {
00832                         if (inquo)
00833                            {
00834                                 *str = 0;
00835                                 inquo = 0;
00836                            }
00837                         else
00838                            {
00839                                 strp[i - 1] = str + 1;
00840                                 inquo = 1;
00841                            }
00842       }
00843                 if ((*str == DELIMCHR) && (!inquo))
00844                 {
00845                         *str = 0;
00846          l++;
00847                         strp[i++] = str + 1;
00848                 }
00849            }
00850         strp[i] = 0;
00851         return(i);
00852 
00853 }
00854 
00855 /*
00856 * Match a keyword in a list, and return index of string plus 1 if there was a match,
00857 * else return 0. If param is passed in non-null, then it will be set to the first character past the match
00858 */
00859 
00860 static int matchkeyword(char *string, char **param, char *keywords[])
00861 {
00862 int   i,ls;
00863    for( i = 0 ; keywords[i] ; i++){
00864       ls = strlen(keywords[i]);
00865       if(!ls){
00866          *param = NULL;
00867          return 0;
00868       }
00869       if(!strncmp(string, keywords[i], ls)){
00870          if(param)
00871             *param = string + ls;
00872          return i + 1; 
00873       }
00874    }
00875    param = NULL;
00876    return 0;
00877 }
00878 
00879 /*
00880 * Skip characters in string which are in charlist, and return a pointer to the
00881 * first non-matching character
00882 */
00883 
00884 static char *skipchars(char *string, char *charlist)
00885 {
00886 int i;   
00887    while(*string){
00888       for(i = 0; charlist[i] ; i++){
00889          if(*string == charlist[i]){
00890             string++;
00891             break;
00892          }
00893       }
00894       if(!charlist[i])
00895          return string;
00896    }
00897    return string;
00898 }  
00899                
00900 
00901 
00902 static int myatoi(const char *str)
00903 {
00904 int   ret;
00905 
00906    if (str == NULL) return -1;
00907    /* leave this %i alone, non-base-10 input is useful here */
00908    if (sscanf(str,"%i",&ret) != 1) return -1;
00909    return ret;
00910 }
00911 
00912 
00913 #ifdef   __RPT_NOTCH
00914 
00915 /* rpt filter routine */
00916 static void rpt_filter(struct rpt *myrpt, volatile short *buf, int len)
00917 {
00918 int   i,j;
00919 struct   rptfilter *f;
00920 
00921    for(i = 0; i < len; i++)
00922    {
00923       for(j = 0; j < MAXFILTERS; j++)
00924       {
00925          f = &myrpt->filters[j];
00926          if (!*f->desc) continue;
00927          f->x0 = f->x1; f->x1 = f->x2;
00928               f->x2 = ((float)buf[i]) / f->gain;
00929               f->y0 = f->y1; f->y1 = f->y2;
00930               f->y2 =   (f->x0 + f->x2) +   f->const0 * f->x1
00931                            + (f->const1 * f->y0) + (f->const2 * f->y1);
00932          buf[i] = (short)f->y2;
00933       }
00934    }
00935 }
00936 
00937 #endif
00938 
00939 /* Retrieve an int from a config file */
00940                                                                                 
00941 static int retrieve_astcfgint(struct rpt *myrpt,char *category, char *name, int min, int max, int defl)
00942 {
00943         const char *var;
00944         int ret;
00945                                                                                 
00946         var = ast_variable_retrieve(myrpt->cfg, category, name);
00947         if(var){
00948                 ret = myatoi(var);
00949                 if(ret < min)
00950                         ret = min;
00951                 if(ret > max)
00952                         ret = max;
00953         }
00954         else
00955                 ret = defl;
00956         return ret;
00957 }
00958 
00959 
00960 static void load_rpt_vars(int n,int init)
00961 {
00962 char *this;
00963    const char *val;
00964 int   j,longestnode;
00965 struct ast_variable *vp;
00966 struct ast_config *cfg;
00967 #ifdef   __RPT_NOTCH
00968 int   i;
00969 char *strs[100];
00970 #endif
00971 
00972    if (option_verbose > 2)
00973       ast_verbose(VERBOSE_PREFIX_3 "%s config for repeater %s\n",
00974          (init) ? "Loading initial" : "Re-Loading",rpt_vars[n].name);
00975    ast_mutex_lock(&rpt_vars[n].lock);
00976    if (rpt_vars[n].cfg) ast_config_destroy(rpt_vars[n].cfg);
00977    cfg = ast_config_load("rpt.conf");
00978    if (!cfg) {
00979       ast_mutex_unlock(&rpt_vars[n].lock);
00980       ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf.  Radio Repeater disabled.\n");
00981       pthread_exit(NULL);
00982    }
00983    rpt_vars[n].cfg = cfg; 
00984    this = rpt_vars[n].name;
00985    memset(&rpt_vars[n].p,0,sizeof(rpt_vars[n].p));
00986    if (init)
00987    {
00988       char *cp;
00989       int savearea = (char *)&rpt_vars[n].p - (char *)&rpt_vars[n];
00990 
00991       cp = (char *) &rpt_vars[n].p;
00992       memset(cp + sizeof(rpt_vars[n].p),0,
00993          sizeof(rpt_vars[n]) - (sizeof(rpt_vars[n].p) + savearea));
00994       rpt_vars[n].tele.next = &rpt_vars[n].tele;
00995       rpt_vars[n].tele.prev = &rpt_vars[n].tele;
00996       rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
00997       rpt_vars[n].tailmessagen = 0;
00998    }
00999 #ifdef   __RPT_NOTCH
01000    /* zot out filters stuff */
01001    memset(&rpt_vars[n].filters,0,sizeof(rpt_vars[n].filters));
01002 #endif
01003    val = ast_variable_retrieve(cfg,this,"context");
01004    if (val) rpt_vars[n].p.ourcontext = val;
01005    else rpt_vars[n].p.ourcontext = this;
01006    val = ast_variable_retrieve(cfg,this,"callerid");
01007    if (val) rpt_vars[n].p.ourcallerid = val;
01008    val = ast_variable_retrieve(cfg,this,"accountcode");
01009    if (val) rpt_vars[n].p.acctcode = val;
01010    val = ast_variable_retrieve(cfg,this,"idrecording");
01011    if (val) rpt_vars[n].p.ident = val;
01012    val = ast_variable_retrieve(cfg,this,"hangtime");
01013    if (val) rpt_vars[n].p.hangtime = atoi(val);
01014       else rpt_vars[n].p.hangtime = HANGTIME;
01015    val = ast_variable_retrieve(cfg,this,"totime");
01016    if (val) rpt_vars[n].p.totime = atoi(val);
01017       else rpt_vars[n].p.totime = TOTIME;
01018    rpt_vars[n].p.tailmessagetime = retrieve_astcfgint(&rpt_vars[n],this, "tailmessagetime", 0, 2400000, 0);    
01019    rpt_vars[n].p.tailsquashedtime = retrieve_astcfgint(&rpt_vars[n],this, "tailsquashedtime", 0, 2400000, 0);     
01020    rpt_vars[n].p.duplex = retrieve_astcfgint(&rpt_vars[n],this,"duplex",0,4,2);
01021    rpt_vars[n].p.idtime = retrieve_astcfgint(&rpt_vars[n],this, "idtime", 60000, 2400000, IDTIME); /* Enforce a min max */
01022    rpt_vars[n].p.politeid = retrieve_astcfgint(&rpt_vars[n],this, "politeid", 30000, 300000, POLITEID); /* Enforce a min max */
01023    val = ast_variable_retrieve(cfg,this,"tonezone");
01024    if (val) rpt_vars[n].p.tonezone = ast_strdupa(val);
01025    rpt_vars[n].p.tailmessages[0] = 0;
01026    rpt_vars[n].p.tailmessagemax = 0;
01027    val = ast_variable_retrieve(cfg,this,"tailmessagelist");
01028    if (val) rpt_vars[n].p.tailmessagemax = finddelim(ast_strdupa(val), rpt_vars[n].p.tailmessages, 500);
01029    val = ast_variable_retrieve(cfg,this,"memory");
01030    if (!val) val = MEMORY;
01031    rpt_vars[n].p.memory = val;
01032    val = ast_variable_retrieve(cfg,this,"macro");
01033    if (!val) val = MACRO;
01034    rpt_vars[n].p.macro = val;
01035    val = ast_variable_retrieve(cfg,this,"startup_macro");
01036    if (val) rpt_vars[n].p.startupmacro = val;
01037    val = ast_variable_retrieve(cfg,this,"iobase");
01038    /* do not use atoi() here, we need to be able to have
01039       the input specified in hex or decimal so we use
01040       sscanf with a %i */
01041    if ((!val) || (sscanf(val,"%i",&rpt_vars[n].p.iobase) != 1))
01042    rpt_vars[n].p.iobase = DEFAULT_IOBASE;
01043    val = ast_variable_retrieve(cfg,this,"functions");
01044    if (!val)
01045       {
01046          val = FUNCTIONS;
01047          rpt_vars[n].p.simple = 1;
01048       } 
01049    rpt_vars[n].p.functions = val;
01050    val =  ast_variable_retrieve(cfg,this,"link_functions");
01051    if (val) rpt_vars[n].p.link_functions = val;
01052    else 
01053       rpt_vars[n].p.link_functions = rpt_vars[n].p.functions;
01054    val = ast_variable_retrieve(cfg,this,"phone_functions");
01055    if (val) rpt_vars[n].p.phone_functions = val;
01056    val = ast_variable_retrieve(cfg,this,"dphone_functions");
01057    if (val) rpt_vars[n].p.dphone_functions = val;
01058    val = ast_variable_retrieve(cfg,this,"funcchar");
01059    if (!val) rpt_vars[n].p.funcchar = FUNCCHAR; else 
01060       rpt_vars[n].p.funcchar = *val;      
01061    val = ast_variable_retrieve(cfg,this,"endchar");
01062    if (!val) rpt_vars[n].p.endchar = ENDCHAR; else 
01063       rpt_vars[n].p.endchar = *val;    
01064    val = ast_variable_retrieve(cfg,this,"nobusyout");
01065    if (val) rpt_vars[n].p.nobusyout = ast_true(val);
01066    val = ast_variable_retrieve(cfg,this,"nodes");
01067    if (!val) val = NODES;
01068    rpt_vars[n].p.nodes = val;
01069 #ifdef   __RPT_NOTCH
01070    val = ast_variable_retrieve(cfg,this,"rxnotch");
01071    if (val) {
01072       i = finddelim(ast_strdupa(val),strs,MAXFILTERS * 2);
01073       i &= ~1; /* force an even number, rounded down */
01074       if (i >= 2) for(j = 0; j < i; j += 2)
01075       {
01076          rpt_mknotch(atof(strs[j]),atof(strs[j + 1]),
01077            &rpt_vars[n].filters[j >> 1].gain,
01078              &rpt_vars[n].filters[j >> 1].const0,
01079             &rpt_vars[n].filters[j >> 1].const1,
01080                 &rpt_vars[n].filters[j >> 1].const2);
01081          sprintf(rpt_vars[n].filters[j >> 1].desc,"%s Hz, BW = %s",
01082             strs[j],strs[j + 1]);
01083       }
01084 
01085    }
01086 #endif
01087    longestnode = 0;
01088 
01089    vp = ast_variable_browse(cfg, rpt_vars[n].p.nodes);
01090       
01091    while(vp){
01092       j = strlen(vp->name);
01093       if (j > longestnode)
01094          longestnode = j;
01095       vp = vp->next;
01096    }
01097 
01098    rpt_vars[n].longestnode = longestnode;
01099       
01100    /*
01101    * For this repeater, Determine the length of the longest function 
01102    */
01103    rpt_vars[n].longestfunc = 0;
01104    vp = ast_variable_browse(cfg, rpt_vars[n].p.functions);
01105    while(vp){
01106       j = strlen(vp->name);
01107       if (j > rpt_vars[n].longestfunc)
01108          rpt_vars[n].longestfunc = j;
01109       vp = vp->next;
01110    }
01111    /*
01112    * For this repeater, Determine the length of the longest function 
01113    */
01114    rpt_vars[n].link_longestfunc = 0;
01115    vp = ast_variable_browse(cfg, rpt_vars[n].p.link_functions);
01116    while(vp){
01117       j = strlen(vp->name);
01118       if (j > rpt_vars[n].link_longestfunc)
01119          rpt_vars[n].link_longestfunc = j;
01120       vp = vp->next;
01121    }
01122    rpt_vars[n].phone_longestfunc = 0;
01123    if (rpt_vars[n].p.phone_functions)
01124    {
01125       vp = ast_variable_browse(cfg, rpt_vars[n].p.phone_functions);
01126       while(vp){
01127          j = strlen(vp->name);
01128          if (j > rpt_vars[n].phone_longestfunc)
01129             rpt_vars[n].phone_longestfunc = j;
01130          vp = vp->next;
01131       }
01132    }
01133    rpt_vars[n].dphone_longestfunc = 0;
01134    if (rpt_vars[n].p.dphone_functions)
01135    {
01136       vp = ast_variable_browse(cfg, rpt_vars[n].p.dphone_functions);
01137       while(vp){
01138          j = strlen(vp->name);
01139          if (j > rpt_vars[n].dphone_longestfunc)
01140             rpt_vars[n].dphone_longestfunc = j;
01141          vp = vp->next;
01142       }
01143    }
01144    rpt_vars[n].macro_longest = 1;
01145    vp = ast_variable_browse(cfg, rpt_vars[n].p.macro);
01146    while(vp){
01147       j = strlen(vp->name);
01148       if (j > rpt_vars[n].macro_longest)
01149          rpt_vars[n].macro_longest = j;
01150       vp = vp->next;
01151    }
01152    ast_mutex_unlock(&rpt_vars[n].lock);
01153 }
01154 
01155 /*
01156 * Enable or disable debug output at a given level at the console
01157 */
01158                                                                                                                                  
01159 static int rpt_do_debug(int fd, int argc, char *argv[])
01160 {
01161    int newlevel;
01162 
01163         if (argc != 4)
01164                 return RESULT_SHOWUSAGE;
01165         newlevel = myatoi(argv[3]);
01166         if((newlevel < 0) || (newlevel > 7))
01167                 return RESULT_SHOWUSAGE;
01168         if(newlevel)
01169                 ast_cli(fd, "app_rpt Debugging enabled, previous level: %d, new level: %d\n", debug, newlevel);
01170         else
01171                 ast_cli(fd, "app_rpt Debugging disabled\n");
01172 
01173         debug = newlevel;                                                                                                                          
01174         return RESULT_SUCCESS;
01175 }
01176 
01177 /*
01178 * Dump rpt struct debugging onto console
01179 */
01180                                                                                                                                  
01181 static int rpt_do_dump(int fd, int argc, char *argv[])
01182 {
01183    int i;
01184 
01185         if (argc != 3)
01186                 return RESULT_SHOWUSAGE;
01187 
01188    for(i = 0; i < nrpts; i++)
01189    {
01190       if (!strcmp(argv[2],rpt_vars[i].name))
01191       {
01192          rpt_vars[i].disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
01193               ast_cli(fd, "app_rpt struct dump requested for node %s\n",argv[2]);
01194               return RESULT_SUCCESS;
01195       }
01196    }
01197    return RESULT_FAILURE;
01198 }
01199 
01200 /*
01201 * Dump statistics onto console
01202 */
01203 
01204 static int rpt_do_stats(int fd, int argc, char *argv[])
01205 {
01206    int i,j;
01207    int dailytxtime, dailykerchunks;
01208    int totalkerchunks, dailykeyups, totalkeyups, timeouts;
01209    int totalexecdcommands, dailyexecdcommands, hours, minutes, seconds;
01210    long long totaltxtime;
01211    struct   rpt_link *l;
01212    char *listoflinks[MAX_STAT_LINKS];  
01213    char *lastnodewhichkeyedusup, *lastdtmfcommand;
01214    char *tot_state, *ider_state, *patch_state;
01215    char *reverse_patch_state, *enable_state, *input_signal, *called_number;
01216    struct rpt *myrpt;
01217 
01218    static char *not_applicable = "N/A";
01219 
01220    if(argc != 3)
01221       return RESULT_SHOWUSAGE;
01222 
01223    for(i = 0 ; i <= MAX_STAT_LINKS; i++)
01224       listoflinks[i] = NULL;
01225 
01226    tot_state = ider_state = 
01227    patch_state = reverse_patch_state = 
01228    input_signal = called_number = 
01229    lastdtmfcommand = not_applicable;
01230 
01231    for(i = 0; i < nrpts; i++)
01232    {
01233       if (!strcmp(argv[2],rpt_vars[i].name)){
01234          /* Make a copy of all stat variables while locked */
01235          myrpt = &rpt_vars[i];
01236          rpt_mutex_lock(&myrpt->lock); /* LOCK */
01237 
01238          dailytxtime = myrpt->dailytxtime;
01239          totaltxtime = myrpt->totaltxtime;
01240          dailykeyups = myrpt->dailykeyups;
01241          totalkeyups = myrpt->totalkeyups;
01242          dailykerchunks = myrpt->dailykerchunks;
01243          totalkerchunks = myrpt->totalkerchunks;
01244          dailyexecdcommands = myrpt->dailyexecdcommands;
01245          totalexecdcommands = myrpt->totalexecdcommands;
01246          timeouts = myrpt->timeouts;
01247 
01248          /* Traverse the list of connected nodes */
01249          reverse_patch_state = "DOWN";
01250          j = 0;
01251          l = myrpt->links.next;
01252          while(l != &myrpt->links){
01253             if (l->name[0] == '0'){ /* Skip '0' nodes */
01254                reverse_patch_state = "UP";
01255                l = l->next;
01256                continue;
01257             }
01258             listoflinks[j] = ast_strdupa(l->name);
01259             if(listoflinks[j])
01260                j++;
01261             l = l->next;
01262          }
01263 
01264          lastnodewhichkeyedusup = ast_strdupa(myrpt->lastnodewhichkeyedusup);       
01265          if((!lastnodewhichkeyedusup) || (!strlen(lastnodewhichkeyedusup)))
01266             lastnodewhichkeyedusup = not_applicable;
01267 
01268          if(myrpt->keyed)
01269             input_signal = "YES";
01270          else
01271             input_signal = "NO";
01272 
01273          if(myrpt->enable)
01274             enable_state = "YES";
01275          else
01276             enable_state = "NO";
01277 
01278          if(!myrpt->totimer)
01279             tot_state = "TIMED OUT!";
01280          else if(myrpt->totimer != myrpt->p.totime)
01281             tot_state = "ARMED";
01282          else
01283             tot_state = "RESET";
01284 
01285          if(myrpt->tailid)
01286             ider_state = "QUEUED IN TAIL";
01287          else if(myrpt->mustid)
01288             ider_state = "QUEUED FOR CLEANUP";
01289          else
01290             ider_state = "CLEAN";
01291 
01292          switch(myrpt->callmode){
01293             case 1:
01294                patch_state = "DIALING";
01295                break;
01296             case 2:
01297                patch_state = "CONNECTING";
01298                break;
01299             case 3:
01300                patch_state = "UP";
01301                break;
01302 
01303             case 4:
01304                patch_state = "CALL FAILED";
01305                break;
01306 
01307             default:
01308                patch_state = "DOWN";
01309          }
01310 
01311          if(strlen(myrpt->exten)){
01312             called_number = ast_strdupa(myrpt->exten);
01313             if(!called_number)
01314                called_number = not_applicable;
01315          }
01316 
01317          if(strlen(myrpt->lastdtmfcommand)){
01318             lastdtmfcommand = ast_strdupa(myrpt->lastdtmfcommand);
01319             if(!lastdtmfcommand)
01320                lastdtmfcommand = not_applicable;
01321          }
01322 
01323          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
01324 
01325          ast_cli(fd, "************************ NODE %s STATISTICS *************************\n\n", myrpt->name);
01326          ast_cli(fd, "Signal on input..................................: %s\n", input_signal);
01327          ast_cli(fd, "Transmitter enabled..............................: %s\n", enable_state);
01328          ast_cli(fd, "Time out timer state.............................: %s\n", tot_state);
01329          ast_cli(fd, "Time outs since system initialization............: %d\n", timeouts);
01330          ast_cli(fd, "Identifier state.................................: %s\n", ider_state);
01331          ast_cli(fd, "Kerchunks today..................................: %d\n", dailykerchunks);
01332          ast_cli(fd, "Kerchunks since system initialization............: %d\n", totalkerchunks);
01333          ast_cli(fd, "Keyups today.....................................: %d\n", dailykeyups);
01334          ast_cli(fd, "Keyups since system initialization...............: %d\n", totalkeyups);
01335          ast_cli(fd, "DTMF commands today..............................: %d\n", dailyexecdcommands);
01336          ast_cli(fd, "DTMF commands since system initialization........: %d\n", totalexecdcommands);
01337          ast_cli(fd, "Last DTMF command executed.......................: %s\n", lastdtmfcommand);
01338 
01339          hours = dailytxtime/3600000;
01340          dailytxtime %= 3600000;
01341          minutes = dailytxtime/60000;
01342          dailytxtime %= 60000;
01343          seconds = dailytxtime/1000;
01344          dailytxtime %= 1000;
01345 
01346          ast_cli(fd, "TX time today ...................................: %02d:%02d:%02d.%d\n",
01347             hours, minutes, seconds, dailytxtime);
01348 
01349          hours = (int) totaltxtime/3600000;
01350          totaltxtime %= 3600000;
01351          minutes = (int) totaltxtime/60000;
01352          totaltxtime %= 60000;
01353          seconds = (int)  totaltxtime/1000;
01354          totaltxtime %= 1000;
01355 
01356          ast_cli(fd, "TX time since system initialization..............: %02d:%02d:%02d.%d\n",
01357              hours, minutes, seconds, (int) totaltxtime);
01358          ast_cli(fd, "Nodes currently connected to us..................: ");
01359          for(j = 0 ;; j++){
01360             if(!listoflinks[j]){
01361                if(!j){
01362                   ast_cli(fd,"<NONE>");
01363                }
01364                break;
01365             }
01366             ast_cli(fd, "%s", listoflinks[j]);
01367             if(j % 4 == 3){
01368                ast_cli(fd, "\n");
01369                ast_cli(fd, "                                                 : ");
01370             }
01371             else{
01372                if(listoflinks[j + 1])
01373                   ast_cli(fd, ", ");
01374             }
01375          }
01376          ast_cli(fd,"\n");
01377 
01378          ast_cli(fd, "Last node which transmitted to us................: %s\n", lastnodewhichkeyedusup);
01379          ast_cli(fd, "Autopatch state..................................: %s\n", patch_state);
01380          ast_cli(fd, "Autopatch called number..........................: %s\n", called_number);
01381          ast_cli(fd, "Reverse patch/IAXRPT connected...................: %s\n\n", reverse_patch_state);
01382 
01383               return RESULT_SUCCESS;
01384       }
01385    }
01386    return RESULT_FAILURE;
01387 }
01388 
01389 /*
01390 * Link stats function
01391 */
01392 
01393 static int rpt_do_lstats(int fd, int argc, char *argv[])
01394 {
01395    int i,j;
01396    struct rpt *myrpt;
01397    struct rpt_link *l;
01398    struct rpt_lstat *s,*t;
01399    struct rpt_lstat s_head;
01400    if(argc != 3)
01401       return RESULT_SHOWUSAGE;
01402 
01403    s = NULL;
01404    s_head.next = &s_head;
01405    s_head.prev = &s_head;
01406 
01407    for(i = 0; i < nrpts; i++)
01408    {
01409       if (!strcmp(argv[2],rpt_vars[i].name)){
01410          /* Make a copy of all stat variables while locked */
01411          myrpt = &rpt_vars[i];
01412          rpt_mutex_lock(&myrpt->lock); /* LOCK */
01413          /* Traverse the list of connected nodes */
01414          j = 0;
01415          l = myrpt->links.next;
01416          while(l != &myrpt->links){
01417             if (l->name[0] == '0'){ /* Skip '0' nodes */
01418                l = l->next;
01419                continue;
01420             }
01421             if((s = (struct rpt_lstat *) malloc(sizeof(struct rpt_lstat))) == NULL){
01422                ast_log(LOG_ERROR, "Malloc failed in rpt_do_lstats\n");
01423                rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
01424                return RESULT_FAILURE;
01425             }
01426             memset(s, 0, sizeof(struct rpt_lstat));
01427             ast_copy_string(s->name, l->name, MAXREMSTR);
01428             pbx_substitute_variables_helper(l->chan, "${IAXPEER(CURRENTCHANNEL)}", s->peer, MAXPEERSTR - 1);
01429             s->mode = l->mode;
01430             s->outbound = l->outbound;
01431             s->reconnects = l->reconnects;
01432             s->connecttime = l->connecttime;
01433             insque((struct qelem *) s, (struct qelem *) s_head.next);
01434             l = l->next;
01435          }
01436          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
01437          ast_cli(fd, "NODE      PEER                RECONNECTS  DIRECTION  CONNECT TIME\n");
01438          ast_cli(fd, "----      ----                ----------  ---------  ------------\n");
01439 
01440          for(s = s_head.next; s != &s_head; s = s->next){
01441             int hours, minutes, seconds;
01442             long long connecttime = s->connecttime;
01443             char conntime[31];
01444             hours = (int) connecttime/3600000;
01445             connecttime %= 3600000;
01446             minutes = (int) connecttime/60000;
01447             connecttime %= 60000;
01448             seconds = (int)  connecttime/1000;
01449             connecttime %= 1000;
01450             snprintf(conntime, 30, "%02d:%02d:%02d.%d",
01451                hours, minutes, seconds, (int) connecttime);
01452             conntime[30] = 0;
01453             ast_cli(fd, "%-10s%-20s%-12d%-11s%-30s\n",
01454                s->name, s->peer, s->reconnects, (s->outbound)? "OUT":"IN", conntime);
01455          }  
01456          /* destroy our local link queue */
01457          s = s_head.next;
01458          while(s != &s_head){
01459             t = s;
01460             s = s->next;
01461             remque((struct qelem *)t);
01462             free(t);
01463          }        
01464          return RESULT_SUCCESS;
01465       }
01466    }
01467    return RESULT_FAILURE;
01468 }
01469 
01470 /*
01471 * reload vars 
01472 */
01473                                                                                                                                  
01474 static int rpt_do_reload(int fd, int argc, char *argv[])
01475 {
01476 int   n;
01477 
01478         if (argc > 2) return RESULT_SHOWUSAGE;
01479 
01480    for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
01481 
01482    return RESULT_FAILURE;
01483 }
01484 
01485 /*
01486 * restart app_rpt
01487 */
01488                                                                                                                                  
01489 static int rpt_do_restart(int fd, int argc, char *argv[])
01490 {
01491 int   i;
01492 
01493         if (argc > 2) return RESULT_SHOWUSAGE;
01494    for(i = 0; i < nrpts; i++)
01495    {
01496       if (rpt_vars[i].rxchannel) ast_softhangup(rpt_vars[i].rxchannel,AST_SOFTHANGUP_DEV);
01497    }
01498    return RESULT_FAILURE;
01499 }
01500 
01501 static int play_tone_pair(struct ast_channel *chan, int f1, int f2, int duration, int amplitude)
01502 {
01503    int res;
01504 
01505         if ((res = ast_tonepair_start(chan, f1, f2, duration, amplitude)))
01506                 return res;
01507                                                                                                                                             
01508         while(chan->generatordata) {
01509       if (ast_safe_sleep(chan,1)) return -1;
01510    }
01511 
01512         return 0;
01513 }
01514 
01515 static int play_tone(struct ast_channel *chan, int freq, int duration, int amplitude)
01516 {
01517    return play_tone_pair(chan, freq, 0, duration, amplitude);
01518 }
01519 
01520 static int play_silence(struct ast_channel *chan, int duration)
01521 {
01522    return play_tone_pair(chan, 0, 0, duration, 0);
01523 }
01524 
01525 
01526 static int send_morse(struct ast_channel *chan, const char *string, int speed, int freq, int amplitude)
01527 {
01528 
01529 static struct morse_bits mbits[] = {
01530       {0, 0}, /* SPACE */
01531       {0, 0}, 
01532       {6, 18},/* " */
01533       {0, 0},
01534       {7, 72},/* $ */
01535       {0, 0},
01536       {0, 0},
01537       {6, 30},/* ' */
01538       {5, 13},/* ( */
01539       {6, 29},/* ) */
01540       {0, 0},
01541       {5, 10},/* + */
01542       {6, 51},/* , */
01543       {6, 33},/* - */
01544       {6, 42},/* . */
01545       {5, 9}, /* / */
01546       {5, 31},/* 0 */
01547       {5, 30},/* 1 */
01548       {5, 28},/* 2 */
01549       {5, 24},/* 3 */
01550       {5, 16},/* 4 */
01551       {5, 0}, /* 5 */
01552       {5, 1}, /* 6 */
01553       {5, 3}, /* 7 */
01554       {5, 7}, /* 8 */
01555       {5, 15},/* 9 */
01556       {6, 7}, /* : */
01557       {6, 21},/* ; */
01558       {0, 0},
01559       {5, 33},/* = */
01560       {0, 0},
01561       {6, 12},/* ? */
01562       {0, 0},
01563          {2, 2}, /* A */
01564       {4, 1}, /* B */
01565       {4, 5}, /* C */
01566       {3, 1}, /* D */
01567       {1, 0}, /* E */
01568       {4, 4}, /* F */
01569       {3, 3}, /* G */
01570       {4, 0}, /* H */
01571       {2, 0}, /* I */
01572       {4, 14},/* J */
01573       {3, 5}, /* K */
01574       {4, 2}, /* L */
01575       {2, 3}, /* M */
01576       {2, 1}, /* N */
01577       {3, 7}, /* O */
01578       {4, 6}, /* P */
01579       {4, 11},/* Q */
01580       {3, 2}, /* R */
01581       {3, 0}, /* S */
01582       {1, 1}, /* T */
01583       {3, 4}, /* U */
01584       {4, 8}, /* V */
01585       {3, 6}, /* W */
01586       {4, 9}, /* X */
01587       {4, 13},/* Y */
01588       {4, 3}  /* Z */
01589    };
01590 
01591 
01592    int dottime;
01593    int dashtime;
01594    int intralettertime;
01595    int interlettertime;
01596    int interwordtime;
01597    int len, ddcomb;
01598    int res;
01599    int c;
01600    int i;
01601    int flags;
01602          
01603    res = 0;
01604    
01605    /* Approximate the dot time from the speed arg. */
01606    
01607    dottime = 900/speed;
01608    
01609    /* Establish timing relationships */
01610    
01611    dashtime = 3 * dottime;
01612    intralettertime = dottime;
01613    interlettertime = dottime * 4 ;
01614    interwordtime = dottime * 7;
01615    
01616    for(;(*string) && (!res); string++){
01617    
01618       c = *string;
01619       
01620       /* Convert lower case to upper case */
01621       
01622       if((c >= 'a') && (c <= 'z'))
01623          c -= 0x20;
01624       
01625       /* Can't deal with any char code greater than Z, skip it */
01626       
01627       if(c  > 'Z')
01628          continue;
01629       
01630       /* If space char, wait the inter word time */
01631                
01632       if(c == ' '){
01633          if(!res)
01634             res = play_silence(chan, interwordtime);
01635          continue;
01636       }
01637       
01638       /* Subtract out control char offset to match our table */
01639       
01640       c -= 0x20;
01641       
01642       /* Get the character data */
01643       
01644       len = mbits[c].len;
01645       ddcomb = mbits[c].ddcomb;
01646       
01647       /* Send the character */
01648       
01649       for(; len ; len--){
01650          if(!res)
01651             res = play_tone(chan, freq, (ddcomb & 1) ? dashtime : dottime, amplitude);
01652          if(!res)
01653             res = play_silence(chan, intralettertime);
01654          ddcomb >>= 1;
01655       }
01656       
01657       /* Wait the interletter time */
01658       
01659       if(!res)
01660          res = play_silence(chan, interlettertime - intralettertime);
01661    }
01662    
01663    /* Wait for all the frames to be sent */
01664    
01665    if (!res) 
01666       res = ast_waitstream(chan, "");
01667    ast_stopstream(chan);
01668    
01669    /*
01670    * Wait for the zaptel driver to physically write the tone blocks to the hardware
01671    */
01672 
01673    for(i = 0; i < 20 ; i++){
01674       flags =  ZT_IOMUX_WRITEEMPTY | ZT_IOMUX_NOWAIT; 
01675       res = ioctl(chan->fds[0], ZT_IOMUX, &flags);
01676       if(flags & ZT_IOMUX_WRITEEMPTY)
01677          break;
01678       if( ast_safe_sleep(chan, 50)){
01679          res = -1;
01680          break;
01681       }
01682    }
01683 
01684    
01685    return res;
01686 }
01687 
01688 static int send_tone_telemetry(struct ast_channel *chan, const char *tonestring)
01689 {
01690    char *stringp;
01691    char *tonesubset;
01692    int f1,f2;
01693    int duration;
01694    int amplitude;
01695    int res;
01696    int i;
01697    int flags;
01698    
01699    res = 0;
01700    
01701    stringp = ast_strdupa(tonestring);
01702 
01703    for(;tonestring;){
01704       tonesubset = strsep(&stringp,")");
01705       if(!tonesubset)
01706          break;
01707       if(sscanf(tonesubset,"(%d,%d,%d,%d", &f1, &f2, &duration, &amplitude) != 4)
01708          break;
01709       res = play_tone_pair(chan, f1, f2, duration, amplitude);
01710       if(res)
01711          break;
01712    }
01713    if(!res)
01714       res = play_tone_pair(chan, 0, 0, 100, 0); /* This is needed to ensure the last tone segment is timed correctly */
01715    
01716    if (!res) 
01717       res = ast_waitstream(chan, "");
01718    ast_stopstream(chan);
01719 
01720    /*
01721    * Wait for the zaptel driver to physically write the tone blocks to the hardware
01722    */
01723 
01724    for(i = 0; i < 20 ; i++){
01725       flags =  ZT_IOMUX_WRITEEMPTY | ZT_IOMUX_NOWAIT; 
01726       res = ioctl(chan->fds[0], ZT_IOMUX, &flags);
01727       if(flags & ZT_IOMUX_WRITEEMPTY)
01728          break;
01729       if( ast_safe_sleep(chan, 50)){
01730          res = -1;
01731          break;
01732       }
01733    }
01734       
01735    return res;
01736       
01737 }
01738    
01739 
01740 static int sayfile(struct ast_channel *mychannel, const char *fname)
01741 {
01742 int   res;
01743 
01744    res = ast_streamfile(mychannel, fname, mychannel->language);
01745    if (!res) 
01746       res = ast_waitstream(mychannel, "");
01747    else
01748        ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
01749    ast_stopstream(mychannel);
01750    return res;
01751 }
01752 
01753 static int saycharstr(struct ast_channel *mychannel,char *str)
01754 {
01755 int   res;
01756 
01757    res = ast_say_character_str(mychannel,str,NULL,mychannel->language);
01758    if (!res) 
01759       res = ast_waitstream(mychannel, "");
01760    else
01761        ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
01762    ast_stopstream(mychannel);
01763    return res;
01764 }
01765 
01766 static int saynum(struct ast_channel *mychannel, int num)
01767 {
01768    int res;
01769    res = ast_say_number(mychannel, num, NULL, mychannel->language, NULL);
01770    if(!res)
01771       res = ast_waitstream(mychannel, "");
01772    else
01773       ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
01774    ast_stopstream(mychannel);
01775    return res;
01776 }
01777 
01778 
01779 static int telem_any(struct rpt *myrpt,struct ast_channel *chan, const char *entry)
01780 {
01781    int res;
01782    char c;
01783    
01784    static int morsespeed;
01785    static int morsefreq;
01786    static int morseampl;
01787    static int morseidfreq = 0;
01788    static int morseidampl;
01789    static char mcat[] = MORSE;
01790    
01791    res = 0;
01792    
01793    if(!morseidfreq){ /* Get the morse parameters if not already loaded */
01794       morsespeed = retrieve_astcfgint(myrpt, mcat, "speed", 5, 20, 20);
01795          morsefreq = retrieve_astcfgint(myrpt, mcat, "frequency", 300, 3000, 800);
01796          morseampl = retrieve_astcfgint(myrpt, mcat, "amplitude", 200, 8192, 4096);
01797       morseidampl = retrieve_astcfgint(myrpt, mcat, "idamplitude", 200, 8192, 2048);
01798       morseidfreq = retrieve_astcfgint(myrpt, mcat, "idfrequency", 300, 3000, 330); 
01799    }
01800    
01801    /* Is it a file, or a tone sequence? */
01802          
01803    if(entry[0] == '|'){
01804       c = entry[1];
01805       if((c >= 'a')&&(c <= 'z'))
01806          c -= 0x20;
01807    
01808       switch(c){
01809          case 'I': /* Morse ID */
01810             res = send_morse(chan, entry + 2, morsespeed, morseidfreq, morseidampl);
01811             break;
01812          
01813          case 'M': /* Morse Message */
01814             res = send_morse(chan, entry + 2, morsespeed, morsefreq, morseampl);
01815             break;
01816          
01817          case 'T': /* Tone sequence */
01818             res = send_tone_telemetry(chan, entry + 2);
01819             break;
01820          default:
01821             res = -1;
01822       }
01823    }
01824    else
01825       res = sayfile(chan, entry); /* File */
01826    return res;
01827 }
01828 
01829 /*
01830 * This function looks up a telemetry name in the config file, and does a telemetry response as configured.
01831 *
01832 * 4 types of telemtry are handled: Morse ID, Morse Message, Tone Sequence, and a File containing a recording.
01833 */
01834 
01835 static int telem_lookup(struct rpt *myrpt,struct ast_channel *chan, char *node, char *name)
01836 {
01837    
01838    int res;
01839    int i;
01840    const char *entry;
01841    const char *telemetry;
01842    char *telemetry_save;
01843 
01844    res = 0;
01845    telemetry_save = NULL;
01846    entry = NULL;
01847    
01848    /* Retrieve the section name for telemetry from the node section */
01849    telemetry = ast_variable_retrieve(myrpt->cfg, node, TELEMETRY);
01850    if(telemetry ){
01851       telemetry_save = ast_strdupa(telemetry);
01852       if(!telemetry_save){
01853          ast_log(LOG_WARNING,"ast_strdupa() failed in telem_lookup()\n");
01854          return res;
01855       }
01856       entry = ast_variable_retrieve(myrpt->cfg, telemetry_save, name);
01857    }
01858    
01859    /* Try to look up the telemetry name */   
01860 
01861    if(!entry){
01862       /* Telemetry name wasn't found in the config file, use the default */
01863       for(i = 0; i < sizeof(tele_defs)/sizeof(struct telem_defaults) ; i++){
01864          if(!strcasecmp(tele_defs[i].name, name))
01865             entry = tele_defs[i].value;
01866       }
01867    }
01868    if(entry){  
01869       if(strlen(entry))
01870          telem_any(myrpt,chan, entry);
01871    }
01872    else{
01873       res = -1;
01874    }
01875    return res;
01876 }
01877 
01878 /*
01879 * Retrieve a wait interval
01880 */
01881 
01882 static int get_wait_interval(struct rpt *myrpt, int type)
01883 {
01884    int interval;
01885    const char *wait_times;
01886    char *wait_times_save = NULL;
01887 
01888    wait_times = ast_variable_retrieve(myrpt->cfg, myrpt->name, "wait_times");
01889 
01890    if (wait_times) {
01891       wait_times_save = ast_strdupa(wait_times);
01892       if (!wait_times_save) {
01893          ast_log(LOG_WARNING, "Out of memory in wait_interval()\n");
01894          wait_times = NULL;
01895       }
01896    }
01897 
01898    switch (type) {
01899    case DLY_TELEM:
01900       if (wait_times)
01901          interval = retrieve_astcfgint(myrpt, wait_times_save, "telemwait", 500, 5000, 1000);
01902       else
01903          interval = 1000;
01904       break;
01905 
01906    case DLY_ID:
01907       if (wait_times)
01908          interval = retrieve_astcfgint(myrpt, wait_times_save, "idwait", 250, 5000, 500);
01909       else
01910          interval = 500;
01911       break;
01912 
01913    case DLY_UNKEY:
01914       if (wait_times)
01915          interval = retrieve_astcfgint(myrpt, wait_times_save, "unkeywait", 500, 5000, 1000);
01916       else
01917          interval = 1000;
01918       break;
01919 
01920    case DLY_CALLTERM:
01921       if (wait_times)
01922          interval = retrieve_astcfgint(myrpt, wait_times_save, "calltermwait", 500, 5000, 1500);
01923       else
01924          interval = 1500;
01925       break;
01926 
01927    default:
01928       return 0;
01929    }
01930    return interval;
01931 }
01932 
01933 
01934 /*
01935 * Wait a configurable interval of time 
01936 */
01937 
01938 
01939 static void wait_interval(struct rpt *myrpt, int type, struct ast_channel *chan)
01940 {
01941    int interval;
01942    interval = get_wait_interval(myrpt, type);
01943    if(debug)
01944       ast_log(LOG_NOTICE," Delay interval = %d\n", interval);
01945    if(interval)
01946       ast_safe_sleep(chan,interval);
01947    if(debug)
01948       ast_log(LOG_NOTICE,"Delay complete\n");
01949    return;
01950 }
01951 
01952 
01953 static void *rpt_tele_thread(void *this)
01954 {
01955 ZT_CONFINFO ci;  /* conference info */
01956 int   res = 0,haslink,hastx,hasremote,imdone = 0, unkeys_queued, x;
01957 struct   rpt_tele *mytele = (struct rpt_tele *)this;
01958 struct  rpt_tele *tlist;
01959 struct   rpt *myrpt;
01960 struct   rpt_link *l,*m,linkbase;
01961 struct   ast_channel *mychannel;
01962    const char *p, *ct;
01963    char *ct_copy, *ident, *nodename;
01964 time_t t;
01965 struct tm localtm;
01966 
01967    /* get a pointer to myrpt */
01968    myrpt = mytele->rpt;
01969 
01970    /* Snag copies of a few key myrpt variables */
01971    rpt_mutex_lock(&myrpt->lock);
01972    nodename = ast_strdupa(myrpt->name);
01973    ident = ast_strdupa(myrpt->p.ident);
01974    rpt_mutex_unlock(&myrpt->lock);
01975    
01976    /* allocate a pseudo-channel thru asterisk */
01977    mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
01978    if (!mychannel)
01979    {
01980       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
01981       rpt_mutex_lock(&myrpt->lock);
01982       remque((struct qelem *)mytele);
01983       ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
01984       rpt_mutex_unlock(&myrpt->lock);
01985       free(mytele);     
01986       pthread_exit(NULL);
01987    }
01988    rpt_mutex_lock(&myrpt->lock);
01989    mytele->chan = mychannel; /* Save a copy of the channel so we can access it externally if need be */
01990    rpt_mutex_unlock(&myrpt->lock);
01991    
01992    /* make a conference for the tx */
01993    ci.chan = 0;
01994    /* If there's an ID queued, or tail message queued, */
01995    /* only connect the ID audio to the local tx conference so */
01996    /* linked systems can't hear it */
01997    ci.confno = (((mytele->mode == ID) || (mytele->mode == IDTALKOVER) || (mytele->mode == UNKEY) || 
01998       (mytele->mode == TAILMSG)) ?
01999          myrpt->txconf : myrpt->conf);
02000    ci.confmode = ZT_CONF_CONFANN;
02001    /* first put the channel on the conference in announce mode */
02002    if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
02003    {
02004       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
02005       rpt_mutex_lock(&myrpt->lock);
02006       remque((struct qelem *)mytele);
02007       rpt_mutex_unlock(&myrpt->lock);
02008       ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
02009       free(mytele);     
02010       ast_hangup(mychannel);
02011       pthread_exit(NULL);
02012    }
02013    ast_stopstream(mychannel);
02014    switch(mytele->mode)
02015    {
02016 
02017        case ID:
02018        case ID1:
02019       /* wait a bit */
02020       wait_interval(myrpt, (mytele->mode == ID) ? DLY_ID : DLY_TELEM,mychannel);
02021       res = telem_any(myrpt,mychannel, ident); 
02022       imdone=1;   
02023       break;
02024       
02025        case TAILMSG:
02026       res = ast_streamfile(mychannel, myrpt->p.tailmessages[myrpt->tailmessagen], mychannel->language); 
02027       break;
02028       
02029        case IDTALKOVER:
02030          p = ast_variable_retrieve(myrpt->cfg, nodename, "idtalkover");
02031          if(p)
02032          res = telem_any(myrpt,mychannel, p); 
02033       imdone=1;   
02034          break;
02035             
02036        case PROC:
02037       /* wait a little bit longer */
02038       wait_interval(myrpt, DLY_TELEM, mychannel);
02039       res = telem_lookup(myrpt, mychannel, myrpt->name, "patchup");
02040       if(res < 0){ /* Then default message */
02041          res = ast_streamfile(mychannel, "rpt/callproceeding", mychannel->language);
02042       }
02043       break;
02044        case TERM:
02045       /* wait a little bit longer */
02046       wait_interval(myrpt, DLY_CALLTERM, mychannel);
02047       res = telem_lookup(myrpt, mychannel, myrpt->name, "patchdown");
02048       if(res < 0){ /* Then default message */
02049          res = ast_streamfile(mychannel, "rpt/callterminated", mychannel->language);
02050       }
02051       break;
02052        case COMPLETE:
02053       /* wait a little bit */
02054       wait_interval(myrpt, DLY_TELEM, mychannel);
02055       res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
02056       break;
02057        case MACRO_NOTFOUND:
02058       /* wait a little bit */
02059       wait_interval(myrpt, DLY_TELEM, mychannel);
02060       res = ast_streamfile(mychannel, "rpt/macro_notfound", mychannel->language);
02061       break;
02062        case MACRO_BUSY:
02063       /* wait a little bit */
02064       wait_interval(myrpt, DLY_TELEM, mychannel);
02065       res = ast_streamfile(mychannel, "rpt/macro_busy", mychannel->language);
02066       break;
02067        case UNKEY:
02068       if(myrpt->patchnoct && myrpt->callmode){ /* If no CT during patch configured, then don't send one */
02069          imdone = 1;
02070          break;
02071       }
02072          
02073       /*
02074       * Reset the Unkey to CT timer
02075       */
02076 
02077       x = get_wait_interval(myrpt, DLY_UNKEY);
02078       rpt_mutex_lock(&myrpt->lock);
02079       myrpt->unkeytocttimer = x; /* Must be protected as it is changed below */
02080       rpt_mutex_unlock(&myrpt->lock);
02081 
02082       /*
02083       * If there's one already queued, don't do another
02084       */
02085 
02086       tlist = myrpt->tele.next;
02087       unkeys_queued = 0;
02088                 if (tlist != &myrpt->tele)
02089                 {
02090                         rpt_mutex_lock(&myrpt->lock);
02091                         while(tlist != &myrpt->tele){
02092                                 if (tlist->mode == UNKEY) unkeys_queued++;
02093                                 tlist = tlist->next;
02094                         }
02095                         rpt_mutex_unlock(&myrpt->lock);
02096       }
02097       if( unkeys_queued > 1){
02098          imdone = 1;
02099          break;
02100       }
02101 
02102       /* Wait for the telemetry timer to expire */
02103       /* Periodically check the timer since it can be re-initialized above */
02104       while(myrpt->unkeytocttimer)
02105       {
02106          int ctint;
02107          if(myrpt->unkeytocttimer > 100)
02108             ctint = 100;
02109          else
02110             ctint = myrpt->unkeytocttimer;
02111          ast_safe_sleep(mychannel, ctint);
02112          rpt_mutex_lock(&myrpt->lock);
02113          if(myrpt->unkeytocttimer < ctint)
02114             myrpt->unkeytocttimer = 0;
02115          else
02116             myrpt->unkeytocttimer -= ctint;
02117          rpt_mutex_unlock(&myrpt->lock);
02118       }
02119    
02120       /*
02121       * Now, the carrier on the rptr rx should be gone. 
02122       * If it re-appeared, then forget about sending the CT
02123       */
02124       if(myrpt->keyed){
02125          imdone = 1;
02126          break;
02127       }
02128       
02129       rpt_mutex_lock(&myrpt->lock); /* Update the kerchunk counters */
02130       myrpt->dailykerchunks++;
02131       myrpt->totalkerchunks++;
02132       rpt_mutex_unlock(&myrpt->lock);
02133    
02134       haslink = 0;
02135       hastx = 0;
02136       hasremote = 0;    
02137       l = myrpt->links.next;
02138       if (l != &myrpt->links)
02139       {
02140          rpt_mutex_lock(&myrpt->lock);
02141          while(l != &myrpt->links)
02142          {
02143             if (l->name[0] == '0')
02144             {
02145                l = l->next;
02146                continue;
02147             }
02148             haslink = 1;
02149             if (l->mode) {
02150                hastx++;
02151                if (l->isremote) hasremote++;
02152             }
02153             l = l->next;
02154          }
02155          rpt_mutex_unlock(&myrpt->lock);
02156       }
02157       if (haslink)
02158       {
02159 
02160          res = telem_lookup(myrpt,mychannel, myrpt->name, (!hastx) ? "remotemon" : "remotetx");
02161          if(res)
02162             ast_log(LOG_WARNING, "telem_lookup:remotexx failed on %s\n", mychannel->name);
02163          
02164       
02165          /* if in remote cmd mode, indicate it */
02166          if (myrpt->cmdnode[0])
02167          {
02168             ast_safe_sleep(mychannel,200);
02169             res = telem_lookup(myrpt,mychannel, myrpt->name, "cmdmode");
02170             if(res)
02171                ast_log(LOG_WARNING, "telem_lookup:cmdmode failed on %s\n", mychannel->name);
02172             ast_stopstream(mychannel);
02173          }
02174       }
02175       else if((ct = ast_variable_retrieve(myrpt->cfg, nodename, "unlinkedct"))){ /* Unlinked Courtesy Tone */
02176          ct_copy = ast_strdupa(ct);
02177          res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
02178          if(res)
02179             ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);     
02180       }  
02181       if (hasremote && (!myrpt->cmdnode[0]))
02182       {
02183          /* set for all to hear */
02184          ci.chan = 0;
02185          ci.confno = myrpt->conf;
02186          ci.confmode = ZT_CONF_CONFANN;
02187          /* first put the channel on the conference in announce mode */
02188          if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
02189          {
02190             ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
02191             rpt_mutex_lock(&myrpt->lock);
02192             remque((struct qelem *)mytele);
02193             rpt_mutex_unlock(&myrpt->lock);
02194             ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
02195             free(mytele);     
02196             ast_hangup(mychannel);
02197             pthread_exit(NULL);
02198          }
02199          if((ct = ast_variable_retrieve(myrpt->cfg, nodename, "remotect"))){ /* Unlinked Courtesy Tone */
02200             ast_safe_sleep(mychannel,200);
02201             ct_copy = ast_strdupa(ct);
02202             res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
02203             if(res)
02204                ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);     
02205          }  
02206       }
02207 #ifdef   _MDC_DECODE_H_
02208       if (myrpt->lastunit)
02209       {
02210          char mystr[10];
02211 
02212          ast_safe_sleep(mychannel,200);
02213          /* set for all to hear */
02214          ci.chan = 0;
02215          ci.confno = myrpt->txconf;
02216          ci.confmode = ZT_CONF_CONFANN;
02217          /* first put the channel on the conference in announce mode */
02218          if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
02219          {
02220             ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
02221             rpt_mutex_lock(&myrpt->lock);
02222             remque((struct qelem *)mytele);
02223             rpt_mutex_unlock(&myrpt->lock);
02224             ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
02225             free(mytele);     
02226             ast_hangup(mychannel);
02227             pthread_exit(NULL);
02228          }
02229          sprintf(mystr,"%04x",myrpt->lastunit);
02230          myrpt->lastunit = 0;
02231          ast_say_character_str(mychannel,mystr,NULL,mychannel->language);
02232          break;
02233       }
02234 #endif
02235       imdone = 1;
02236       break;
02237        case REMDISC:
02238       /* wait a little bit */
02239       wait_interval(myrpt, DLY_TELEM, mychannel);
02240       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
02241       if (!res) 
02242          res = ast_waitstream(mychannel, "");
02243       else
02244           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02245       ast_stopstream(mychannel);
02246       ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
02247       res = ast_streamfile(mychannel, ((mytele->mylink.connected) ? 
02248          "rpt/remote_disc" : "rpt/remote_busy"), mychannel->language);
02249       break;
02250        case REMALREADY:
02251       /* wait a little bit */
02252       wait_interval(myrpt, DLY_TELEM, mychannel);
02253       res = ast_streamfile(mychannel, "rpt/remote_already", mychannel->language);
02254       break;
02255        case REMNOTFOUND:
02256       /* wait a little bit */
02257       wait_interval(myrpt, DLY_TELEM, mychannel);
02258       res = ast_streamfile(mychannel, "rpt/remote_notfound", mychannel->language);
02259       break;
02260        case REMGO:
02261       /* wait a little bit */
02262       wait_interval(myrpt, DLY_TELEM, mychannel);
02263       res = ast_streamfile(mychannel, "rpt/remote_go", mychannel->language);
02264       break;
02265        case CONNECTED:
02266       /* wait a little bit */
02267       wait_interval(myrpt, DLY_TELEM,  mychannel);
02268       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
02269       if (!res) 
02270          res = ast_waitstream(mychannel, "");
02271       else
02272           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02273       ast_stopstream(mychannel);
02274       ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
02275       res = ast_streamfile(mychannel, "rpt/connected", mychannel->language);
02276       break;
02277        case CONNFAIL:
02278       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
02279       if (!res) 
02280          res = ast_waitstream(mychannel, "");
02281       else
02282           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02283       ast_stopstream(mychannel);
02284       ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
02285       res = ast_streamfile(mychannel, "rpt/connection_failed", mychannel->language);
02286       break;
02287        case STATUS:
02288       /* wait a little bit */
02289       wait_interval(myrpt, DLY_TELEM, mychannel);
02290       hastx = 0;
02291       linkbase.next = &linkbase;
02292       linkbase.prev = &linkbase;
02293       rpt_mutex_lock(&myrpt->lock);
02294       /* make our own list of links */
02295       l = myrpt->links.next;
02296       while(l != &myrpt->links)
02297       {
02298          if (l->name[0] == '0')
02299          {
02300             l = l->next;
02301             continue;
02302          }
02303          m = malloc(sizeof(struct rpt_link));
02304          if (!m)
02305          {
02306             ast_log(LOG_WARNING, "Cannot alloc memory on %s\n", mychannel->name);
02307             remque((struct qelem *)mytele);
02308             rpt_mutex_unlock(&myrpt->lock);
02309             ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
02310             free(mytele);     
02311             ast_hangup(mychannel);
02312             pthread_exit(NULL);
02313          }
02314          memcpy(m,l,sizeof(struct rpt_link));
02315          m->next = m->prev = NULL;
02316          insque((struct qelem *)m,(struct qelem *)linkbase.next);
02317          l = l->next;
02318       }
02319       rpt_mutex_unlock(&myrpt->lock);
02320       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
02321       if (!res) 
02322          res = ast_waitstream(mychannel, "");
02323       else
02324           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02325       ast_stopstream(mychannel);
02326       ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
02327       if (!res) 
02328          res = ast_waitstream(mychannel, "");
02329       else
02330           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02331       ast_stopstream(mychannel);
02332       if (myrpt->callmode)
02333       {
02334          hastx = 1;
02335          res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
02336          if (!res) 
02337             res = ast_waitstream(mychannel, "");
02338          else
02339              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02340          ast_stopstream(mychannel);
02341       }
02342       l = linkbase.next;
02343       while(l != &linkbase)
02344       {
02345          hastx = 1;
02346          res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
02347          if (!res) 
02348             res = ast_waitstream(mychannel, "");
02349          else
02350             ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02351          ast_stopstream(mychannel);
02352          ast_say_character_str(mychannel,l->name,NULL,mychannel->language);
02353          if (!res) 
02354             res = ast_waitstream(mychannel, "");
02355          else
02356              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02357          ast_stopstream(mychannel);
02358          res = ast_streamfile(mychannel, ((l->mode) ? 
02359             "rpt/tranceive" : "rpt/monitor"), mychannel->language);
02360          if (!res) 
02361             res = ast_waitstream(mychannel, "");
02362          else
02363             ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02364          ast_stopstream(mychannel);
02365          l = l->next;
02366       }        
02367       if (!hastx)
02368       {
02369          res = ast_streamfile(mychannel, "rpt/repeat_only", mychannel->language);
02370          if (!res) 
02371             res = ast_waitstream(mychannel, "");
02372          else
02373              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02374          ast_stopstream(mychannel);
02375       }
02376       /* destroy our local link queue */
02377       l = linkbase.next;
02378       while(l != &linkbase)
02379       {
02380          m = l;
02381          l = l->next;
02382          remque((struct qelem *)m);
02383          free(m);
02384       }        
02385       imdone = 1;
02386       break;
02387 
02388        case LASTNODEKEY: /* Identify last node which keyed us up */
02389       rpt_mutex_lock(&myrpt->lock);
02390       if(myrpt->lastnodewhichkeyedusup)
02391          p = ast_strdupa(myrpt->lastnodewhichkeyedusup); /* Make a local copy of the node name */
02392       else
02393          p = NULL;
02394       rpt_mutex_unlock(&myrpt->lock);
02395       if(!p){
02396          imdone = 1; /* no node previously keyed us up, or the node which did has been disconnected */
02397          break;
02398       }
02399       wait_interval(myrpt, DLY_TELEM, mychannel);
02400       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
02401       if (!res) 
02402          res = ast_waitstream(mychannel, "");
02403       else
02404           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02405       ast_stopstream(mychannel);
02406       ast_say_character_str(mychannel, p, NULL, mychannel->language);
02407       if (!res) 
02408          res = ast_waitstream(mychannel, "");
02409       else
02410          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02411       ast_stopstream(mychannel);
02412       imdone = 1;
02413       break;      
02414 
02415        case TIMEOUT:
02416       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
02417       if (!res) 
02418          res = ast_waitstream(mychannel, "");
02419       else
02420           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02421       ast_stopstream(mychannel);
02422       ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
02423       res = ast_streamfile(mychannel, "rpt/timeout", mychannel->language);
02424       break;
02425       
02426        case STATS_TIME:
02427          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
02428       t = time(NULL);
02429       localtime_r(&t, &localtm);
02430       /* Say the phase of the day is before the time */
02431       if((localtm.tm_hour >= 0) && (localtm.tm_hour < 12))
02432          p = "rpt/goodmorning";
02433       else if((localtm.tm_hour >= 12) && (localtm.tm_hour < 18))
02434          p = "rpt/goodafternoon";
02435       else
02436          p = "rpt/goodevening";
02437       if (sayfile(mychannel,p) == -1)
02438       {
02439          imdone = 1;
02440          break;
02441       }
02442       /* Say the time is ... */     
02443       if (sayfile(mychannel,"rpt/thetimeis") == -1)
02444       {
02445          imdone = 1;
02446          break;
02447       }
02448       /* Say the time */            
02449          res = ast_say_time(mychannel, t, "", mychannel->language);
02450       if (!res) 
02451          res = ast_waitstream(mychannel, "");
02452       ast_stopstream(mychannel);    
02453       imdone = 1;
02454          break;
02455        case STATS_VERSION:
02456          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
02457       /* Say "version" */
02458       if (sayfile(mychannel,"rpt/version") == -1)
02459       {
02460          imdone = 1;
02461          break;
02462       }
02463       if(!res) /* Say "X" */
02464          ast_say_number(mychannel, vmajor, "", mychannel->language, (char *) NULL);
02465       if (!res) 
02466          res = ast_waitstream(mychannel, "");
02467       ast_stopstream(mychannel); 
02468       if (saycharstr(mychannel,".") == -1)
02469       {
02470          imdone = 1;
02471          break;
02472       }
02473       if(!res) /* Say "Y" */
02474          ast_say_number(mychannel, vminor, "", mychannel->language, (char *) NULL);
02475       if (!res){
02476          res = ast_waitstream(mychannel, "");
02477          ast_stopstream(mychannel);
02478       }  
02479       else
02480           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02481       imdone = 1;
02482          break;
02483        case ARB_ALPHA:
02484          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
02485          if(mytele->param)
02486             saycharstr(mychannel, mytele->param);
02487          imdone = 1;
02488       break;
02489        case REV_PATCH:
02490          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
02491          if(mytele->param) {
02492 
02493          /* Parts of this section taken from app_parkandannounce */
02494          char *tpl_working, *tpl_current;
02495          char *tmp[100], *myparm;
02496          int looptemp=0,i=0, dres = 0;
02497    
02498 
02499          tpl_working = strdupa(mytele->param);
02500          myparm = strsep(&tpl_working,",");
02501          tpl_current=strsep(&tpl_working, ":");
02502 
02503          while(tpl_current && looptemp < sizeof(tmp)) {
02504             tmp[looptemp]=tpl_current;
02505             looptemp++;
02506             tpl_current=strsep(&tpl_working,":");
02507          }
02508 
02509          for(i=0; i<looptemp; i++) {
02510             if(!strcmp(tmp[i], "PARKED")) {
02511                ast_say_digits(mychannel, atoi(myparm), "", mychannel->language);
02512             } else if(!strcmp(tmp[i], "NODE")) {
02513                ast_say_digits(mychannel, atoi(myrpt->name), "", mychannel->language);
02514             } else {
02515                dres = ast_streamfile(mychannel, tmp[i], mychannel->language);
02516                if(!dres) {
02517                   dres = ast_waitstream(mychannel, "");
02518                } else {
02519                   ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", tmp[i], mychannel->name);
02520                   dres = 0;
02521                }
02522             }
02523          }
02524       }
02525          imdone = 1;
02526       break;
02527        case TEST_TONE:
02528       imdone = 1;
02529       myrpt->stopgen = 0;
02530            if ((res = ast_tonepair_start(mychannel, 1004.0, 0, 99999999, 7200.0))) 
02531          break;
02532            while(mychannel->generatordata && (!myrpt->stopgen)) {
02533          if (ast_safe_sleep(mychannel,1)) break;
02534             imdone = 1;
02535          }
02536       break;
02537        default:
02538          break;
02539    }
02540    myrpt->stopgen = 0;
02541    if (!imdone)
02542    {
02543       if (!res) 
02544          res = ast_waitstream(mychannel, "");
02545       else {
02546          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02547          res = 0;
02548       }
02549    }
02550    ast_stopstream(mychannel);
02551    rpt_mutex_lock(&myrpt->lock);
02552    if (mytele->mode == TAILMSG)
02553    {
02554       if (!res)
02555       {
02556          myrpt->tailmessagen++;
02557          if(myrpt->tailmessagen >= myrpt->p.tailmessagemax) myrpt->tailmessagen = 0;
02558       }
02559       else
02560       {
02561          myrpt->tmsgtimer = myrpt->p.tailsquashedtime;
02562       }
02563    }
02564    remque((struct qelem *)mytele);
02565    rpt_mutex_unlock(&myrpt->lock);
02566    free(mytele);     
02567    ast_hangup(mychannel);
02568 #ifdef  APP_RPT_LOCK_DEBUG
02569    {
02570       struct lockthread *t;
02571 
02572       sleep(5);
02573       ast_mutex_lock(&locklock);
02574       t = get_lockthread(pthread_self());
02575       if (t) memset(t,0,sizeof(struct lockthread));
02576       ast_mutex_unlock(&locklock);
02577    }        
02578 #endif
02579    pthread_exit(NULL);
02580 }
02581 
02582 static void rpt_telemetry(struct rpt *myrpt,int mode, void *data)
02583 {
02584 struct rpt_tele *tele;
02585 struct rpt_link *mylink = (struct rpt_link *) data;
02586 int res;
02587 pthread_attr_t attr;
02588 
02589    tele = malloc(sizeof(struct rpt_tele));
02590    if (!tele)
02591    {
02592       ast_log(LOG_WARNING, "Unable to allocate memory\n");
02593       pthread_exit(NULL);
02594       return;
02595    }
02596    /* zero it out */
02597    memset((char *)tele,0,sizeof(struct rpt_tele));
02598    tele->rpt = myrpt;
02599    tele->mode = mode;
02600    rpt_mutex_lock(&myrpt->lock);
02601    if((mode == CONNFAIL) || (mode == REMDISC) || (mode == CONNECTED)){
02602       memset(&tele->mylink,0,sizeof(struct rpt_link));
02603       if (mylink){
02604          memcpy(&tele->mylink,mylink,sizeof(struct rpt_link));
02605       }
02606    }
02607    else if ((mode == ARB_ALPHA) || (mode == REV_PATCH)) {
02608       ast_copy_string(tele->param, (char *) data, TELEPARAMSIZE);
02609    }
02610    insque((struct qelem *)tele, (struct qelem *)myrpt->tele.next);
02611    rpt_mutex_unlock(&myrpt->lock);
02612         pthread_attr_init(&attr);
02613         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
02614    res = ast_pthread_create(&tele->threadid,&attr,rpt_tele_thread,(void *) tele);
02615    pthread_attr_destroy(&attr);
02616    if(res < 0){
02617       rpt_mutex_lock(&myrpt->lock);
02618       remque((struct qlem *) tele); /* We don't like stuck transmitters, remove it from the queue */
02619       rpt_mutex_unlock(&myrpt->lock);  
02620       ast_log(LOG_WARNING, "Could not create telemetry thread: %s\n",strerror(res));
02621    }
02622    return;
02623 }
02624 
02625 static void *rpt_call(void *this)
02626 {
02627 ZT_CONFINFO ci;  /* conference info */
02628 struct   rpt *myrpt = (struct rpt *)this;
02629 int   res;
02630 struct   ast_frame wf;
02631 int stopped,congstarted,dialtimer,lastcidx,aborted;
02632 struct ast_channel *mychannel,*genchannel;
02633 
02634 
02635    myrpt->mydtmf = 0;
02636    /* allocate a pseudo-channel thru asterisk */
02637    mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
02638    if (!mychannel)
02639    {
02640       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
02641       pthread_exit(NULL);
02642    }
02643    ci.chan = 0;
02644    ci.confno = myrpt->conf; /* use the pseudo conference */
02645    ci.confmode = ZT_CONF_REALANDPSEUDO | ZT_CONF_TALKER | ZT_CONF_LISTENER
02646       | ZT_CONF_PSEUDO_TALKER | ZT_CONF_PSEUDO_LISTENER; 
02647    /* first put the channel on the conference */
02648    if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
02649    {
02650       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
02651       ast_hangup(mychannel);
02652       myrpt->callmode = 0;
02653       pthread_exit(NULL);
02654    }
02655    /* allocate a pseudo-channel thru asterisk */
02656    genchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
02657    if (!genchannel)
02658    {
02659       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
02660       ast_hangup(mychannel);
02661       pthread_exit(NULL);
02662    }
02663    ci.chan = 0;
02664    ci.confno = myrpt->conf;
02665    ci.confmode = ZT_CONF_REALANDPSEUDO | ZT_CONF_TALKER | ZT_CONF_LISTENER
02666       | ZT_CONF_PSEUDO_TALKER | ZT_CONF_PSEUDO_LISTENER; 
02667    /* first put the channel on the conference */
02668    if (ioctl(genchannel->fds[0],ZT_SETCONF,&ci) == -1)
02669    {
02670       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
02671       ast_hangup(mychannel);
02672       ast_hangup(genchannel);
02673       myrpt->callmode = 0;
02674       pthread_exit(NULL);
02675    }
02676    if (myrpt->p.tonezone && (tone_zone_set_zone(mychannel->fds[0],myrpt->p.tonezone) == -1))
02677    {
02678       ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
02679       ast_hangup(mychannel);
02680       ast_hangup(genchannel);
02681       myrpt->callmode = 0;
02682       pthread_exit(NULL);
02683    }
02684    if (myrpt->p.tonezone && (tone_zone_set_zone(genchannel->fds[0],myrpt->p.tonezone) == -1))
02685    {
02686       ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
02687       ast_hangup(mychannel);
02688       ast_hangup(genchannel);
02689       myrpt->callmode = 0;
02690       pthread_exit(NULL);
02691    }
02692    /* start dialtone if patchquiet is 0. Special patch modes don't send dial tone */
02693    if ((!myrpt->patchquiet) && (tone_zone_play_tone(mychannel->fds[0],ZT_TONE_DIALTONE) < 0))
02694    {
02695       ast_log(LOG_WARNING, "Cannot start dialtone\n");
02696       ast_hangup(mychannel);
02697       ast_hangup(genchannel);
02698       myrpt->callmode = 0;
02699       pthread_exit(NULL);
02700    }
02701    stopped = 0;
02702    congstarted = 0;
02703    dialtimer = 0;
02704    lastcidx = 0;
02705    aborted = 0;
02706 
02707 
02708    while ((myrpt->callmode == 1) || (myrpt->callmode == 4))
02709    {
02710 
02711       if((myrpt->patchdialtime)&&(myrpt->callmode == 1)&&(myrpt->cidx != lastcidx)){
02712          dialtimer = 0;
02713          lastcidx = myrpt->cidx;
02714       }     
02715 
02716       if((myrpt->patchdialtime)&&(dialtimer >= myrpt->patchdialtime)){ 
02717          rpt_mutex_lock(&myrpt->lock);
02718          aborted = 1;
02719          myrpt->callmode = 0;
02720          rpt_mutex_unlock(&myrpt->lock);
02721          break;
02722       }
02723    
02724       if ((!myrpt->patchquiet) && (!stopped) && (myrpt->callmode == 1) && (myrpt->cidx > 0))
02725       {
02726          stopped = 1;
02727          /* stop dial tone */
02728          tone_zone_play_tone(mychannel->fds[0],-1);
02729       }
02730       if (myrpt->callmode == 4)
02731       {
02732          if(!congstarted){
02733             congstarted = 1;
02734             /* start congestion tone */
02735             tone_zone_play_tone(mychannel->fds[0],ZT_TONE_CONGESTION);
02736          }
02737       }
02738       res = ast_safe_sleep(mychannel, MSWAIT);
02739       if (res < 0)
02740       {
02741          ast_hangup(mychannel);
02742          ast_hangup(genchannel);
02743          rpt_mutex_lock(&myrpt->lock);
02744          myrpt->callmode = 0;
02745          rpt_mutex_unlock(&myrpt->lock);
02746          pthread_exit(NULL);
02747       }
02748       dialtimer += MSWAIT;
02749    }
02750    /* stop any tone generation */
02751    tone_zone_play_tone(mychannel->fds[0],-1);
02752    /* end if done */
02753    if (!myrpt->callmode)
02754    {
02755       ast_hangup(mychannel);
02756       ast_hangup(genchannel);
02757       rpt_mutex_lock(&myrpt->lock);
02758       myrpt->callmode = 0;
02759       rpt_mutex_unlock(&myrpt->lock);
02760       if((!myrpt->patchquiet) && aborted)
02761          rpt_telemetry(myrpt, TERM, NULL);
02762       pthread_exit(NULL);        
02763    }
02764 
02765    if (myrpt->p.ourcallerid && *myrpt->p.ourcallerid){
02766       char *name, *loc, *instr;
02767       instr = strdup(myrpt->p.ourcallerid);
02768       if(instr){
02769          ast_callerid_parse(instr, &name, &loc);
02770          if(loc){
02771             if(mychannel->cid.cid_num)
02772                free(mychannel->cid.cid_num);
02773             mychannel->cid.cid_num = strdup(loc);
02774          }
02775          if(name){
02776             if(mychannel->cid.cid_name)
02777                free(mychannel->cid.cid_name);
02778             mychannel->cid.cid_name = strdup(name);
02779          }
02780          free(instr);
02781       }
02782    }
02783 
02784    ast_copy_string(mychannel->exten, myrpt->exten, sizeof(mychannel->exten));
02785    ast_copy_string(mychannel->context, myrpt->patchcontext, sizeof(mychannel->context));
02786    
02787    if (myrpt->p.acctcode)
02788       ast_string_field_set(mychannel, accountcode, myrpt->p.acctcode);
02789    mychannel->priority = 1;
02790    ast_channel_undefer_dtmf(mychannel);
02791    if (ast_pbx_start(mychannel) < 0)
02792    {
02793       ast_log(LOG_WARNING, "Unable to start PBX!!\n");
02794       ast_hangup(mychannel);
02795       ast_hangup(genchannel);
02796       rpt_mutex_lock(&myrpt->lock);
02797       myrpt->callmode = 0;
02798       rpt_mutex_unlock(&myrpt->lock);
02799       pthread_exit(NULL);
02800    }
02801    usleep(10000);
02802    rpt_mutex_lock(&myrpt->lock);
02803    myrpt->callmode = 3;
02804    /* set appropriate conference for the pseudo */
02805    ci.chan = 0;
02806    ci.confno = myrpt->conf;
02807    ci.confmode = (myrpt->p.duplex == 2) ? ZT_CONF_CONFANNMON :
02808       (ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER);
02809    /* first put the channel on the conference in announce mode */
02810    if (ioctl(myrpt->pchannel->fds[0],ZT_SETCONF,&ci) == -1)
02811    {
02812       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
02813       ast_hangup(mychannel);
02814       ast_hangup(genchannel);
02815       myrpt->callmode = 0;
02816       pthread_exit(NULL);
02817    }
02818    while(myrpt->callmode)
02819    {
02820       if ((!mychannel->pbx) && (myrpt->callmode != 4))
02821       {
02822          if(myrpt->patchfarenddisconnect){ /* If patch is setup for far end disconnect */
02823             myrpt->callmode = 0;
02824             if(!myrpt->patchquiet){
02825                rpt_mutex_unlock(&myrpt->lock);
02826                rpt_telemetry(myrpt, TERM, NULL);
02827                rpt_mutex_lock(&myrpt->lock);
02828             }
02829          }
02830          else{ /* Send congestion until patch is downed by command */
02831             myrpt->callmode = 4;
02832             rpt_mutex_unlock(&myrpt->lock);
02833             /* start congestion tone */
02834             tone_zone_play_tone(genchannel->fds[0],ZT_TONE_CONGESTION);
02835             rpt_mutex_lock(&myrpt->lock);
02836          }
02837       }
02838       if (myrpt->mydtmf)
02839       {
02840          wf.frametype = AST_FRAME_DTMF;
02841          wf.subclass = myrpt->mydtmf;
02842          wf.offset = 0;
02843          wf.mallocd = 0;
02844          wf.data = NULL;
02845          wf.datalen = 0;
02846          wf.samples = 0;
02847          rpt_mutex_unlock(&myrpt->lock);
02848          ast_write(genchannel,&wf); 
02849          rpt_mutex_lock(&myrpt->lock);
02850          myrpt->mydtmf = 0;
02851       }
02852       rpt_mutex_unlock(&myrpt->lock);
02853       usleep(MSWAIT * 1000);
02854       rpt_mutex_lock(&myrpt->lock);
02855    }
02856    rpt_mutex_unlock(&myrpt->lock);
02857    tone_zone_play_tone(genchannel->fds[0],-1);
02858    if (mychannel->pbx) ast_softhangup(mychannel,AST_SOFTHANGUP_DEV);
02859    ast_hangup(genchannel);
02860    rpt_mutex_lock(&myrpt->lock);
02861    myrpt->callmode = 0;
02862    rpt_mutex_unlock(&myrpt->lock);
02863    /* set appropriate conference for the pseudo */
02864    ci.chan = 0;
02865    ci.confno = myrpt->conf;
02866    ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? ZT_CONF_CONFANNMON :
02867       (ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER);
02868    /* first put the channel on the conference in announce mode */
02869    if (ioctl(myrpt->pchannel->fds[0],ZT_SETCONF,&ci) == -1)
02870    {
02871       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
02872    }
02873    pthread_exit(NULL);
02874 }
02875 
02876 static void send_link_dtmf(struct rpt *myrpt,char c)
02877 {
02878 char  str[300];
02879 struct   ast_frame wf;
02880 struct   rpt_link *l;
02881 
02882    snprintf(str, sizeof(str), "D %s %s %d %c", myrpt->cmdnode, myrpt->name, ++(myrpt->dtmfidx), c);
02883    wf.frametype = AST_FRAME_TEXT;
02884    wf.subclass = 0;
02885    wf.offset = 0;
02886    wf.mallocd = 1;
02887    wf.datalen = strlen(str) + 1;
02888    wf.samples = 0;
02889    l = myrpt->links.next;
02890    /* first, see if our dude is there */
02891    while(l != &myrpt->links)
02892    {
02893       if (l->name[0] == '0') 
02894       {
02895          l = l->next;
02896          continue;
02897       }
02898       /* if we found it, write it and were done */
02899       if (!strcmp(l->name,myrpt->cmdnode))
02900       {
02901          wf.data = strdup(str);
02902          if (l->chan) ast_write(l->chan,&wf);
02903          return;
02904       }
02905       l = l->next;
02906    }
02907    l = myrpt->links.next;
02908    /* if not, give it to everyone */
02909    while(l != &myrpt->links)
02910    {
02911       wf.data = strdup(str);
02912       if (l->chan) ast_write(l->chan,&wf);
02913       l = l->next;
02914    }
02915    return;
02916 }
02917 
02918 /*
02919 * Internet linking function 
02920 */
02921 
02922 static int function_ilink(struct rpt *myrpt, char *param, char *digits, int command_source, struct rpt_link *mylink)
02923 {
02924 
02925    const char *val;
02926    char *s, *s1, *s2, *tele;
02927    char tmp[300], deststr[300] = "",modechange = 0;
02928    char digitbuf[MAXNODESTR];
02929    struct rpt_link *l;
02930    int reconnects = 0;
02931    ZT_CONFINFO ci;  /* conference info */
02932 
02933    if(!param)
02934       return DC_ERROR;
02935       
02936          
02937    if (!myrpt->enable)
02938       return DC_ERROR;
02939 
02940    ast_copy_string(digitbuf,digits,MAXNODESTR);
02941 
02942    if(debug)
02943       printf("@@@@ ilink param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
02944       
02945    switch(myatoi(param)){
02946       case 1: /* Link off */
02947          if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
02948             strcpy(digitbuf,myrpt->lastlinknode);
02949          val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
02950          if (!val){
02951             if(strlen(digitbuf) >= myrpt->longestnode)
02952                return DC_ERROR;
02953             break;
02954          }
02955          ast_copy_string(tmp,val,sizeof(tmp));
02956          s = tmp;
02957          s1 = strsep(&s,",");
02958          s2 = strsep(&s,",");
02959          rpt_mutex_lock(&myrpt->lock);
02960          l = myrpt->links.next;
02961          /* try to find this one in queue */
02962          while(l != &myrpt->links){
02963             if (l->name[0] == '0') 
02964             {
02965                l = l->next;
02966                continue;
02967             }
02968             /* if found matching string */
02969             if (!strcmp(l->name, digitbuf))
02970                break;
02971             l = l->next;
02972          }
02973          if (l != &myrpt->links){ /* if found */
02974             struct   ast_frame wf;
02975             ast_copy_string(myrpt->lastlinknode,digitbuf,MAXNODESTR);
02976             l->retries = MAX_RETRIES + 1;
02977             l->disced = 1;
02978             rpt_mutex_unlock(&myrpt->lock);
02979             wf.frametype = AST_FRAME_TEXT;
02980             wf.subclass = 0;
02981             wf.offset = 0;
02982             wf.mallocd = 1;
02983             wf.datalen = strlen(discstr) + 1;
02984             wf.samples = 0;
02985             wf.data = strdup(discstr);
02986             if (l->chan)
02987             {
02988                ast_write(l->chan,&wf);
02989                if (ast_safe_sleep(l->chan,250) == -1) return DC_ERROR;
02990                ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
02991             }
02992             rpt_telemetry(myrpt, COMPLETE, NULL);
02993             return DC_COMPLETE;
02994          }
02995          rpt_mutex_unlock(&myrpt->lock);  
02996          return DC_COMPLETE;
02997       case 2: /* Link Monitor */
02998          if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
02999             strcpy(digitbuf,myrpt->lastlinknode);
03000          val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
03001          if (!val){
03002             if(strlen(digitbuf) >= myrpt->longestnode)
03003                return DC_ERROR;
03004             break;
03005          }
03006          ast_copy_string(tmp, val, sizeof(tmp));
03007          s = tmp;
03008          s1 = strsep(&s,",");
03009          s2 = strsep(&s,",");
03010          rpt_mutex_lock(&myrpt->lock);
03011          l = myrpt->links.next;
03012          /* try to find this one in queue */
03013          while(l != &myrpt->links){
03014             if (l->name[0] == '0') 
03015             {
03016                l = l->next;
03017                continue;
03018             }
03019             /* if found matching string */
03020             if (!strcmp(l->name, digitbuf))
03021                break;
03022             l = l->next;
03023          }
03024          /* if found */
03025          if (l != &myrpt->links) 
03026          {
03027             /* if already in this mode, just ignore */
03028             if ((!l->mode) || (!l->chan)) {
03029                rpt_mutex_unlock(&myrpt->lock);
03030                rpt_telemetry(myrpt,REMALREADY,NULL);
03031                return DC_COMPLETE;
03032                
03033             }
03034             reconnects = l->reconnects;
03035             rpt_mutex_unlock(&myrpt->lock);
03036             if (l->chan) ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
03037             l->retries = MAX_RETRIES + 1;
03038             l->disced = 2;
03039             modechange = 1;
03040          } else
03041             rpt_mutex_unlock(&myrpt->lock);
03042          ast_copy_string(myrpt->lastlinknode,digitbuf,MAXNODESTR);
03043          /* establish call in monitor mode */
03044          l = malloc(sizeof(struct rpt_link));
03045          if (!l){
03046             ast_log(LOG_WARNING, "Unable to malloc\n");
03047             return DC_ERROR;
03048          }
03049          /* zero the silly thing */
03050          memset((char *)l,0,sizeof(struct rpt_link));
03051          snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
03052          tele = strchr(deststr,'/');
03053          if (!tele){
03054             fprintf(stderr,"link2:Dial number (%s) must be in format tech/number\n",deststr);
03055             return DC_ERROR;
03056          }
03057          *tele++ = 0;
03058          l->isremote = (s && ast_true(s));
03059          ast_copy_string(l->name, digitbuf, MAXNODESTR);
03060          l->chan = ast_request(deststr,AST_FORMAT_SLINEAR,tele,NULL);
03061          if (modechange) l->connected = 1;
03062          if (l->chan){
03063             ast_set_read_format(l->chan,AST_FORMAT_SLINEAR);
03064             ast_set_write_format(l->chan,AST_FORMAT_SLINEAR);
03065             l->chan->whentohangup = 0;
03066             l->chan->appl = "Apprpt";
03067             l->chan->data = "(Remote Rx)";
03068             if (option_verbose > 2)
03069                ast_verbose(VERBOSE_PREFIX_3 "rpt (remote) initiating call to %s/%s on %s\n",
03070                   deststr,tele,l->chan->name);
03071             if(l->chan->cid.cid_num)
03072                free(l->chan->cid.cid_num);
03073             l->chan->cid.cid_num = strdup(myrpt->name);
03074             ast_call(l->chan,tele,0);
03075          }
03076          else
03077          {
03078             rpt_telemetry(myrpt,CONNFAIL,l);
03079             free(l);
03080             if (option_verbose > 2)
03081                ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
03082                   deststr,tele,l->chan->name);
03083             return DC_ERROR;
03084          }
03085          /* allocate a pseudo-channel thru asterisk */
03086          l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
03087          if (!l->pchan){
03088             fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
03089             ast_hangup(l->chan);
03090             free(l);
03091             return DC_ERROR;
03092          }
03093          ast_set_read_format(l->pchan,AST_FORMAT_SLINEAR);
03094          ast_set_write_format(l->pchan,AST_FORMAT_SLINEAR);
03095          /* make a conference for the pseudo-one */
03096          ci.chan = 0;
03097          ci.confno = myrpt->conf;
03098          ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER;
03099          /* first put the channel on the conference in proper mode */
03100          if (ioctl(l->pchan->fds[0],ZT_SETCONF,&ci) == -1)
03101          {
03102             ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
03103             ast_hangup(l->chan);
03104             ast_hangup(l->pchan);
03105             free(l);
03106             return DC_ERROR;
03107          }
03108          rpt_mutex_lock(&myrpt->lock);
03109          l->reconnects = reconnects;
03110          /* insert at end of queue */
03111          insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
03112          rpt_mutex_unlock(&myrpt->lock);
03113          rpt_telemetry(myrpt,COMPLETE,NULL);
03114          return DC_COMPLETE;
03115       case 3: /* Link transceive */
03116          if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
03117             strcpy(digitbuf,myrpt->lastlinknode);
03118          val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
03119          if (!val){
03120             if(strlen(digitbuf) >= myrpt->longestnode)
03121                return DC_ERROR;
03122             break;
03123          }
03124          ast_copy_string(tmp,val,sizeof(tmp));
03125          s = tmp;
03126          s1 = strsep(&s,",");
03127          s2 = strsep(&s,",");
03128          rpt_mutex_lock(&myrpt->lock);
03129          l = myrpt->links.next;
03130          /* try to find this one in queue */
03131          while(l != &myrpt->links){
03132             if (l->name[0] == '0') 
03133             {
03134                l = l->next;
03135                continue;
03136             }
03137             /* if found matching string */
03138             if (!strcmp(l->name, digitbuf))
03139                break;
03140             l = l->next;
03141          }
03142          /* if found */
03143          if (l != &myrpt->links){ 
03144             /* if already in this mode, just ignore */
03145             if ((l->mode) || (!l->chan)) {
03146                rpt_mutex_unlock(&myrpt->lock);
03147                rpt_telemetry(myrpt, REMALREADY, NULL);
03148                return DC_COMPLETE;
03149             }
03150             reconnects = l->reconnects;
03151             rpt_mutex_unlock(&myrpt->lock);
03152             if (l->chan) ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
03153             l->retries = MAX_RETRIES + 1;
03154             l->disced = 2;
03155             modechange = 1;
03156          } else
03157             rpt_mutex_unlock(&myrpt->lock);
03158          ast_copy_string(myrpt->lastlinknode,digitbuf,MAXNODESTR);
03159          /* establish call in tranceive mode */
03160          l = malloc(sizeof(struct rpt_link));
03161          if (!l){
03162             ast_log(LOG_WARNING, "Unable to malloc\n");
03163             return(DC_ERROR);
03164          }
03165          /* zero the silly thing */
03166          memset((char *)l,0,sizeof(struct rpt_link));
03167          l->mode = 1;
03168          l->outbound = 1;
03169          ast_copy_string(l->name, digitbuf, MAXNODESTR);
03170          l->isremote = (s && ast_true(s));
03171          if (modechange) l->connected = 1;
03172          snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
03173          tele = strchr(deststr, '/');
03174          if (!tele){
03175             fprintf(stderr,"link3:Dial number (%s) must be in format tech/number\n",deststr);
03176             free(l);
03177             return DC_ERROR;
03178          }
03179          *tele++ = 0;
03180          l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele,NULL);
03181          if (l->chan){
03182             ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
03183             ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
03184             l->chan->whentohangup = 0;
03185             l->chan->appl = "Apprpt";
03186             l->chan->data = "(Remote Rx)";
03187             if (option_verbose > 2)
03188                ast_verbose(VERBOSE_PREFIX_3 "rpt (remote) initiating call to %s/%s on %s\n",
03189                   deststr, tele, l->chan->name);
03190             if(l->chan->cid.cid_num)
03191                free(l->chan->cid.cid_num);
03192             l->chan->cid.cid_num = strdup(myrpt->name);
03193             ast_call(l->chan,tele,999);
03194          }
03195          else{
03196             rpt_telemetry(myrpt,CONNFAIL,l);
03197             free(l);
03198             if (option_verbose > 2)
03199                ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
03200                   deststr,tele,l->chan->name);
03201             return DC_ERROR;
03202          }
03203          /* allocate a pseudo-channel thru asterisk */
03204          l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
03205          if (!l->pchan){
03206             fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
03207             ast_hangup(l->chan);
03208             free(l);
03209             return DC_ERROR;
03210          }
03211          ast_set_read_format(l->pchan, AST_FORMAT_SLINEAR);
03212          ast_set_write_format(l->pchan, AST_FORMAT_SLINEAR);
03213          /* make a conference for the tx */
03214          ci.chan = 0;
03215          ci.confno = myrpt->conf;
03216          ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER;
03217          /* first put the channel on the conference in proper mode */
03218          if (ioctl(l->pchan->fds[0], ZT_SETCONF, &ci) == -1)
03219          {
03220             ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
03221             ast_hangup(l->chan);
03222             ast_hangup(l->pchan);
03223             free(l);
03224             return DC_ERROR;
03225          }
03226          rpt_mutex_lock(&myrpt->lock);
03227          l->reconnects = reconnects;
03228          /* insert at end of queue */
03229          insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
03230          rpt_mutex_unlock(&myrpt->lock);
03231          rpt_telemetry(myrpt,COMPLETE,NULL);
03232          return DC_COMPLETE;
03233       case 4: /* Enter Command Mode */
03234       
03235          /* if doesnt allow link cmd, or no links active, return */
03236          if (((command_source != SOURCE_RPT) && (command_source != SOURCE_PHONE) && (command_source != SOURCE_DPHONE)) || (myrpt->links.next == &myrpt->links))
03237             return DC_COMPLETE;
03238          
03239          /* if already in cmd mode, or selected self, fughetabahtit */
03240          if ((myrpt->cmdnode[0]) || (!strcmp(myrpt->name, digitbuf))){
03241          
03242             rpt_telemetry(myrpt, REMALREADY, NULL);
03243             return DC_COMPLETE;
03244          }
03245          if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
03246             strcpy(digitbuf,myrpt->lastlinknode);
03247          /* node must at least exist in list */
03248          val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
03249          if (!val){
03250             if(strlen(digitbuf) >= myrpt->longestnode)
03251                return DC_ERROR;
03252             break;
03253          
03254          }
03255          rpt_mutex_lock(&myrpt->lock);
03256          strcpy(myrpt->lastlinknode,digitbuf);
03257          ast_copy_string(myrpt->cmdnode, digitbuf, sizeof(myrpt->cmdnode));
03258          rpt_mutex_unlock(&myrpt->lock);
03259          rpt_telemetry(myrpt, REMGO, NULL);  
03260          return DC_COMPLETE;
03261          
03262       case 5: /* Status */
03263          rpt_telemetry(myrpt, STATUS, NULL);
03264          return DC_COMPLETE;
03265          
03266          
03267       case 6: /* All Links Off */
03268          l = myrpt->links.next;
03269          
03270          while(l != &myrpt->links){ /* This code is broke and needs to be changed to work with the reconnect kludge */
03271             if (l->chan) ast_softhangup(l->chan, AST_SOFTHANGUP_DEV); /* Hang 'em up */
03272             l = l->next;
03273          }
03274          rpt_telemetry(myrpt, COMPLETE, NULL);
03275          break;
03276 
03277       case 7: /* Identify last node which keyed us up */
03278          rpt_telemetry(myrpt, LASTNODEKEY, NULL);
03279          break;
03280    
03281       default:
03282          return DC_ERROR;
03283          
03284    }
03285    
03286    return DC_INDETERMINATE;
03287 }  
03288 
03289 /*
03290 * Autopatch up
03291 */
03292 
03293 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
03294 {
03295    pthread_attr_t attr;
03296    int i, index, paramlength;
03297    char *lparam;
03298    char *value = NULL;
03299    char *paramlist[20];
03300 
03301    static char *keywords[] = {
03302    "context",
03303    "dialtime",
03304    "farenddisconnect",
03305    "noct",
03306    "quiet",
03307    NULL
03308    };
03309       
03310    if (!myrpt->enable)
03311       return DC_ERROR;
03312       
03313    if(debug)
03314       printf("@@@@ Autopatch up\n");
03315 
03316    if(!myrpt->callmode){
03317       /* Set defaults */
03318       myrpt->patchnoct = 0;
03319       myrpt->patchdialtime = 0;
03320       myrpt->patchfarenddisconnect = 0;
03321       myrpt->patchquiet = 0;
03322       ast_copy_string(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT);
03323 
03324       if(param){
03325          /* Process parameter list */
03326          lparam = ast_strdupa(param);
03327          if(!lparam){
03328             ast_log(LOG_ERROR,"App_rpt out of memory on line %d\n",__LINE__);
03329             return DC_ERROR;  
03330          }
03331          paramlength = finddelim(lparam, paramlist, 20);          
03332          for(i = 0; i < paramlength; i++){
03333             index = matchkeyword(paramlist[i], &value, keywords);
03334             if(value)
03335                value = skipchars(value, "= ");
03336             switch(index){
03337 
03338                case 1: /* context */
03339                   ast_copy_string(myrpt->patchcontext, value, MAXPATCHCONTEXT) ;
03340                   break;
03341                   
03342                case 2: /* dialtime */
03343                   myrpt->patchdialtime = atoi(value);
03344                   break;
03345 
03346                case 3: /* farenddisconnect */
03347                   myrpt->patchfarenddisconnect = atoi(value);
03348                   break;
03349 
03350                case 4:  /* noct */
03351                   myrpt->patchnoct = atoi(value);
03352                   break;
03353 
03354                case 5: /* quiet */
03355                   myrpt->patchquiet = atoi(value);
03356                   break;
03357                            
03358                default:
03359                   break;
03360             }
03361          }
03362       }
03363    }
03364                
03365    rpt_mutex_lock(&myrpt->lock);
03366 
03367    /* if on call, force * into current audio stream */
03368    
03369    if ((myrpt->callmode == 2) || (myrpt->callmode == 3)){
03370       myrpt->mydtmf = myrpt->p.funcchar;
03371    }
03372    if (myrpt->callmode){
03373       rpt_mutex_unlock(&myrpt->lock);
03374       return DC_COMPLETE;
03375    }
03376    myrpt->callmode = 1;
03377    myrpt->cidx = 0;
03378    myrpt->exten[myrpt->cidx] = 0;
03379    rpt_mutex_unlock(&myrpt->lock);
03380    pthread_attr_init(&attr);
03381    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
03382    ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *) myrpt);
03383    pthread_attr_destroy(&attr);
03384    return DC_COMPLETE;
03385 }
03386 
03387 /*
03388 * Autopatch down
03389 */
03390 
03391 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
03392 {
03393    if (!myrpt->enable)
03394       return DC_ERROR;
03395    
03396    if(debug)
03397       printf("@@@@ Autopatch down\n");
03398       
03399    rpt_mutex_lock(&myrpt->lock);
03400    
03401    if (!myrpt->callmode){
03402       rpt_mutex_unlock(&myrpt->lock);
03403       return DC_COMPLETE;
03404    }
03405    
03406    myrpt->callmode = 0;
03407    rpt_mutex_unlock(&myrpt->lock);
03408    rpt_telemetry(myrpt, TERM, NULL);
03409    return DC_COMPLETE;
03410 }
03411 
03412 /*
03413 * Status
03414 */
03415 
03416 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
03417 {
03418 
03419    if (!param)
03420       return DC_ERROR;
03421 
03422    if (!myrpt->enable)
03423       return DC_ERROR;
03424 
03425    if(debug)
03426       printf("@@@@ status param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
03427    
03428    switch(myatoi(param)){
03429       case 1: /* System ID */
03430          rpt_telemetry(myrpt, ID1, NULL);
03431          return DC_COMPLETE;
03432       case 2: /* System Time */
03433          rpt_telemetry(myrpt, STATS_TIME, NULL);
03434          return DC_COMPLETE;
03435       case 3: /* app_rpt.c version */
03436          rpt_telemetry(myrpt, STATS_VERSION, NULL);
03437       default:
03438          return DC_ERROR;
03439    }
03440    return DC_INDETERMINATE;
03441 }
03442 
03443 /*
03444 *  Macro-oni (without Salami)
03445 */
03446 
03447 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
03448 {
03449 
03450    const char  *val;
03451 int   i;
03452 struct   ast_channel *mychannel;
03453 
03454    if ((!myrpt->remote) && (!myrpt->enable))
03455       return DC_ERROR;
03456 
03457    if(debug) 
03458       printf("@@@@ macro-oni param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
03459    
03460    mychannel = myrpt->remchannel;
03461 
03462    if(strlen(digitbuf) < 1) /* needs 1 digit */
03463       return DC_INDETERMINATE;
03464          
03465    for(i = 0 ; i < digitbuf[i] ; i++) {
03466       if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
03467          return DC_ERROR;
03468    }
03469    
03470    if (*digitbuf == '0') val = myrpt->p.startupmacro;
03471    else val = ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, digitbuf);
03472    /* param was 1 for local buf */
03473    if (!val){
03474       rpt_telemetry(myrpt, MACRO_NOTFOUND, NULL);
03475       return DC_COMPLETE;
03476    }        
03477    rpt_mutex_lock(&myrpt->lock);
03478    if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(val))
03479    {
03480       rpt_mutex_unlock(&myrpt->lock);
03481       rpt_telemetry(myrpt, MACRO_BUSY, NULL);
03482       return DC_ERROR;
03483    }
03484    myrpt->macrotimer = MACROTIME;
03485    strncat(myrpt->macrobuf,val,MAXMACRO - 1);
03486    rpt_mutex_unlock(&myrpt->lock);
03487    return DC_COMPLETE;  
03488 }
03489 
03490 /*
03491 * COP - Control operator
03492 */
03493 
03494 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
03495 {
03496    if(!param)
03497       return DC_ERROR;
03498    
03499    switch(myatoi(param)){
03500       case 1: /* System reset */
03501          system("killall -9 asterisk"); /* FIXME to drastic? */
03502          return DC_COMPLETE;
03503 
03504       case 2:
03505          myrpt->enable = 1;
03506          rpt_telemetry(myrpt, ARB_ALPHA, (void *) "RPTENA");
03507          return DC_COMPLETE;
03508          
03509       case 3:
03510          myrpt->enable = 0;
03511          return DC_COMPLETE;
03512          
03513       case 4: /* test tone on */
03514          rpt_telemetry(myrpt, TEST_TONE, NULL);
03515          return DC_COMPLETE;
03516 
03517       case 5: /* Disgorge variables to log for debug purposes */
03518          myrpt->disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
03519          return DC_COMPLETE;
03520 
03521       case 6: /* Simulate COR being activated (phone only) */
03522          if (command_source != SOURCE_PHONE) return DC_INDETERMINATE;
03523          return DC_DOKEY;  
03524 
03525    }  
03526    return DC_INDETERMINATE;
03527 }
03528 
03529 /*
03530 * Collect digits one by one until something matches
03531 */
03532 
03533 static int collect_function_digits(struct rpt *myrpt, char *digits, 
03534    int command_source, struct rpt_link *mylink)
03535 {
03536    int i;
03537    char *stringp,*action,*param,*functiondigits;
03538    char function_table_name[30] = "";
03539    char workstring[200];
03540    
03541    struct ast_variable *vp;
03542    
03543    if(debug)   
03544       printf("@@@@ Digits collected: %s, source: %d\n", digits, command_source);
03545    
03546    if (command_source == SOURCE_DPHONE) {
03547       if (!myrpt->p.dphone_functions) return DC_INDETERMINATE;
03548       ast_copy_string(function_table_name, myrpt->p.dphone_functions, sizeof(function_table_name));
03549       }
03550    else if (command_source == SOURCE_PHONE) {
03551       if (!myrpt->p.phone_functions) return DC_INDETERMINATE;
03552       ast_copy_string(function_table_name, myrpt->p.phone_functions, sizeof(function_table_name));
03553       }
03554    else if (command_source == SOURCE_LNK)
03555       ast_copy_string(function_table_name, myrpt->p.link_functions, sizeof(function_table_name));
03556    else
03557       ast_copy_string(function_table_name, myrpt->p.functions, sizeof(function_table_name));
03558    vp = ast_variable_browse(myrpt->cfg, function_table_name);
03559    while(vp) {
03560       if(!strncasecmp(vp->name, digits, strlen(vp->name)))
03561          break;
03562       vp = vp->next;
03563    }  
03564    if(!vp) {
03565       int n;
03566 
03567       n = myrpt->longestfunc;
03568       if (command_source == SOURCE_LNK) n = myrpt->link_longestfunc;
03569       else 
03570       if (command_source == SOURCE_PHONE) n = myrpt->phone_longestfunc;
03571       else 
03572       if (command_source == SOURCE_DPHONE) n = myrpt->dphone_longestfunc;
03573       
03574       if(strlen(digits) >= n)
03575          return DC_ERROR;
03576       else
03577          return DC_INDETERMINATE;
03578    }  
03579    /* Found a match, retrieve value part and parse */
03580    ast_copy_string(workstring, vp->value, sizeof(workstring));
03581    stringp = workstring;
03582    action = strsep(&stringp, ",");
03583    param = stringp;
03584    if(debug)
03585       printf("@@@@ action: %s, param = %s\n",action, (param) ? param : "(null)");
03586    /* Look up the action */
03587    for(i = 0 ; i < (sizeof(function_table)/sizeof(struct function_table_tag)); i++){
03588       if(!strncasecmp(action, function_table[i].action, strlen(action)))
03589          break;
03590    }
03591    if(debug)
03592       printf("@@@@ table index i = %d\n",i);
03593    if(i == (sizeof(function_table)/sizeof(struct function_table_tag))){
03594       /* Error, action not in table */
03595       return DC_ERROR;
03596    }
03597    if(function_table[i].function == NULL){
03598       /* Error, function undefined */
03599       if(debug)
03600          printf("@@@@ NULL for action: %s\n",action);
03601       return DC_ERROR;
03602    }
03603    functiondigits = digits + strlen(vp->name);
03604    return (*function_table[i].function)(myrpt, param, functiondigits, command_source, mylink);
03605 }
03606 
03607 
03608 static void handle_link_data(struct rpt *myrpt, struct rpt_link *mylink,
03609    char *str)
03610 {
03611 char  tmp[300],cmd[300] = "",dest[300],src[300],c;
03612 int   seq, res;
03613 struct rpt_link *l;
03614 struct   ast_frame wf;
03615 
03616    wf.frametype = AST_FRAME_TEXT;
03617    wf.subclass = 0;
03618    wf.offset = 0;
03619    wf.mallocd = 1;
03620    wf.datalen = strlen(str) + 1;
03621    wf.samples = 0;
03622    /* put string in our buffer */
03623    ast_copy_string(tmp, str, sizeof(tmp));
03624 
03625         if (!strcmp(tmp,discstr))
03626         {
03627                 mylink->disced = 1;
03628       mylink->retries = MAX_RETRIES + 1;
03629                 ast_softhangup(mylink->chan,AST_SOFTHANGUP_DEV);
03630                 return;
03631         }
03632    if (sscanf(tmp,"%s %s %s %d %c",cmd,dest,src,&seq,&c) != 5)
03633    {
03634       ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
03635       return;
03636    }
03637    if (strcmp(cmd,"D"))
03638    {
03639       ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
03640       return;
03641    }
03642 
03643    if (dest[0] == '0')
03644    {
03645       strcpy(dest,myrpt->name);
03646    }     
03647 
03648    /* if not for me, redistribute to all links */
03649    if (strcmp(dest,myrpt->name))
03650    {
03651       l = myrpt->links.next;
03652       /* see if this is one in list */
03653       while(l != &myrpt->links)
03654       {
03655          if (l->name[0] == '0') 
03656          {
03657             l = l->next;
03658             continue;
03659          }
03660          /* dont send back from where it came */
03661          if ((l == mylink) || (!strcmp(l->name,mylink->name)))
03662          {
03663             l = l->next;
03664             continue;
03665          }
03666          /* if it is, send it and we're done */
03667          if (!strcmp(l->name,dest))
03668          {
03669             /* send, but not to src */
03670             if (strcmp(l->name,src)) {
03671                wf.data = strdup(str);
03672                if (l->chan) ast_write(l->chan,&wf);
03673             }
03674             return;
03675          }
03676          l = l->next;
03677       }
03678       l = myrpt->links.next;
03679       /* otherwise, send it to all of em */
03680       while(l != &myrpt->links)
03681       {
03682          if (l->name[0] == '0') 
03683          {
03684             l = l->next;
03685             continue;
03686          }
03687          /* dont send back from where it came */
03688          if ((l == mylink) || (!strcmp(l->name,mylink->name)))
03689          {
03690             l = l->next;
03691             continue;
03692          }
03693          /* send, but not to src */
03694          if (strcmp(l->name,src)) {
03695             wf.data = strdup(str);
03696             if (l->chan) ast_write(l->chan,&wf);
03697          }
03698          l = l->next;
03699       }
03700       return;
03701    }
03702    rpt_mutex_lock(&myrpt->lock);
03703    if (c == myrpt->p.endchar) myrpt->stopgen = 1;
03704    if (myrpt->callmode == 1)
03705    {
03706       myrpt->exten[myrpt->cidx++] = c;
03707       myrpt->exten[myrpt->cidx] = 0;
03708       /* if this exists */
03709       if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
03710       {
03711          myrpt->callmode = 2;
03712          if(!myrpt->patchquiet){
03713             rpt_mutex_unlock(&myrpt->lock);
03714             rpt_telemetry(myrpt,PROC,NULL); 
03715             rpt_mutex_lock(&myrpt->lock);
03716          }
03717       }
03718       /* if can continue, do so */
03719       if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL)) 
03720       {
03721          /* call has failed, inform user */
03722          myrpt->callmode = 4;
03723       }
03724    }
03725    if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
03726    {
03727       myrpt->mydtmf = c;
03728    }
03729    if (c == myrpt->p.funcchar)
03730    {
03731       myrpt->rem_dtmfidx = 0;
03732       myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
03733       time(&myrpt->rem_dtmf_time);
03734       rpt_mutex_unlock(&myrpt->lock);
03735       return;
03736    } 
03737    else if ((c != myrpt->p.endchar) && (myrpt->rem_dtmfidx >= 0))
03738    {
03739       time(&myrpt->rem_dtmf_time);
03740       if (myrpt->rem_dtmfidx < MAXDTMF)
03741       {
03742          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
03743          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
03744          
03745          rpt_mutex_unlock(&myrpt->lock);
03746          ast_copy_string(cmd, myrpt->rem_dtmfbuf, sizeof(cmd));
03747          res = collect_function_digits(myrpt, cmd, SOURCE_LNK, mylink);
03748          rpt_mutex_lock(&myrpt->lock);
03749          
03750          switch(res){
03751 
03752             case DC_INDETERMINATE:
03753                break;
03754             
03755             case DC_REQ_FLUSH:
03756                myrpt->rem_dtmfidx = 0;
03757                myrpt->rem_dtmfbuf[0] = 0;
03758                break;
03759             
03760             
03761             case DC_COMPLETE:
03762                myrpt->totalexecdcommands++;
03763                myrpt->dailyexecdcommands++;
03764                ast_copy_string(myrpt->lastdtmfcommand, cmd, MAXDTMF);
03765                myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
03766                myrpt->rem_dtmfbuf[0] = 0;
03767                myrpt->rem_dtmfidx = -1;
03768                myrpt->rem_dtmf_time = 0;
03769                break;
03770             
03771             case DC_ERROR:
03772             default:
03773                myrpt->rem_dtmfbuf[0] = 0;
03774                myrpt->rem_dtmfidx = -1;
03775                myrpt->rem_dtmf_time = 0;
03776                break;
03777          }
03778       }
03779 
03780    }
03781    rpt_mutex_unlock(&myrpt->lock);
03782    return;
03783 }
03784 
03785 static void handle_link_phone_dtmf(struct rpt *myrpt, struct rpt_link *mylink,
03786    char c)
03787 {
03788 
03789 char  cmd[300];
03790 int   res;
03791 
03792    rpt_mutex_lock(&myrpt->lock);
03793    if (c == myrpt->p.endchar)
03794    {
03795       if (mylink->lastrx)
03796       {
03797          mylink->lastrx = 0;
03798          rpt_mutex_unlock(&myrpt->lock);
03799          return;
03800       }
03801       myrpt->stopgen = 1;
03802       if (myrpt->cmdnode[0])
03803       {
03804          myrpt->cmdnode[0] = 0;
03805          myrpt->dtmfidx = -1;
03806          myrpt->dtmfbuf[0] = 0;
03807          rpt_mutex_unlock(&myrpt->lock);
03808          rpt_telemetry(myrpt,COMPLETE,NULL);
03809          return;
03810       }
03811    }
03812    if (myrpt->cmdnode[0])
03813    {
03814       rpt_mutex_unlock(&myrpt->lock);
03815       send_link_dtmf(myrpt,c);
03816       return;
03817    }
03818    if (myrpt->callmode == 1)
03819    {
03820       myrpt->exten[myrpt->cidx++] = c;
03821       myrpt->exten[myrpt->cidx] = 0;
03822       /* if this exists */
03823       if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
03824       {
03825          myrpt->callmode = 2;
03826          if(!myrpt->patchquiet){
03827             rpt_mutex_unlock(&myrpt->lock);
03828             rpt_telemetry(myrpt,PROC,NULL); 
03829             rpt_mutex_lock(&myrpt->lock);
03830          }
03831       }
03832       /* if can continue, do so */
03833       if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL)) 
03834       {
03835          /* call has failed, inform user */
03836          myrpt->callmode = 4;
03837       }
03838    }
03839    if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
03840    {
03841       myrpt->mydtmf = c;
03842    }
03843    if (c == myrpt->p.funcchar)
03844    {
03845       myrpt->rem_dtmfidx = 0;
03846       myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
03847       time(&myrpt->rem_dtmf_time);
03848       rpt_mutex_unlock(&myrpt->lock);
03849       return;
03850    } 
03851    else if ((c != myrpt->p.endchar) && (myrpt->rem_dtmfidx >= 0))
03852    {
03853       time(&myrpt->rem_dtmf_time);
03854       if (myrpt->rem_dtmfidx < MAXDTMF)
03855       {
03856          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
03857          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
03858          
03859          rpt_mutex_unlock(&myrpt->lock);
03860          ast_copy_string(cmd, myrpt->rem_dtmfbuf, sizeof(cmd));
03861          switch(mylink->phonemode)
03862          {
03863              case 1:
03864             res = collect_function_digits(myrpt, cmd, 
03865                SOURCE_PHONE, mylink);
03866             break;
03867              case 2:
03868             res = collect_function_digits(myrpt, cmd, 
03869                SOURCE_DPHONE,mylink);
03870             break;
03871              default:
03872             res = collect_function_digits(myrpt, cmd, 
03873                SOURCE_LNK, mylink);
03874             break;
03875          }
03876 
03877          rpt_mutex_lock(&myrpt->lock);
03878          
03879          switch(res){
03880 
03881             case DC_INDETERMINATE:
03882                break;
03883             
03884             case DC_DOKEY:
03885                mylink->lastrx = 1;
03886                break;
03887             
03888             case DC_REQ_FLUSH:
03889                myrpt->rem_dtmfidx = 0;
03890                myrpt->rem_dtmfbuf[0] = 0;
03891                break;
03892             
03893             
03894             case DC_COMPLETE:
03895                myrpt->totalexecdcommands++;
03896                myrpt->dailyexecdcommands++;
03897                ast_copy_string(myrpt->lastdtmfcommand, cmd, MAXDTMF);
03898                myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
03899                myrpt->rem_dtmfbuf[0] = 0;
03900                myrpt->rem_dtmfidx = -1;
03901                myrpt->rem_dtmf_time = 0;
03902                break;
03903             
03904             case DC_ERROR:
03905             default:
03906                myrpt->rem_dtmfbuf[0] = 0;
03907                myrpt->rem_dtmfidx = -1;
03908                myrpt->rem_dtmf_time = 0;
03909                break;
03910          }
03911       }
03912 
03913    }
03914    rpt_mutex_unlock(&myrpt->lock);
03915    return;
03916 }
03917 
03918 /* Doug Hall RBI-1 serial data definitions:
03919  *
03920  * Byte 0: Expansion external outputs 
03921  * Byte 1: 
03922  * Bits 0-3 are BAND as follows:
03923  * Bits 4-5 are POWER bits as follows:
03924  *    00 - Low Power
03925  *    01 - Hi Power
03926  *    02 - Med Power
03927  * Bits 6-7 are always set
03928  * Byte 2:
03929  * Bits 0-3 MHZ in BCD format
03930  * Bits 4-5 are offset as follows:
03931  *    00 - minus
03932  *    01 - plus
03933  *    02 - simplex
03934  *    03 - minus minus (whatever that is)
03935  * Bit 6 is the 0/5 KHZ bit
03936  * Bit 7 is always set
03937  * Byte 3:
03938  * Bits 0-3 are 10 KHZ in BCD format
03939  * Bits 4-7 are 100 KHZ in BCD format
03940  * Byte 4: PL Tone code and encode/decode enable bits
03941  * Bits 0-5 are PL tone code (comspec binary codes)
03942  * Bit 6 is encode enable/disable
03943  * Bit 7 is decode enable/disable
03944  */
03945 
03946 /* take the frequency from the 10 mhz digits (and up) and convert it
03947    to a band number */
03948 
03949 static int rbi_mhztoband(char *str)
03950 {
03951 int   i;
03952 
03953    i = atoi(str) / 10; /* get the 10's of mhz */
03954    switch(i)
03955    {
03956        case 2:
03957       return 10;
03958        case 5:
03959       return 11;
03960        case 14:
03961       return 2;
03962        case 22:
03963       return 3;
03964        case 44:
03965       return 4;
03966        case 124:
03967       return 0;
03968        case 125:
03969       return 1;
03970        case 126:
03971       return 8;
03972        case 127:
03973       return 5;
03974        case 128:
03975       return 6;
03976        case 129:
03977       return 7;
03978        default:
03979       break;
03980    }
03981    return -1;
03982 }
03983 
03984 /* take a PL frequency and turn it into a code */
03985 static int rbi_pltocode(char *str)
03986 {
03987 int i;
03988 char *s;
03989 
03990    s = strchr(str,'.');
03991    i = 0;
03992    if (s) i = atoi(s + 1);
03993    i += atoi(str) * 10;
03994    switch(i)
03995    {
03996        case 670:
03997       return 0;
03998        case 719:
03999       return 1;
04000        case 744:
04001       return 2;
04002        case 770:
04003       return 3;
04004        case 797:
04005       return 4;
04006        case 825:
04007       return 5;
04008        case 854:
04009       return 6;
04010        case 885:
04011       return 7;
04012        case 915:
04013       return 8;
04014        case 948:
04015       return 9;
04016        case 974:
04017       return 10;
04018        case 1000:
04019       return 11;
04020        case 1035:
04021       return 12;
04022        case 1072:
04023       return 13;
04024        case 1109:
04025       return 14;
04026        case 1148:
04027       return 15;
04028        case 1188:
04029       return 16;
04030        case 1230:
04031       return 17;
04032        case 1273:
04033       return 18;
04034        case 1318:
04035       return 19;
04036        case 1365:
04037       return 20;
04038        case 1413:
04039       return 21;
04040        case 1462:
04041       return 22;
04042        case 1514:
04043       return 23;
04044        case 1567:
04045       return 24;
04046        case 1622:
04047       return 25;
04048        case 1679:
04049       return 26;
04050        case 1738:
04051       return 27;
04052        case 1799:
04053       return 28;
04054        case 1862:
04055       return 29;
04056        case 1928:
04057       return 30;
04058        case 2035:
04059       return 31;
04060        case 2107:
04061       return 32;
04062        case 2181:
04063       return 33;
04064        case 2257:
04065       return 34;
04066        case 2336:
04067       return 35;
04068        case 2418:
04069       return 36;
04070        case 2503:
04071       return 37;
04072    }
04073    return -1;
04074 }
04075 
04076 /*
04077 * Shift out a formatted serial bit stream
04078 */
04079 
04080 static void rbi_out_parallel(struct rpt *myrpt,unsigned char *data)
04081     {
04082     int i,j;
04083     unsigned char od,d;
04084     static volatile long long delayvar;
04085 
04086     for(i = 0 ; i < 5 ; i++){
04087         od = *data++; 
04088         for(j = 0 ; j < 8 ; j++){
04089             d = od & 1;
04090             outb(d,myrpt->p.iobase);
04091        /* >= 15 us */
04092        for(delayvar = 1; delayvar < 15000; delayvar++); 
04093             od >>= 1;
04094             outb(d | 2,myrpt->p.iobase);
04095        /* >= 30 us */
04096        for(delayvar = 1; delayvar < 30000; delayvar++); 
04097             outb(d,myrpt->p.iobase);
04098        /* >= 10 us */
04099        for(delayvar = 1; delayvar < 10000; delayvar++); 
04100             }
04101         }
04102    /* >= 50 us */
04103         for(delayvar = 1; delayvar < 50000; delayvar++); 
04104     }
04105 
04106 static void rbi_out(struct rpt *myrpt,unsigned char *data)
04107 {
04108 struct zt_radio_param r;
04109 
04110    memset(&r,0,sizeof(struct zt_radio_param));
04111    r.radpar = ZT_RADPAR_REMMODE;
04112    r.data = ZT_RADPAR_REM_RBI1;
04113    /* if setparam ioctl fails, its probably not a pciradio card */
04114    if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&r) == -1)
04115    {
04116       rbi_out_parallel(myrpt,data);
04117       return;
04118    }
04119    r.radpar = ZT_RADPAR_REMCOMMAND;
04120    memcpy(&r.data,data,5);
04121    if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&r) == -1)
04122    {
04123       ast_log(LOG_WARNING,"Cannot send RBI command for channel %s\n",myrpt->rxchannel->name);
04124       return;
04125    }
04126 }
04127 
04128 static int serial_remote_io(struct rpt *myrpt, unsigned char *txbuf, int txbytes, char *rxbuf,
04129         int rxmaxbytes, int asciiflag)
04130 {
04131    int i;
04132    struct zt_radio_param prm;
04133 
04134    if(debug){
04135       printf("String output was: ");
04136       for(i = 0; i < txbytes; i++)
04137          printf("%02X ", (unsigned char ) txbuf[i]);
04138       printf("\n");
04139    }
04140 
04141         prm.radpar = ZT_RADPAR_REMMODE;
04142         if (asciiflag)  prm.data = ZT_RADPAR_REM_SERIAL_ASCII;
04143         else prm.data = ZT_RADPAR_REM_SERIAL;
04144    if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&prm) == -1) return -1;
04145         prm.radpar = ZT_RADPAR_REMCOMMAND;
04146         prm.data = rxmaxbytes;
04147         memcpy(prm.buf,txbuf,txbytes);
04148         prm.index = txbytes;
04149    if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&prm) == -1) return -1;
04150         if (rxbuf)
04151         {
04152                 *rxbuf = 0;
04153                 memcpy(rxbuf,prm.buf,prm.index);
04154         }
04155         return(prm.index);
04156 }
04157 
04158 static int setrbi(struct rpt *myrpt)
04159 {
04160 char tmp[MAXREMSTR] = "",*s;
04161 unsigned char rbicmd[5];
04162 int   band,txoffset = 0,txpower = 0,txpl;
04163 
04164    /* must be a remote system */
04165    if (!myrpt->remote) return(0);
04166    /* must have rbi hardware */
04167    if (strncmp(myrpt->remote,remote_rig_rbi,3)) return(0);
04168    ast_copy_string(tmp, myrpt->freq, sizeof(tmp));
04169    s = strchr(tmp,'.');
04170    /* if no decimal, is invalid */
04171    
04172    if (s == NULL){
04173       if(debug)
04174          printf("@@@@ Frequency needs a decimal\n");
04175       return -1;
04176    }
04177    
04178    *s++ = 0;
04179    if (strlen(tmp) < 2){
04180       if(debug)
04181          printf("@@@@ Bad MHz digits: %s\n", tmp);
04182       return -1;
04183    }
04184     
04185    if (strlen(s) < 3){
04186       if(debug)
04187          printf("@@@@ Bad KHz digits: %s\n", s);
04188       return -1;
04189    }
04190 
04191    if ((s[2] != '0') && (s[2] != '5')){
04192       if(debug)
04193          printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
04194       return -1;
04195    }
04196     
04197    band = rbi_mhztoband(tmp);
04198    if (band == -1){
04199       if(debug)
04200          printf("@@@@ Bad Band: %s\n", tmp);
04201       return -1;
04202    }
04203    
04204    txpl = rbi_pltocode(myrpt->txpl);
04205    
04206    if (txpl == -1){
04207       if(debug)
04208          printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
04209       return -1;
04210    }
04211 
04212    
04213    switch(myrpt->offset)
04214    {
04215        case REM_MINUS:
04216       txoffset = 0;
04217       break;
04218        case REM_PLUS:
04219       txoffset = 0x10;
04220       break;
04221        case REM_SIMPLEX:
04222       txoffset = 0x20;
04223       break;
04224    }
04225    switch(myrpt->powerlevel)
04226    {
04227        case REM_LOWPWR:
04228       txpower = 0;
04229       break;
04230        case REM_MEDPWR:
04231       txpower = 0x20;
04232       break;
04233        case REM_HIPWR:
04234       txpower = 0x10;
04235       break;
04236    }
04237    rbicmd[0] = 0;
04238    rbicmd[1] = band | txpower | 0xc0;
04239    rbicmd[2] = (*(s - 2) - '0') | txoffset | 0x80;
04240    if (s[2] == '5') rbicmd[2] |= 0x40;
04241    rbicmd[3] = ((*s - '0') << 4) + (s[1] - '0');
04242    rbicmd[4] = txpl;
04243    if (myrpt->txplon) rbicmd[4] |= 0x40;
04244    if (myrpt->rxplon) rbicmd[4] |= 0x80;
04245    rbi_out(myrpt,rbicmd);
04246    return 0;
04247 }
04248 
04249 
04250 /* Check for valid rbi frequency */
04251 /* Hard coded limits now, configurable later, maybe? */
04252 
04253 static int check_freq_rbi(int m, int d, int *defmode)
04254 {
04255    int dflmd = REM_MODE_FM;
04256 
04257    if(m == 50){ /* 6 meters */
04258       if(d < 10100)
04259          return -1;
04260    }
04261    else if((m >= 51) && ( m < 54)){
04262                 ;
04263    }
04264    else if(m == 144){ /* 2 meters */
04265       if(d < 10100)
04266          return -1;
04267    }
04268    else if((m >= 145) && (m < 148)){
04269       ;
04270    }
04271    else if((m >= 222) && (m < 225)){ /* 1.25 meters */
04272       ;
04273    }
04274    else if((m >= 430) && (m < 450)){ /* 70 centimeters */
04275       ;
04276    }
04277    else if((m >= 1240) && (m < 1300)){ /* 23 centimeters */
04278       ;
04279    }
04280    else
04281       return -1;
04282    
04283    if(defmode)
04284       *defmode = dflmd; 
04285 
04286 
04287    return 0;
04288 }
04289 
04290 /*
04291 * Split frequency into mhz and decimals
04292 */
04293  
04294 static int split_freq(char *mhz, char *decimals, char *freq)
04295 {
04296    char *decp;
04297 
04298    freq = ast_strdupa(freq);
04299    if ((decp = strchr(freq, '.'))) {
04300       *decp++ = 0;
04301       ast_copy_string(mhz, freq, MAXREMSTR);
04302       strcpy(decimals, "00000");
04303       ast_copy_string(decimals, decp, 6);
04304       return 0;
04305    }
04306    else
04307       return -1;
04308 
04309 }
04310    
04311 /*
04312 * Split ctcss frequency into hertz and decimal
04313 */
04314  
04315 static int split_ctcss_freq(char *hertz, char *decimal, char *freq)
04316 {
04317    char *decp;
04318 
04319    freq = ast_strdupa(freq);
04320    if ((decp = strchr(freq, '.'))) {
04321       *decp++ = 0;
04322       ast_copy_string(hertz, freq, MAXREMSTR);
04323       ast_copy_string(decimal, decp, sizeof(decimal));
04324       return 0;
04325    }
04326    else
04327       return -1;
04328 }
04329 
04330 
04331 
04332 /*
04333 * FT-897 I/O handlers
04334 */
04335 
04336 /* Check to see that the frequency is valid */
04337 /* Hard coded limits now, configurable later, maybe? */
04338 
04339 
04340 static int check_freq_ft897(int m, int d, int *defmode)
04341 {
04342    int dflmd = REM_MODE_FM;
04343 
04344    if(m == 1){ /* 160 meters */
04345       dflmd =  REM_MODE_LSB; 
04346       if(d < 80001)
04347          return -1;
04348    }
04349    else if(m == 3){ /* 80 meters */
04350       dflmd = REM_MODE_LSB;
04351       if(d < 75001)
04352          return -1;
04353    }
04354    else if(m == 7){ /* 40 meters */
04355       dflmd = REM_MODE_LSB;
04356       if((d < 15001) || (d > 29999))
04357          return -1;
04358    }
04359    else if(m == 14){ /* 20 meters */
04360       dflmd = REM_MODE_USB;
04361       if((d < 15001) || (d > 34999))
04362          return -1;
04363    }
04364    else if(m == 18){ /* 17 meters */
04365       dflmd = REM_MODE_USB;
04366       if((d < 11001) || (d > 16797))
04367          return -1;
04368    }
04369    else if(m == 21){ /* 15 meters */
04370       dflmd = REM_MODE_USB;
04371       if((d < 20001) || (d > 44999))
04372          return -1;
04373    }
04374    else if(m == 24){ /* 12 meters */
04375       dflmd = REM_MODE_USB;
04376       if((d < 93001) || (d > 98999))
04377          return -1;
04378    }
04379    else if(m == 28){ /* 10 meters */
04380       dflmd = REM_MODE_USB;
04381       if(d < 30001)
04382          return -1;
04383    }
04384    else if(m == 29){ 
04385       if(d >= 51000)
04386          dflmd = REM_MODE_FM;
04387       else
04388          dflmd = REM_MODE_USB;
04389       if(d > 69999)
04390          return -1;
04391    }
04392    else if(m == 50){ /* 6 meters */
04393       if(d < 10100)
04394          return -1;
04395       if(d >= 30000)
04396          dflmd = REM_MODE_FM;
04397       else
04398          dflmd = REM_MODE_USB;
04399 
04400    }
04401    else if((m >= 51) && ( m < 54)){
04402       dflmd = REM_MODE_FM;
04403    }
04404    else if(m == 144){ /* 2 meters */
04405       if(d < 10100)
04406          return -1;
04407       if(d >= 30000)
04408          dflmd = REM_MODE_FM;
04409       else
04410          dflmd = REM_MODE_USB;
04411    }
04412    else if((m >= 145) && (m < 148)){
04413       dflmd = REM_MODE_FM;
04414    }
04415    else if((m >= 430) && (m < 450)){ /* 70 centimeters */
04416       if(m  < 438)
04417          dflmd = REM_MODE_USB;
04418       else
04419          dflmd = REM_MODE_FM;
04420       ;
04421    }
04422    else
04423       return -1;
04424 
04425    if(defmode)
04426       *defmode = dflmd;
04427 
04428    return 0;
04429 }
04430 
04431 /*
04432 * Set a new frequency for the FT897
04433 */
04434 
04435 static int set_freq_ft897(struct rpt *myrpt, char *newfreq)
04436 {
04437    char mhz[MAXREMSTR];
04438    char decimals[MAXREMSTR];
04439    unsigned char cmdstr[5];
04440    int fd,m,d;
04441 
04442    fd = 0;
04443    if(debug) 
04444       printf("New frequency: %s\n",newfreq);
04445 
04446    if(split_freq(mhz, decimals, newfreq))
04447       return -1; 
04448 
04449    m = atoi(mhz);
04450    d = atoi(decimals);
04451 
04452    /* The FT-897 likes packed BCD frequencies */
04453 
04454    cmdstr[0] = ((m / 100) << 4) + ((m % 100)/10);        /* 100MHz 10Mhz */
04455    cmdstr[1] = ((m % 10) << 4) + (d / 10000);         /* 1MHz 100KHz */
04456    cmdstr[2] = (((d % 10000)/1000) << 4) + ((d % 1000)/ 100);  /* 10KHz 1KHz */
04457    cmdstr[3] = (((d % 100)/10) << 4) + (d % 10);         /* 100Hz 10Hz */
04458    cmdstr[4] = 0x01;                /* command */
04459 
04460    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
04461 
04462 }
04463 
04464 /* ft-897 simple commands */
04465 
04466 static int simple_command_ft897(struct rpt *myrpt, char command)
04467 {
04468    unsigned char cmdstr[5];
04469    
04470    memset(cmdstr, 0, 5);
04471 
04472    cmdstr[4] = command; 
04473 
04474    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
04475 
04476 }
04477 
04478 /* ft-897 offset */
04479 
04480 static int set_offset_ft897(struct rpt *myrpt, char offset)
04481 {
04482    unsigned char cmdstr[5];
04483    
04484    memset(cmdstr, 0, 5);
04485 
04486    switch(offset){
04487       case  REM_SIMPLEX:
04488          cmdstr[0] = 0x89;
04489          break;
04490 
04491       case  REM_MINUS:
04492          cmdstr[0] = 0x09;
04493          break;
04494       
04495       case  REM_PLUS:
04496          cmdstr[0] = 0x49;
04497          break;   
04498 
04499       default:
04500          return -1;
04501    }
04502 
04503    cmdstr[4] = 0x09; 
04504 
04505    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
04506 }
04507 
04508 /* ft-897 mode */
04509 
04510 static int set_mode_ft897(struct rpt *myrpt, char newmode)
04511 {
04512    unsigned char cmdstr[5];
04513    
04514    memset(cmdstr, 0, 5);
04515    
04516    switch(newmode){
04517       case  REM_MODE_FM:
04518          cmdstr[0] = 0x08;
04519          break;
04520 
04521       case  REM_MODE_USB:
04522          cmdstr[0] = 0x01;
04523          break;
04524 
04525       case  REM_MODE_LSB:
04526          cmdstr[0] = 0x00;
04527          break;
04528 
04529       case  REM_MODE_AM:
04530          cmdstr[0] = 0x04;
04531          break;
04532       
04533       default:
04534          return -1;
04535    }
04536    cmdstr[4] = 0x07; 
04537 
04538    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
04539 }
04540 
04541 /* Set tone encode and decode modes */
04542 
04543 static int set_ctcss_mode_ft897(struct rpt *myrpt, char txplon, char rxplon)
04544 {
04545    unsigned char cmdstr[5];
04546    
04547    memset(cmdstr, 0, 5);
04548    
04549    if(rxplon && txplon)
04550       cmdstr[0] = 0x2A; /* Encode and Decode */
04551    else if (!rxplon && txplon)
04552       cmdstr[0] = 0x4A; /* Encode only */
04553    else if (rxplon && !txplon)
04554       cmdstr[0] = 0x3A; /* Encode only */
04555    else
04556       cmdstr[0] = 0x8A; /* OFF */
04557 
04558    cmdstr[4] = 0x0A; 
04559 
04560    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
04561 }
04562 
04563 
04564 /* Set transmit and receive ctcss tone frequencies */
04565 
04566 static int set_ctcss_freq_ft897(struct rpt *myrpt, char *txtone, char *rxtone)
04567 {
04568    unsigned char cmdstr[5];
04569    char hertz[MAXREMSTR],decimal[MAXREMSTR];
04570    int h,d; 
04571 
04572    memset(cmdstr, 0, 5);
04573 
04574    if(split_ctcss_freq(hertz, decimal, txtone))
04575       return -1; 
04576 
04577    h = atoi(hertz);
04578    d = atoi(decimal);
04579    
04580    cmdstr[0] = ((h / 100) << 4) + (h % 100)/ 10;
04581    cmdstr[1] = ((h % 10) << 4) + (d % 10);
04582    
04583    if(rxtone){
04584    
04585       if(split_ctcss_freq(hertz, decimal, rxtone))
04586          return -1; 
04587 
04588       h = atoi(hertz);
04589       d = atoi(decimal);
04590    
04591       cmdstr[2] = ((h / 100) << 4) + (h % 100)/ 10;
04592       cmdstr[3] = ((h % 10) << 4) + (d % 10);
04593    }
04594    cmdstr[4] = 0x0B; 
04595 
04596    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
04597 }  
04598 
04599 
04600 
04601 static int set_ft897(struct rpt *myrpt)
04602 {
04603    int res;
04604    
04605    if(debug)
04606       printf("@@@@ lock on\n");
04607 
04608    res = simple_command_ft897(myrpt, 0x00);           /* LOCK on */  
04609 
04610    if(debug)
04611       printf("@@@@ ptt off\n");
04612 
04613    if(!res)
04614       res = simple_command_ft897(myrpt, 0x88);     /* PTT off */
04615 
04616    if(debug)
04617       printf("Modulation mode\n");
04618 
04619    if(!res)
04620       res = set_mode_ft897(myrpt, myrpt->remmode);    /* Modulation mode */
04621 
04622    if(debug)
04623       printf("Split off\n");
04624 
04625    if(!res)
04626       simple_command_ft897(myrpt, 0x82);        /* Split off */
04627 
04628    if(debug)
04629       printf("Frequency\n");
04630 
04631    if(!res)
04632       res = set_freq_ft897(myrpt, myrpt->freq);    /* Frequency */
04633    if((myrpt->remmode == REM_MODE_FM)){
04634       if(debug)
04635          printf("Offset\n");
04636       if(!res)
04637          res = set_offset_ft897(myrpt, myrpt->offset);   /* Offset if FM */
04638       if((!res)&&(myrpt->rxplon || myrpt->txplon)){
04639          if(debug)
04640             printf("CTCSS tone freqs.\n");
04641          res = set_ctcss_freq_ft897(myrpt, myrpt->txpl, myrpt->rxpl); /* CTCSS freqs if CTCSS is enabled */
04642       }
04643       if(!res){
04644          if(debug)
04645             printf("CTCSS mode\n");
04646          res = set_ctcss_mode_ft897(myrpt, myrpt->txplon, myrpt->rxplon); /* CTCSS mode */
04647       }
04648    }
04649    if((myrpt->remmode == REM_MODE_USB)||(myrpt->remmode == REM_MODE_LSB)){
04650       if(debug)
04651          printf("Clarifier off\n");
04652       simple_command_ft897(myrpt, 0x85);        /* Clarifier off if LSB or USB */
04653    }
04654    return res;
04655 }
04656 
04657 static int closerem_ft897(struct rpt *myrpt)
04658 {
04659    simple_command_ft897(myrpt, 0x88); /* PTT off */
04660    return 0;
04661 }  
04662 
04663 /*
04664 * Bump frequency up or down by a small amount 
04665 * Return 0 if the new frequnecy is valid, or -1 if invalid
04666 * Interval is in Hz, resolution is 10Hz 
04667 */
04668 
04669 static int multimode_bump_freq_ft897(struct rpt *myrpt, int interval)
04670 {
04671    int m,d;
04672    char mhz[MAXREMSTR], decimals[MAXREMSTR];
04673 
04674    if(debug)
04675       printf("Before bump: %s\n", myrpt->freq);
04676 
04677    if(split_freq(mhz, decimals, myrpt->freq))
04678       return -1;
04679    
04680    m = atoi(mhz);
04681    d = atoi(decimals);
04682 
04683    d += (interval / 10); /* 10Hz resolution */
04684    if(d < 0){
04685       m--;
04686       d += 100000;
04687    }
04688    else if(d >= 100000){
04689       m++;
04690       d -= 100000;
04691    }
04692 
04693    if(check_freq_ft897(m, d, NULL)){
04694       if(debug)
04695          printf("Bump freq invalid\n");
04696       return -1;
04697    }
04698 
04699    snprintf(myrpt->freq, MAXREMSTR, "%d.%05d", m, d);
04700 
04701    if(debug)
04702       printf("After bump: %s\n", myrpt->freq);
04703 
04704    return set_freq_ft897(myrpt, myrpt->freq);   
04705 }
04706 
04707 
04708 
04709 /*
04710 * Dispatch to correct I/O handler 
04711 */
04712 
04713 static int setrem(struct rpt *myrpt)
04714 {
04715    return 0; /* XXX BROKEN!! */
04716    if(!strcmp(myrpt->remote, remote_rig_ft897))
04717       return set_ft897(myrpt);
04718    else if(!strcmp(myrpt->remote, remote_rig_rbi))
04719       return setrbi(myrpt);
04720    else
04721       return -1;
04722 }
04723 
04724 static int closerem(struct rpt *myrpt)
04725 {
04726    return 0; /* XXX BROKEN!! */
04727    if(!strcmp(myrpt->remote, remote_rig_ft897))
04728       return closerem_ft897(myrpt);
04729    else
04730       return 0;
04731 }
04732 
04733 /*
04734 * Dispatch to correct frequency checker
04735 */
04736 
04737 static int check_freq(struct rpt *myrpt, int m, int d, int *defmode)
04738 {
04739    if(!strcmp(myrpt->remote, remote_rig_ft897))
04740       return check_freq_ft897(m, d, defmode);
04741    else if(!strcmp(myrpt->remote, remote_rig_rbi))
04742       return check_freq_rbi(m, d, defmode);
04743    else
04744       return -1;
04745 }
04746 
04747 /*
04748 * Return 1 if rig is multimode capable
04749 */
04750 
04751 static int multimode_capable(struct rpt *myrpt)
04752 {
04753    if(!strcmp(myrpt->remote, remote_rig_ft897))
04754       return 1;
04755    return 0;
04756 }  
04757 
04758 /*
04759 * Dispatch to correct frequency bumping function
04760 */
04761 
04762 static int multimode_bump_freq(struct rpt *myrpt, int interval)
04763 {
04764    if(!strcmp(myrpt->remote, remote_rig_ft897))
04765       return multimode_bump_freq_ft897(myrpt, interval);
04766    else
04767       return -1;
04768 }
04769 
04770 
04771 /*
04772 * Queue announcment that scan has been stopped 
04773 */
04774 
04775 static void stop_scan(struct rpt *myrpt, int flag)
04776 {
04777    myrpt->hfscanmode = 0;
04778    myrpt->hfscanstatus = ((flag) ? -2 : -1);
04779 }
04780 
04781 /*
04782 * This is called periodically when in scan mode
04783 */
04784 
04785 
04786 static int service_scan(struct rpt *myrpt)
04787 {
04788    int res, interval;
04789    char mhz[MAXREMSTR], decimals[MAXREMSTR], k10=0i, k100=0;
04790 
04791    switch(myrpt->hfscanmode){
04792 
04793       case HF_SCAN_DOWN_SLOW:
04794          interval = -10; /* 100Hz /sec */
04795          break;
04796 
04797       case HF_SCAN_DOWN_QUICK:
04798          interval = -50; /* 500Hz /sec */
04799          break;
04800 
04801       case HF_SCAN_DOWN_FAST:
04802          interval = -200; /* 2KHz /sec */
04803          break;
04804 
04805       case HF_SCAN_UP_SLOW:
04806          interval = 10; /* 100Hz /sec */
04807          break;
04808 
04809       case HF_SCAN_UP_QUICK:
04810          interval = 50; /* 500 Hz/sec */
04811          break;
04812 
04813       case HF_SCAN_UP_FAST:
04814          interval = 200; /* 2KHz /sec */
04815          break;
04816 
04817       default:
04818          myrpt->hfscanmode = 0; /* Huh? */
04819          return -1;
04820    }
04821 
04822    res = split_freq(mhz, decimals, myrpt->freq);
04823       
04824    if(!res){
04825       k100 =decimals[0];
04826       k10 = decimals[1];
04827       res = multimode_bump_freq(myrpt, interval);
04828    }
04829 
04830    if(!res)
04831       res = split_freq(mhz, decimals, myrpt->freq);
04832 
04833 
04834    if(res){
04835       stop_scan(myrpt,1);
04836       return -1;
04837    }
04838 
04839    /* Announce 10KHz boundaries */
04840    if(k10 != decimals[1]){
04841       int myhund = (interval < 0) ? k100 : decimals[0];
04842       int myten = (interval < 0) ? k10 : decimals[1];
04843       myrpt->hfscanstatus = (myten == '0') ? (myhund - '0') * 100 : (myten - '0') * 10;
04844    }
04845    return res;
04846 
04847 }
04848 
04849 
04850 static int rmt_telem_start(struct rpt *myrpt, struct ast_channel *chan, int delay)
04851 {
04852          myrpt->remotetx = 0;
04853          ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
04854          if (!myrpt->remoterx)
04855             ast_indicate(chan,AST_CONTROL_RADIO_KEY);
04856          if (ast_safe_sleep(chan, delay) == -1)
04857                return -1;
04858          return 0;
04859 }
04860 
04861 
04862 static int rmt_telem_finish(struct rpt *myrpt, struct ast_channel *chan)
04863 {
04864 
04865 struct zt_params par;
04866 
04867    if (ioctl(myrpt->txchannel->fds[0],ZT_GET_PARAMS,&par) == -1)
04868    {
04869       return -1;
04870 
04871    }
04872    if (!par.rxisoffhook)
04873    {
04874       ast_indicate(myrpt->remchannel,AST_CONTROL_RADIO_UNKEY);
04875       myrpt->remoterx = 0;
04876    }
04877    else
04878    {
04879       myrpt->remoterx = 1;
04880    }
04881    return 0;
04882 }
04883 
04884 
04885 static int rmt_sayfile(struct rpt *myrpt, struct ast_channel *chan, int delay, char *filename)
04886 {
04887    int res;
04888 
04889    res = rmt_telem_start(myrpt, chan, delay);
04890 
04891    if(!res)
04892       res = sayfile(chan, filename);
04893    
04894    if(!res)
04895       res = rmt_telem_finish(myrpt, chan);
04896    return res;
04897 }
04898 
04899 static int rmt_saycharstr(struct rpt *myrpt, struct ast_channel *chan, int delay, char *charstr)
04900 {
04901    int res;
04902 
04903    res = rmt_telem_start(myrpt, chan, delay);
04904 
04905    if(!res)
04906       res = saycharstr(chan, charstr);
04907    
04908    if(!res)
04909       res = rmt_telem_finish(myrpt, chan);
04910    return res;
04911 }
04912 
04913 
04914 
04915 /*
04916 * Remote base function
04917 */
04918 
04919 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
04920 {
04921    char *s,*s1,*s2;
04922    const char *val;
04923    int i,j,ht,k,l,ls2,m,d,res,offset,offsave, modesave, defmode;
04924    char multimode = 0;
04925    char oc;
04926    char tmp[20], freq[20] = "", savestr[20] = "";
04927    char mhz[MAXREMSTR], decimals[MAXREMSTR];
04928    struct ast_channel *mychannel;
04929 
04930    if((!param) || (command_source == SOURCE_RPT) || (command_source == SOURCE_LNK))
04931       return DC_ERROR;
04932       
04933    multimode = multimode_capable(myrpt);
04934 
04935    mychannel = myrpt->remchannel;
04936    
04937    
04938    switch(myatoi(param)){
04939 
04940       case 1:  /* retrieve memory */
04941          if(strlen(digitbuf) < 2) /* needs 2 digits */
04942             break;
04943          
04944          for(i = 0 ; i < 2 ; i++){
04945             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
04946                return DC_ERROR;
04947          }
04948        
04949          val = ast_variable_retrieve(myrpt->cfg, myrpt->p.memory, digitbuf);
04950          if (!val){
04951             if (ast_safe_sleep(mychannel,1000) == -1)
04952                return DC_ERROR;
04953             sayfile(mychannel,"rpt/memory_notfound");
04954             return DC_COMPLETE;
04955          }        
04956          ast_copy_string(tmp, val, sizeof(tmp));
04957          s = strchr(tmp,',');
04958          if (!s)
04959             return DC_ERROR;
04960          *s++ = 0;
04961          s1 = strchr(s,',');
04962          if (!s1)
04963             return DC_ERROR;
04964          *s1++ = 0;
04965          ast_copy_string(myrpt->freq, tmp, sizeof(myrpt->freq));
04966          ast_copy_string(myrpt->rxpl, s, sizeof(myrpt->rxpl));
04967          ast_copy_string(myrpt->txpl, s, sizeof(myrpt->rxpl));
04968          myrpt->remmode = REM_MODE_FM;
04969          myrpt->offset = REM_SIMPLEX;
04970          myrpt->powerlevel = REM_MEDPWR;
04971          myrpt->txplon = myrpt->rxplon = 0;
04972          while(*s1)
04973          {
04974             switch(*s1++){
04975                case 'A':
04976                case 'a':
04977                   strcpy(myrpt->rxpl, "100.0");
04978                   strcpy(myrpt->txpl, "100.0");
04979                   myrpt->remmode = REM_MODE_AM; 
04980                   break;
04981                
04982                case 'B':
04983                case 'b':
04984                   strcpy(myrpt->rxpl, "100.0");
04985                   strcpy(myrpt->txpl, "100.0");
04986                   myrpt->remmode = REM_MODE_LSB;
04987                   break;
04988          
04989                case 'F':
04990                   myrpt->remmode = REM_MODE_FM;
04991                   break;
04992 
04993                case 'L':
04994                case 'l':
04995                   myrpt->powerlevel = REM_LOWPWR;
04996                   break;               
04997                case 'H':
04998                case 'h':
04999                   myrpt->powerlevel = REM_HIPWR;
05000                   break;
05001                
05002                case 'M':
05003                case 'm':
05004                   myrpt->powerlevel = REM_MEDPWR;
05005                   break;
05006                   
05007                case '-':
05008                   myrpt->offset = REM_MINUS;
05009                   break;
05010                   
05011                case '+':
05012                   myrpt->offset = REM_PLUS;
05013                   break;
05014                   
05015                case 'S':
05016                case 's':
05017                   myrpt->offset = REM_SIMPLEX;
05018                   break;
05019                   
05020                case 'T':
05021                case 't':
05022                   myrpt->txplon = 1;
05023                   break;
05024                   
05025                case 'R':
05026                case 'r':
05027                   myrpt->rxplon = 1;
05028                   break;
05029 
05030                case 'U':
05031                case 'u':
05032                   strcpy(myrpt->rxpl, "100.0");
05033                   strcpy(myrpt->txpl, "100.0");
05034                   myrpt->remmode = REM_MODE_USB;
05035                   break;
05036             }
05037          }
05038       
05039       
05040          if (setrem(myrpt) == -1)
05041             return DC_ERROR;
05042       
05043       
05044          return DC_COMPLETE;  
05045          
05046       case 2:  /* set freq and offset */
05047       
05048          
05049             for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for M+*K+*O or M+*H+* depending on mode */
05050             if(digitbuf[i] == '*'){
05051                j++;
05052                continue;
05053             }
05054             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
05055                goto invalid_freq;
05056             else{
05057                if(j == 0)
05058                   l++; /* # of digits before first * */
05059                if(j == 1)
05060                   k++; /* # of digits after first * */
05061             }
05062          }
05063       
05064          i = strlen(digitbuf) - 1;
05065          if(multimode){
05066             if((j > 2) || (l > 3) || (k > 6))
05067                goto invalid_freq; /* &^@#! */
05068          }
05069          else{
05070             if((j > 2) || (l > 4) || (k > 3))
05071                goto invalid_freq; /* &^@#! */
05072          }
05073 
05074          /* Wait for M+*K+* */
05075 
05076          if(j < 2)
05077             break; /* Not yet */
05078 
05079          /* We have a frequency */
05080 
05081          ast_copy_string(tmp, digitbuf ,sizeof(tmp));
05082          
05083          s = tmp;
05084          s1 = strsep(&s, "*"); /* Pick off MHz */
05085          s2 = strsep(&s,"*"); /* Pick off KHz and Hz */
05086          ls2 = strlen(s2); 
05087          
05088          switch(ls2){ /* Allow partial entry of khz and hz digits for laziness support */
05089             case 1:
05090                ht = 0;
05091                k = 100 * atoi(s2);
05092                break;
05093             
05094             case 2:
05095                ht = 0;
05096                k = 10 * atoi(s2);
05097                break;
05098                
05099             case 3:
05100                if(!multimode){
05101                   if((s2[2] != '0')&&(s2[2] != '5'))
05102                      goto invalid_freq;
05103                }
05104                ht = 0;
05105                k = atoi(s2);
05106                   break;
05107             case 4:
05108                k = atoi(s2)/10;
05109                ht = 10 * (atoi(s2+(ls2-1)));
05110                break;
05111 
05112             case 5:
05113                k = atoi(s2)/100;
05114                ht = (atoi(s2+(ls2-2)));
05115                break;
05116                
05117             default:
05118                goto invalid_freq;
05119          }
05120 
05121          /* Check frequency for validity and establish a default mode */
05122          
05123          snprintf(freq, sizeof(freq), "%s.%03d%02d",s1, k, ht);
05124 
05125          if(debug)
05126             printf("New frequency: %s\n", freq);      
05127    
05128          split_freq(mhz, decimals, freq);
05129          m = atoi(mhz);
05130          d = atoi(decimals);
05131 
05132                         if(check_freq(myrpt, m, d, &defmode)) /* Check to see if frequency entered is legit */
05133                                 goto invalid_freq;
05134 
05135 
05136          if((defmode == REM_MODE_FM) && (digitbuf[i] == '*')) /* If FM, user must enter and additional offset digit */
05137             break; /* Not yet */
05138 
05139 
05140          offset = REM_SIMPLEX; /* Assume simplex */
05141 
05142          if(defmode == REM_MODE_FM){
05143             oc = *s; /* Pick off offset */
05144          
05145             if (oc){
05146                switch(oc){
05147                   case '1':
05148                      offset = REM_MINUS;
05149                      break;
05150                   
05151                   case '2':
05152                      offset = REM_SIMPLEX;
05153                   break;
05154                   
05155                   case '3':
05156                      offset = REM_PLUS;
05157                      break;
05158                   
05159                   default:
05160                      goto invalid_freq;
05161                } 
05162             } 
05163          }  
05164          offsave = myrpt->offset;
05165          modesave = myrpt->remmode;
05166          ast_copy_string(savestr, myrpt->freq, sizeof(savestr));
05167          ast_copy_string(myrpt->freq, freq, sizeof(myrpt->freq));
05168          myrpt->offset = offset;
05169          myrpt->remmode = defmode;
05170 
05171          if (setrem(myrpt) == -1){
05172             myrpt->offset = offsave;
05173             myrpt->remmode = modesave;
05174             ast_copy_string(myrpt->freq, savestr, sizeof(myrpt->freq));
05175             goto invalid_freq;
05176          }
05177 
05178          return DC_COMPLETE;
05179 
05180 
05181          invalid_freq:
05182    
05183          rmt_sayfile(myrpt, mychannel, 1000, "rpt/invalid-freq");
05184 
05185          return DC_ERROR; 
05186       
05187       case 3: /* set rx PL tone */
05188          
05189             for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
05190             if(digitbuf[i] == '*'){
05191                j++;
05192                continue;
05193             }
05194             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
05195                return DC_ERROR;
05196             else{
05197                if(j)
05198                   l++;
05199                else
05200                   k++;
05201             }
05202          }
05203          if((j > 1) || (k > 3) || (l > 1))
05204             return DC_ERROR; /* &$@^! */
05205          i = strlen(digitbuf) - 1;
05206          if((j != 1) || (k < 2)|| (l != 1))
05207             break; /* Not yet */
05208          if(debug)
05209             printf("PL digits entered %s\n", digitbuf);
05210             
05211          ast_copy_string(tmp, digitbuf, sizeof(tmp));
05212          /* see if we have at least 1 */
05213          s = strchr(tmp,'*');
05214          if(s)
05215             *s = '.';
05216          ast_copy_string(savestr, myrpt->rxpl, sizeof(savestr));
05217          ast_copy_string(myrpt->rxpl, tmp, sizeof(myrpt->rxpl));
05218          
05219          if (setrem(myrpt) == -1){
05220             ast_copy_string(myrpt->rxpl, savestr, sizeof(myrpt->rxpl));
05221             return DC_ERROR;
05222          }
05223       
05224       
05225          return DC_COMPLETE;
05226       
05227       case 4: /* set tx PL tone */
05228          
05229             for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
05230             if(digitbuf[i] == '*'){
05231                j++;
05232                continue;
05233             }
05234             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
05235                return DC_ERROR;
05236             else{
05237                if(j)
05238                   l++;
05239                else
05240                   k++;
05241             }
05242          }
05243          if((j > 1) || (k > 3) || (l > 1))
05244             return DC_ERROR; /* &$@^! */
05245          i = strlen(digitbuf) - 1;
05246          if((j != 1) || (k < 2)|| (l != 1))
05247             break; /* Not yet */
05248          if(debug)
05249             printf("PL digits entered %s\n", digitbuf);
05250             
05251          ast_copy_string(tmp, digitbuf, sizeof(tmp));
05252          /* see if we have at least 1 */
05253          s = strchr(tmp,'*');
05254          if(s)
05255             *s = '.';
05256          ast_copy_string(savestr, myrpt->txpl, sizeof(savestr));
05257          ast_copy_string(myrpt->txpl, tmp, sizeof(myrpt->txpl));
05258          
05259          if (setrem(myrpt) == -1){
05260             ast_copy_string(myrpt->txpl, savestr, sizeof(myrpt->txpl) - 1);
05261             return DC_ERROR;
05262          }
05263       
05264       
05265          return DC_COMPLETE;
05266       
05267 
05268       case 6: /* MODE (FM,USB,LSB,AM) */
05269          if(strlen(digitbuf) < 1)
05270             break;
05271 
05272          if(!multimode)
05273             return DC_ERROR; /* Multimode radios only */
05274 
05275          switch(*digitbuf){
05276             case '1':
05277                split_freq(mhz, decimals, myrpt->freq); 
05278                m=atoi(mhz);
05279                if(m < 29) /* No FM allowed below 29MHz! */
05280                   return DC_ERROR;
05281                myrpt->remmode = REM_MODE_FM;
05282                res = rmt_saycharstr(myrpt, mychannel, 1000,"FM");
05283                break;
05284 
05285             case '2':
05286                myrpt->remmode = REM_MODE_USB;
05287                res = rmt_saycharstr(myrpt, mychannel, 1000,"USB");
05288                break;   
05289 
05290             case '3':
05291                myrpt->remmode = REM_MODE_LSB;
05292                res = rmt_saycharstr(myrpt, mychannel, 1000,"LSB");
05293                break;
05294             
05295             case '4':
05296                myrpt->remmode = REM_MODE_AM;
05297                res = rmt_saycharstr(myrpt, mychannel, 1000,"AM");
05298                break;
05299       
05300             default:
05301                return DC_ERROR;
05302          }
05303          if(res)
05304             return DC_ERROR;
05305 
05306          if(setrem(myrpt))
05307             return DC_ERROR;
05308          return DC_COMPLETE;
05309 
05310       case 100: /* other stuff */
05311       case 101: 
05312       case 102: 
05313       case 103: 
05314       case 104: 
05315       case 105: 
05316       case 106:
05317          res = rmt_telem_start(myrpt, mychannel, 1000);
05318          switch(myatoi(param)){ /* Quick commands requiring a setrem call */
05319             case 100: /* RX PL Off */
05320                myrpt->rxplon = 0;
05321                if(!res)
05322                   res = sayfile(mychannel, "rpt/rxpl");
05323                if(!res)
05324                   sayfile(mychannel, "rpt/off");
05325                break;
05326                
05327             case 101: /* RX PL On */
05328                myrpt->rxplon = 1;
05329                if(!res)
05330                   res = sayfile(mychannel, "rpt/rxpl");
05331                if(!res)
05332                   sayfile(mychannel, "rpt/on");
05333                break;
05334 
05335                
05336             case 102: /* TX PL Off */
05337                myrpt->txplon = 0;
05338                if(!res)
05339                   res = sayfile(mychannel, "rpt/txpl");
05340                if(!res)
05341                   sayfile(mychannel, "rpt/off");
05342                break;
05343                
05344             case 103: /* TX PL On */
05345                myrpt->txplon = 1;
05346                if(!res)
05347                   res = sayfile(mychannel, "rpt/txpl");
05348                if(!res)
05349                   sayfile(mychannel, "rpt/on");
05350                break;
05351                
05352             case 104: /* Low Power */
05353                myrpt->powerlevel = REM_LOWPWR;
05354                if(!res)
05355                   res = sayfile(mychannel, "rpt/lopwr");
05356                break;
05357                
05358             case 105: /* Medium Power */
05359                myrpt->powerlevel = REM_MEDPWR;
05360                if(!res)
05361                   res = sayfile(mychannel, "rpt/medpwr");
05362                break;
05363                
05364             case 106: /* Hi Power */
05365                myrpt->powerlevel = REM_HIPWR;
05366                if(!res)
05367                   res = sayfile(mychannel, "rpt/hipwr");
05368                break;
05369          
05370             default:
05371                if(!res)
05372                   rmt_telem_finish(myrpt, mychannel);
05373                return DC_ERROR;
05374          }
05375          if(!res)
05376             res = rmt_telem_finish(myrpt, mychannel);
05377          if(res)
05378             return DC_ERROR;
05379 
05380          if (setrem(myrpt) == -1) 
05381             return DC_ERROR;
05382          return DC_COMPLETE;
05383 
05384       case 107: /* Bump down 20Hz */
05385          multimode_bump_freq(myrpt, -20);
05386          return DC_COMPLETE;
05387 
05388       case 108: /* Bump down 100Hz */
05389          multimode_bump_freq(myrpt, -100);
05390          return DC_COMPLETE;
05391 
05392       case 109: /* Bump down 500Hz */
05393          multimode_bump_freq(myrpt, -500);
05394          return DC_COMPLETE;
05395 
05396       case 110: /* Bump up 20Hz */
05397          multimode_bump_freq(myrpt, 20);
05398          return DC_COMPLETE;
05399             
05400       case 111: /* Bump up 100Hz */
05401          multimode_bump_freq(myrpt, 100);
05402          return DC_COMPLETE;
05403 
05404       case 112: /* Bump up 500Hz */
05405          multimode_bump_freq(myrpt, 500);
05406          return DC_COMPLETE;
05407 
05408 
05409       case 113:
05410       case 114:
05411       case 115:
05412       case 116:
05413       case 117:
05414       case 118:
05415          myrpt->remotetx = 0;
05416          ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
05417          if (!myrpt->remoterx)
05418             ast_indicate(mychannel,AST_CONTROL_RADIO_KEY);
05419          if (ast_safe_sleep(mychannel,1000) == -1)
05420                return DC_ERROR;
05421       
05422          switch(myatoi(param)){
05423 
05424             case 113: /* Scan down slow */
05425                res = sayfile(mychannel,"rpt/down");
05426                if(!res)
05427                   res = sayfile(mychannel, "rpt/slow");
05428                if(!res){
05429                   myrpt->scantimer = REM_SCANTIME;
05430                   myrpt->hfscanmode = HF_SCAN_DOWN_SLOW;
05431                }
05432                break;
05433 
05434             case 114: /* Scan down quick */
05435                res = sayfile(mychannel,"rpt/down");
05436                if(!res)
05437                   res = sayfile(mychannel, "rpt/quick");
05438                if(!res){
05439                   myrpt->scantimer = REM_SCANTIME;
05440                   myrpt->hfscanmode = HF_SCAN_DOWN_QUICK;
05441                }
05442                break;
05443 
05444             case 115: /* Scan down fast */
05445                res = sayfile(mychannel,"rpt/down");
05446                if(!res)
05447                   res = sayfile(mychannel, "rpt/fast");
05448                if(!res){
05449                   myrpt->scantimer = REM_SCANTIME;
05450                   myrpt->hfscanmode = HF_SCAN_DOWN_FAST;
05451                }
05452                break;
05453 
05454             case 116: /* Scan up slow */
05455                res = sayfile(mychannel,"rpt/up");
05456                if(!res)
05457                   res = sayfile(mychannel, "rpt/slow");
05458                if(!res){
05459                   myrpt->scantimer = REM_SCANTIME;
05460                   myrpt->hfscanmode = HF_SCAN_UP_SLOW;
05461                }
05462                break;
05463 
05464             case 117: /* Scan up quick */
05465                res = sayfile(mychannel,"rpt/up");
05466                if(!res)
05467                   res = sayfile(mychannel, "rpt/quick");
05468                if(!res){
05469                   myrpt->scantimer = REM_SCANTIME;
05470                   myrpt->hfscanmode = HF_SCAN_UP_QUICK;
05471                }
05472                break;
05473 
05474             case 118: /* Scan up fast */
05475                res = sayfile(mychannel,"rpt/up");
05476                if(!res)
05477                   res = sayfile(mychannel, "rpt/fast");
05478                if(!res){
05479                   myrpt->scantimer = REM_SCANTIME;
05480                   myrpt->hfscanmode = HF_SCAN_UP_FAST;
05481                }
05482                break;
05483          }
05484          rmt_telem_finish(myrpt,mychannel);
05485          return DC_COMPLETE;
05486 
05487 
05488       case 119: /* Tune Request */
05489          myrpt->tunerequest = 1;
05490          return DC_COMPLETE;
05491 
05492       case 5: /* Long Status */
05493       case 140: /* Short Status */
05494          res = rmt_telem_start(myrpt, mychannel, 1000);
05495 
05496          res = sayfile(mychannel,"rpt/node");
05497          if(!res)
05498             res = saycharstr(mychannel, myrpt->name);
05499          if(!res)
05500             res = sayfile(mychannel,"rpt/frequency");
05501          if(!res)
05502             res = split_freq(mhz, decimals, myrpt->freq);
05503          if(!res){
05504             m = atoi(mhz);
05505             if(m < 100)
05506                res = saynum(mychannel, m);
05507             else
05508                res = saycharstr(mychannel, mhz);
05509          }
05510          if(!res)
05511             res = sayfile(mychannel, "letters/dot");
05512          if(!res)
05513             res = saycharstr(mychannel, decimals);
05514       
05515          if(res){ 
05516             rmt_telem_finish(myrpt,mychannel);
05517             return DC_ERROR;
05518          }
05519          if(myrpt->remmode == REM_MODE_FM){ /* Mode FM? */
05520             switch(myrpt->offset){
05521    
05522                case REM_MINUS:
05523                   res = sayfile(mychannel,"rpt/minus");
05524                   break;
05525             
05526                case REM_SIMPLEX:
05527                   res = sayfile(mychannel,"rpt/simplex");
05528                   break;
05529                
05530                case REM_PLUS:
05531                   res = sayfile(mychannel,"rpt/plus");
05532                   break;
05533                
05534                default:
05535                   return DC_ERROR;
05536 
05537             }
05538          }
05539          else{ /* Must be USB, LSB, or AM */
05540             switch(myrpt->remmode){
05541 
05542                case REM_MODE_USB:
05543                   res = saycharstr(mychannel, "USB");
05544                   break;
05545 
05546                case REM_MODE_LSB:
05547                   res = saycharstr(mychannel, "LSB");
05548                   break;
05549 
05550                case REM_MODE_AM:
05551                   res = saycharstr(mychannel, "AM");
05552                   break;
05553 
05554 
05555                default:
05556                   return DC_ERROR;
05557             }
05558          }
05559 
05560          if (res == -1){
05561             rmt_telem_finish(myrpt,mychannel);
05562             return DC_ERROR;
05563          }
05564 
05565          if(myatoi(param) == 140){ /* Short status? */
05566             if(!res)
05567                res = rmt_telem_finish(myrpt, mychannel);
05568             if(res)
05569                return DC_ERROR;
05570             return DC_COMPLETE;
05571          }
05572 
05573          switch(myrpt->powerlevel){
05574 
05575             case REM_LOWPWR:
05576                res = sayfile(mychannel,"rpt/lopwr") ;
05577                break;
05578                
05579             case REM_MEDPWR:
05580                res = sayfile(mychannel,"rpt/medpwr");
05581                break;
05582             case REM_HIPWR:
05583                res = sayfile(mychannel,"rpt/hipwr"); 
05584                break;
05585          }
05586          if (res || (sayfile(mychannel,"rpt/rxpl") == -1) ||
05587             (sayfile(mychannel,"rpt/frequency") == -1) ||
05588             (saycharstr(mychannel,myrpt->rxpl) == -1) ||
05589             (sayfile(mychannel,"rpt/txpl") == -1) ||
05590             (sayfile(mychannel,"rpt/frequency") == -1) ||
05591             (saycharstr(mychannel,myrpt->txpl) == -1) ||
05592             (sayfile(mychannel,"rpt/txpl") == -1) ||
05593             (sayfile(mychannel,((myrpt->txplon) ? "rpt/on" : "rpt/off")) == -1) ||
05594             (sayfile(mychannel,"rpt/rxpl") == -1) ||
05595             (sayfile(mychannel,((myrpt->rxplon) ? "rpt/on" : "rpt/off")) == -1))
05596             {
05597                rmt_telem_finish(myrpt,mychannel);
05598                return DC_ERROR;
05599             }
05600          if(!res)
05601             res = rmt_telem_finish(myrpt,mychannel);
05602          if(res)
05603             return DC_ERROR;
05604 
05605          return DC_COMPLETE;
05606          default:
05607          return DC_ERROR;
05608    }
05609 
05610    return DC_INDETERMINATE;
05611 }
05612 
05613 static int handle_remote_dtmf_digit(struct rpt *myrpt,char c, char *keyed, int phonemode)
05614 {
05615 time_t   now;
05616 int   ret,res = 0,src;
05617 
05618    /* Stop scan mode if in scan mode */
05619    if(myrpt->hfscanmode){
05620       stop_scan(myrpt,0);
05621       return 0;
05622    }
05623 
05624    time(&now);
05625    /* if timed-out */
05626    if ((myrpt->dtmf_time_rem + DTMF_TIMEOUT) < now)
05627    {
05628       myrpt->dtmfidx = -1;
05629       myrpt->dtmfbuf[0] = 0;
05630       myrpt->dtmf_time_rem = 0;
05631    }
05632    /* if decode not active */
05633    if (myrpt->dtmfidx == -1)
05634    {
05635       /* if not lead-in digit, dont worry */
05636       if (c != myrpt->p.funcchar) return 0;
05637       myrpt->dtmfidx = 0;
05638       myrpt->dtmfbuf[0] = 0;
05639       myrpt->dtmf_time_rem = now;
05640       return 0;
05641    }
05642    /* if too many in buffer, start over */
05643    if (myrpt->dtmfidx >= MAXDTMF)
05644    {
05645       myrpt->dtmfidx = 0;
05646       myrpt->dtmfbuf[0] = 0;
05647       myrpt->dtmf_time_rem = now;
05648    }
05649    if (c == myrpt->p.funcchar)
05650    {
05651       /* if star at beginning, or 2 together, erase buffer */
05652       if ((myrpt->dtmfidx < 1) || 
05653          (myrpt->dtmfbuf[myrpt->dtmfidx - 1] == myrpt->p.funcchar))
05654       {
05655          myrpt->dtmfidx = 0;
05656          myrpt->dtmfbuf[0] = 0;
05657          myrpt->dtmf_time_rem = now;
05658          return 0;
05659       }
05660    }
05661    myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
05662    myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
05663    myrpt->dtmf_time_rem = now;
05664    
05665    
05666    src = SOURCE_RMT;
05667    if (phonemode > 1) src = SOURCE_DPHONE;
05668    else if (phonemode) src = SOURCE_PHONE;
05669    ret = collect_function_digits(myrpt, myrpt->dtmfbuf, src, NULL);
05670    
05671    switch(ret){
05672    
05673       case DC_INDETERMINATE:
05674          res = 0;
05675          break;
05676             
05677       case DC_DOKEY:
05678          if (keyed) *keyed = 1;
05679          res = 0;
05680          break;
05681             
05682       case DC_REQ_FLUSH:
05683          myrpt->dtmfidx = 0;
05684          myrpt->dtmfbuf[0] = 0;
05685          res = 0;
05686          break;
05687             
05688             
05689       case DC_COMPLETE:
05690          myrpt->totalexecdcommands++;
05691          myrpt->dailyexecdcommands++;
05692          ast_copy_string(myrpt->lastdtmfcommand, myrpt->dtmfbuf, MAXDTMF);
05693          myrpt->dtmfbuf[0] = 0;
05694          myrpt->dtmfidx = -1;
05695          myrpt->dtmf_time_rem = 0;
05696          res = 1;
05697          break;
05698             
05699       case DC_ERROR:
05700       default:
05701          myrpt->dtmfbuf[0] = 0;
05702          myrpt->dtmfidx = -1;
05703          myrpt->dtmf_time_rem = 0;
05704          res = 0;
05705          break;
05706    }
05707 
05708    return res;
05709 }
05710 
05711 static int handle_remote_data(struct rpt *myrpt, char *str)
05712 {
05713 char  tmp[300],cmd[300],dest[300],src[300],c;
05714 int   seq,res;
05715 
05716    /* put string in our buffer */
05717    ast_copy_string(tmp,str,sizeof(tmp));
05718    if (!strcmp(tmp,discstr)) return 0;
05719    if (sscanf(tmp,"%s %s %s %d %c",cmd,dest,src,&seq,&c) != 5)
05720    {
05721       ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
05722       return 0;
05723    }
05724    if (strcmp(cmd,"D"))
05725    {
05726       ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
05727       return 0;
05728    }
05729    /* if not for me, ignore */
05730    if (strcmp(dest,myrpt->name)) return 0;
05731    res = handle_remote_dtmf_digit(myrpt,c, NULL, 0);
05732    if (res != 1)
05733       return res;
05734    myrpt->remotetx = 0;
05735    ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
05736    if (!myrpt->remoterx)
05737    {
05738       ast_indicate(myrpt->remchannel,AST_CONTROL_RADIO_KEY);
05739    }
05740    if (ast_safe_sleep(myrpt->remchannel,1000) == -1) return -1;
05741    res = telem_lookup(myrpt,myrpt->remchannel, myrpt->name, "functcomplete");
05742    rmt_telem_finish(myrpt,myrpt->remchannel);
05743    return res;
05744 }
05745 
05746 static int handle_remote_phone_dtmf(struct rpt *myrpt, char c, char *keyed, int phonemode)
05747 {
05748 int   res;
05749 
05750 
05751    if (keyed && *keyed && (c == myrpt->p.endchar))
05752    {
05753       *keyed = 0;
05754       return DC_INDETERMINATE;
05755    }
05756 
05757    res = handle_remote_dtmf_digit(myrpt,c,keyed, phonemode);
05758    if (res != 1)
05759       return res;
05760    myrpt->remotetx = 0;
05761    ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
05762    if (!myrpt->remoterx)
05763    {
05764       ast_indicate(myrpt->remchannel,AST_CONTROL_RADIO_KEY);
05765    }
05766    if (ast_safe_sleep(myrpt->remchannel,1000) == -1) return -1;
05767    res = telem_lookup(myrpt,myrpt->remchannel, myrpt->name, "functcomplete");
05768    rmt_telem_finish(myrpt,myrpt->remchannel);
05769    return res;
05770 }
05771 
05772 static int attempt_reconnect(struct rpt *myrpt, struct rpt_link *l)
05773 {
05774    const char *val;
05775    char *s, *s1, *s2, *tele;
05776    char tmp[300], deststr[300] = "";
05777 
05778    val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, l->name);
05779    if (!val)
05780    {
05781       fprintf(stderr,"attempt_reconnect: cannot find node %s\n",l->name);
05782       return -1;
05783    }
05784 
05785    rpt_mutex_lock(&myrpt->lock);
05786    /* remove from queue */
05787    remque((struct qelem *) l);
05788    rpt_mutex_unlock(&myrpt->lock);
05789    ast_copy_string(tmp,val,sizeof(tmp));
05790    s = tmp;
05791    s1 = strsep(&s,",");
05792    s2 = strsep(&s,",");
05793    snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
05794    tele = strchr(deststr, '/');
05795    if (!tele) {
05796       fprintf(stderr,"attempt_reconnect:Dial number (%s) must be in format tech/number\n",deststr);
05797       return -1;
05798    }
05799    *tele++ = 0;
05800    l->elaptime = 0;
05801    l->connecttime = 0;
05802    l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele,NULL);
05803    if (l->chan){
05804       ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
05805       ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
05806       l->chan->whentohangup = 0;
05807       l->chan->appl = "Apprpt";
05808       l->chan->data = "(Remote Rx)";
05809       if (option_verbose > 2)
05810          ast_verbose(VERBOSE_PREFIX_3 "rpt (attempt_reconnect) initiating call to %s/%s on %s\n",
05811             deststr, tele, l->chan->name);
05812       if(l->chan->cid.cid_num)
05813          free(l->chan->cid.cid_num);
05814       l->chan->cid.cid_num = strdup(myrpt->name);
05815                 ast_call(l->chan,tele,999); 
05816 
05817    }
05818    else 
05819    {
05820       if (option_verbose > 2)
05821          ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
05822             deststr,tele,l->chan->name);
05823       return -1;
05824    }
05825    rpt_mutex_lock(&myrpt->lock);
05826    /* put back in queue */
05827    insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
05828    rpt_mutex_unlock(&myrpt->lock);
05829    ast_log(LOG_NOTICE,"Reconnect Attempt to %s in process\n",l->name);
05830    return 0;
05831 }
05832 
05833 /* 0 return=continue, 1 return = break, -1 return = error */
05834 static void local_dtmf_helper(struct rpt *myrpt,char c)
05835 {
05836 int   res;
05837 pthread_attr_t attr;
05838 char  cmd[MAXDTMF+1] = "";
05839 
05840    if (c == myrpt->p.endchar)
05841    {
05842    /* if in simple mode, kill autopatch */
05843       if (myrpt->p.simple && myrpt->callmode)
05844       {
05845          rpt_mutex_lock(&myrpt->lock);
05846          myrpt->callmode = 0;
05847          rpt_mutex_unlock(&myrpt->lock);
05848          rpt_telemetry(myrpt,TERM,NULL);
05849          return;
05850       }
05851       rpt_mutex_lock(&myrpt->lock);
05852       myrpt->stopgen = 1;
05853       if (myrpt->cmdnode[0])
05854       {
05855          myrpt->cmdnode[0] = 0;
05856          myrpt->dtmfidx = -1;
05857          myrpt->dtmfbuf[0] = 0;
05858          rpt_mutex_unlock(&myrpt->lock);
05859          rpt_telemetry(myrpt,COMPLETE,NULL);
05860       } else rpt_mutex_unlock(&myrpt->lock);
05861       return;
05862    }
05863    rpt_mutex_lock(&myrpt->lock);
05864    if (myrpt->cmdnode[0])
05865    {
05866       rpt_mutex_unlock(&myrpt->lock);
05867       send_link_dtmf(myrpt,c);
05868       return;
05869    }
05870    if (!myrpt->p.simple)
05871    {
05872       if (c == myrpt->p.funcchar)
05873       {
05874          myrpt->dtmfidx = 0;
05875          myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
05876          rpt_mutex_unlock(&myrpt->lock);
05877          time(&myrpt->dtmf_time);
05878          return;
05879       } 
05880       else if ((c != myrpt->p.endchar) && (myrpt->dtmfidx >= 0))
05881       {
05882          time(&myrpt->dtmf_time);
05883          
05884          if (myrpt->dtmfidx < MAXDTMF)
05885          {
05886             myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
05887             myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
05888             
05889             ast_copy_string(cmd, myrpt->dtmfbuf, sizeof(cmd));
05890             
05891             rpt_mutex_unlock(&myrpt->lock);
05892             res = collect_function_digits(myrpt, cmd, SOURCE_RPT, NULL);
05893             rpt_mutex_lock(&myrpt->lock);
05894             switch(res){
05895                 case DC_INDETERMINATE:
05896                break;
05897                 case DC_REQ_FLUSH:
05898                myrpt->dtmfidx = 0;
05899                myrpt->dtmfbuf[0] = 0;
05900                break;
05901                 case DC_COMPLETE:
05902                myrpt->totalexecdcommands++;
05903                myrpt->dailyexecdcommands++;
05904                ast_copy_string(myrpt->lastdtmfcommand, cmd, MAXDTMF);
05905                myrpt->dtmfbuf[0] = 0;
05906                myrpt->dtmfidx = -1;
05907                myrpt->dtmf_time = 0;
05908                break;
05909 
05910                 case DC_ERROR:
05911                 default:
05912                myrpt->dtmfbuf[0] = 0;
05913                myrpt->dtmfidx = -1;
05914                myrpt->dtmf_time = 0;
05915                break;
05916             }
05917             if(res != DC_INDETERMINATE) {
05918                rpt_mutex_unlock(&myrpt->lock);
05919                return;
05920             }
05921          } 
05922       }
05923    }
05924    else /* if simple */
05925    {
05926       if ((!myrpt->callmode) && (c == myrpt->p.funcchar))
05927       {
05928          myrpt->callmode = 1;
05929          myrpt->patchnoct = 0;
05930          myrpt->patchquiet = 0;
05931          myrpt->patchfarenddisconnect = 0;
05932          myrpt->patchdialtime = 0;
05933          ast_copy_string(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT);
05934          myrpt->cidx = 0;
05935          myrpt->exten[myrpt->cidx] = 0;
05936          rpt_mutex_unlock(&myrpt->lock);
05937               pthread_attr_init(&attr);
05938               pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
05939          ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *)myrpt);
05940          pthread_attr_destroy(&attr);
05941          return;
05942       }
05943    }
05944    if (myrpt->callmode == 1)
05945    {
05946       myrpt->exten[myrpt->cidx++] = c;
05947       myrpt->exten[myrpt->cidx] = 0;
05948       /* if this exists */
05949       if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
05950       {
05951          myrpt->callmode = 2;
05952          rpt_mutex_unlock(&myrpt->lock);
05953          if(!myrpt->patchquiet)
05954             rpt_telemetry(myrpt,PROC,NULL); 
05955          return;
05956       }
05957       /* if can continue, do so */
05958       if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
05959       {
05960          /* call has failed, inform user */
05961          myrpt->callmode = 4;
05962       }
05963       rpt_mutex_unlock(&myrpt->lock);
05964       return;
05965    }
05966    if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
05967    {
05968       myrpt->mydtmf = c;
05969    }
05970    rpt_mutex_unlock(&myrpt->lock);
05971    return;
05972 }
05973 
05974 
05975 /* place an ID event in the telemetry queue */
05976 
05977 static void queue_id(struct rpt *myrpt)
05978 {
05979    myrpt->mustid = myrpt->tailid = 0;
05980    myrpt->idtimer = myrpt->p.idtime; /* Reset our ID timer */
05981    rpt_mutex_unlock(&myrpt->lock);
05982    rpt_telemetry(myrpt,ID,NULL);
05983    rpt_mutex_lock(&myrpt->lock);
05984 }
05985 
05986 /* Scheduler */
05987 
05988 static void do_scheduler(struct rpt *myrpt)
05989 {
05990    int res;
05991    struct tm tmnow;
05992 
05993    memcpy(&myrpt->lasttv, &myrpt->curtv, sizeof(struct timeval));
05994    
05995    if( (res = gettimeofday(&myrpt->curtv, NULL)) < 0)
05996       ast_log(LOG_NOTICE, "Scheduler gettime of day returned: %s\n", strerror(res));
05997 
05998    /* Try to get close to a 1 second resolution */
05999    
06000    if(myrpt->lasttv.tv_sec == myrpt->curtv.tv_sec)
06001       return;
06002 
06003    ast_localtime(&myrpt->curtv.tv_sec, &tmnow, NULL);
06004 
06005    /* If midnight, then reset all daily statistics */
06006    
06007    if((tmnow.tm_hour == 0)&&(tmnow.tm_min == 0)&&(tmnow.tm_sec == 0)){
06008       myrpt->dailykeyups = 0;
06009       myrpt->dailytxtime = 0;
06010       myrpt->dailykerchunks = 0;
06011       myrpt->dailyexecdcommands = 0;
06012    }
06013 }
06014 
06015 
06016 /* single thread with one file (request) to dial */
06017 static void *rpt(void *this)
06018 {
06019 struct   rpt *myrpt = (struct rpt *)this;
06020    char *tele, c;
06021    const char *idtalkover;
06022 int ms = MSWAIT,i,lasttx=0,val,remrx=0,identqueued,othertelemqueued,tailmessagequeued,ctqueued;
06023 struct ast_channel *who;
06024 ZT_CONFINFO ci;  /* conference info */
06025 time_t   t;
06026 struct rpt_link *l,*m;
06027 struct rpt_tele *telem;
06028 char tmpstr[300];
06029 
06030    rpt_mutex_lock(&myrpt->lock);
06031 
06032    telem = myrpt->tele.next;
06033    while(telem != &myrpt->tele)
06034    {
06035       ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
06036       telem = telem->next;
06037    }
06038    rpt_mutex_unlock(&myrpt->lock);
06039    /* find our index, and load the vars initially */
06040    for(i = 0; i < nrpts; i++)
06041    {
06042       if (&rpt_vars[i] == myrpt)
06043       {
06044          load_rpt_vars(i,0);
06045          break;
06046       }
06047    }
06048    rpt_mutex_lock(&myrpt->lock);
06049    ast_copy_string(tmpstr,myrpt->rxchanname,sizeof(tmpstr));
06050    tele = strchr(tmpstr,'/');
06051    if (!tele)
06052    {
06053       fprintf(stderr,"rpt:Rxchannel Dial number (%s) must be in format tech/number\n",myrpt->rxchanname);
06054       rpt_mutex_unlock(&myrpt->lock);
06055       myrpt->rpt_thread = AST_PTHREADT_STOP;
06056       pthread_exit(NULL);
06057    }
06058    *tele++ = 0;
06059    myrpt->rxchannel = ast_request(tmpstr,AST_FORMAT_SLINEAR,tele,NULL);
06060    if (myrpt->rxchannel)
06061    {
06062       if (myrpt->rxchannel->_state == AST_STATE_BUSY)
06063       {
06064          fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
06065          rpt_mutex_unlock(&myrpt->lock);
06066          ast_hangup(myrpt->rxchannel);
06067          myrpt->rpt_thread = AST_PTHREADT_STOP;
06068          pthread_exit(NULL);
06069       }
06070       ast_set_read_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
06071       ast_set_write_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
06072       myrpt->rxchannel->whentohangup = 0;
06073       myrpt->rxchannel->appl = "Apprpt";
06074       myrpt->rxchannel->data = "(Repeater Rx)";
06075       if (option_verbose > 2)
06076          ast_verbose(VERBOSE_PREFIX_3 "rpt (Rx) initiating call to %s/%s on %s\n",
06077             tmpstr,tele,myrpt->rxchannel->name);
06078       ast_call(myrpt->rxchannel,tele,999);
06079       if (myrpt->rxchannel->_state != AST_STATE_UP)
06080       {
06081          rpt_mutex_unlock(&myrpt->lock);
06082          ast_hangup(myrpt->rxchannel);
06083          myrpt->rpt_thread = AST_PTHREADT_STOP;
06084          pthread_exit(NULL);
06085       }
06086    }
06087    else
06088    {
06089       fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
06090       rpt_mutex_unlock(&myrpt->lock);
06091       myrpt->rpt_thread = AST_PTHREADT_STOP;
06092       pthread_exit(NULL);
06093    }
06094    if (myrpt->txchanname)
06095    {
06096       ast_copy_string(tmpstr,myrpt->txchanname,sizeof(tmpstr));
06097       tele = strchr(tmpstr,'/');
06098       if (!tele)
06099       {
06100          fprintf(stderr,"rpt:Txchannel Dial number (%s) must be in format tech/number\n",myrpt->txchanname);
06101          rpt_mutex_unlock(&myrpt->lock);
06102          ast_hangup(myrpt->rxchannel);
06103          myrpt->rpt_thread = AST_PTHREADT_STOP;
06104          pthread_exit(NULL);
06105       }
06106       *tele++ = 0;
06107       myrpt->txchannel = ast_request(tmpstr,AST_FORMAT_SLINEAR,tele,NULL);
06108       if (myrpt->txchannel)
06109       {
06110          if (myrpt->txchannel->_state == AST_STATE_BUSY)
06111          {
06112             fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
06113             rpt_mutex_unlock(&myrpt->lock);
06114             ast_hangup(myrpt->txchannel);
06115             ast_hangup(myrpt->rxchannel);
06116             myrpt->rpt_thread = AST_PTHREADT_STOP;
06117             pthread_exit(NULL);
06118          }        
06119          ast_set_read_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
06120          ast_set_write_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
06121          myrpt->txchannel->whentohangup = 0;
06122          myrpt->txchannel->appl = "Apprpt";
06123          myrpt->txchannel->data = "(Repeater Tx)";
06124          if (option_verbose > 2)
06125             ast_verbose(VERBOSE_PREFIX_3 "rpt (Tx) initiating call to %s/%s on %s\n",
06126                tmpstr,tele,myrpt->txchannel->name);
06127          ast_call(myrpt->txchannel,tele,999);
06128          if (myrpt->rxchannel->_state != AST_STATE_UP)
06129          {
06130             rpt_mutex_unlock(&myrpt->lock);
06131             ast_hangup(myrpt->rxchannel);
06132             ast_hangup(myrpt->txchannel);
06133             myrpt->rpt_thread = AST_PTHREADT_STOP;
06134             pthread_exit(NULL);
06135          }
06136       }
06137       else
06138       {
06139          fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
06140          rpt_mutex_unlock(&myrpt->lock);
06141          ast_hangup(myrpt->rxchannel);
06142          myrpt->rpt_thread = AST_PTHREADT_STOP;
06143          pthread_exit(NULL);
06144       }
06145    }
06146    else
06147    {
06148       myrpt->txchannel = myrpt->rxchannel;
06149    }
06150    ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
06151    ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
06152    /* allocate a pseudo-channel thru asterisk */
06153    myrpt->pchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
06154    if (!myrpt->pchannel)
06155    {
06156       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
06157       rpt_mutex_unlock(&myrpt->lock);
06158       if (myrpt->txchannel != myrpt->rxchannel) 
06159          ast_hangup(myrpt->txchannel);
06160       ast_hangup(myrpt->rxchannel);
06161       myrpt->rpt_thread = AST_PTHREADT_STOP;
06162       pthread_exit(NULL);
06163    }
06164    /* make a conference for the tx */
06165    ci.chan = 0;
06166    ci.confno = -1; /* make a new conf */
06167    ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER;
06168    /* first put the channel on the conference in proper mode */
06169    if (ioctl(myrpt->txchannel->fds[0],ZT_SETCONF,&ci) == -1)
06170    {
06171       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
06172       rpt_mutex_unlock(&myrpt->lock);
06173       ast_hangup(myrpt->pchannel);
06174       if (myrpt->txchannel != myrpt->rxchannel) 
06175          ast_hangup(myrpt->txchannel);
06176       ast_hangup(myrpt->rxchannel);
06177       myrpt->rpt_thread = AST_PTHREADT_STOP;
06178       pthread_exit(NULL);
06179    }
06180    /* save tx conference number */
06181    myrpt->txconf = ci.confno;
06182    /* make a conference for the pseudo */
06183    ci.chan = 0;
06184    ci.confno = -1; /* make a new conf */
06185    ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? ZT_CONF_CONFANNMON :
06186       (ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER);
06187    /* first put the channel on the conference in announce mode */
06188    if (ioctl(myrpt->pchannel->fds[0],ZT_SETCONF,&ci) == -1)
06189    {
06190       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
06191       rpt_mutex_unlock(&myrpt->lock);
06192       ast_hangup(myrpt->pchannel);
06193       if (myrpt->txchannel != myrpt->rxchannel) 
06194          ast_hangup(myrpt->txchannel);
06195       ast_hangup(myrpt->rxchannel);
06196       myrpt->rpt_thread = AST_PTHREADT_STOP;
06197       pthread_exit(NULL);
06198    }
06199    /* save pseudo channel conference number */
06200    myrpt->conf = ci.confno;
06201    /* allocate a pseudo-channel thru asterisk */
06202    myrpt->txpchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
06203    if (!myrpt->txpchannel)
06204    {
06205       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
06206       rpt_mutex_unlock(&myrpt->lock);
06207       ast_hangup(myrpt->pchannel);
06208       if (myrpt->txchannel != myrpt->rxchannel) 
06209          ast_hangup(myrpt->txchannel);
06210       ast_hangup(myrpt->rxchannel);
06211       myrpt->rpt_thread = AST_PTHREADT_STOP;
06212       pthread_exit(NULL);
06213    }
06214    /* make a conference for the tx */
06215    ci.chan = 0;
06216    ci.confno = myrpt->txconf;
06217    ci.confmode = ZT_CONF_CONF | ZT_CONF_TALKER ;
06218    /* first put the channel on the conference in proper mode */
06219    if (ioctl(myrpt->txpchannel->fds[0],ZT_SETCONF,&ci) == -1)
06220    {
06221       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
06222       rpt_mutex_unlock(&myrpt->lock);
06223       ast_hangup(myrpt->txpchannel);
06224       ast_hangup(myrpt->pchannel);
06225       if (myrpt->txchannel != myrpt->rxchannel) 
06226          ast_hangup(myrpt->txchannel);
06227       ast_hangup(myrpt->rxchannel);
06228       myrpt->rpt_thread = AST_PTHREADT_STOP;
06229       pthread_exit(NULL);
06230    }
06231    /* Now, the idea here is to copy from the physical rx channel buffer
06232       into the pseudo tx buffer, and from the pseudo rx buffer into the 
06233       tx channel buffer */
06234    myrpt->links.next = &myrpt->links;
06235    myrpt->links.prev = &myrpt->links;
06236    myrpt->tailtimer = 0;
06237    myrpt->totimer = 0;
06238    myrpt->tmsgtimer = myrpt->p.tailmessagetime;
06239    myrpt->idtimer = myrpt->p.politeid;
06240    myrpt->mustid = myrpt->tailid = 0;
06241    myrpt->callmode = 0;
06242    myrpt->tounkeyed = 0;
06243    myrpt->tonotify = 0;
06244    myrpt->retxtimer = 0;
06245    myrpt->skedtimer = 0;
06246    myrpt->tailevent = 0;
06247    lasttx = 0;
06248    myrpt->keyed = 0;
06249    idtalkover = ast_variable_retrieve(myrpt->cfg, myrpt->name, "idtalkover");
06250    myrpt->dtmfidx = -1;
06251    myrpt->dtmfbuf[0] = 0;
06252    myrpt->rem_dtmfidx = -1;
06253    myrpt->rem_dtmfbuf[0] = 0;
06254    myrpt->dtmf_time = 0;
06255    myrpt->rem_dtmf_time = 0;
06256    myrpt->enable = 1;
06257    myrpt->disgorgetime = 0;
06258    myrpt->lastnodewhichkeyedusup[0] = '\0';
06259    myrpt->dailytxtime = 0;
06260    myrpt->totaltxtime = 0;
06261    myrpt->dailykeyups = 0;
06262    myrpt->totalkeyups = 0;
06263    myrpt->dailykerchunks = 0;
06264    myrpt->totalkerchunks = 0;
06265    myrpt->dailyexecdcommands = 0;
06266    myrpt->totalexecdcommands = 0;
06267    myrpt->timeouts = 0;
06268    myrpt->exten[0] = '\0';
06269    myrpt->lastdtmfcommand[0] = '\0';
06270    if (myrpt->p.startupmacro)
06271    {
06272       snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro);
06273    }
06274    rpt_mutex_unlock(&myrpt->lock);
06275    val = 0;
06276    ast_channel_setoption(myrpt->rxchannel,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0);
06277    val = 1;
06278    ast_channel_setoption(myrpt->rxchannel,AST_OPTION_RELAXDTMF,&val,sizeof(char),0);
06279    while (ms >= 0)
06280    {
06281       struct ast_frame *f;
06282       struct ast_channel *cs[300];
06283       int totx=0,elap=0,n,toexit=0;
06284 
06285       /* DEBUG Dump */
06286       if((myrpt->disgorgetime) && (time(NULL) >= myrpt->disgorgetime)){
06287          struct rpt_link *zl;
06288          struct rpt_tele *zt;
06289 
06290          myrpt->disgorgetime = 0;
06291          ast_log(LOG_NOTICE,"********** Variable Dump Start (app_rpt) **********\n");
06292          ast_log(LOG_NOTICE,"totx = %d\n",totx);
06293          ast_log(LOG_NOTICE,"remrx = %d\n",remrx);
06294          ast_log(LOG_NOTICE,"lasttx = %d\n",lasttx);
06295          ast_log(LOG_NOTICE,"elap = %d\n",elap);
06296          ast_log(LOG_NOTICE,"toexit = %d\n",toexit);
06297 
06298          ast_log(LOG_NOTICE,"myrpt->keyed = %d\n",myrpt->keyed);
06299          ast_log(LOG_NOTICE,"myrpt->localtx = %d\n",myrpt->localtx);
06300          ast_log(LOG_NOTICE,"myrpt->callmode = %d\n",myrpt->callmode);
06301          ast_log(LOG_NOTICE,"myrpt->enable = %d\n",myrpt->enable);
06302          ast_log(LOG_NOTICE,"myrpt->mustid = %d\n",myrpt->mustid);
06303          ast_log(LOG_NOTICE,"myrpt->tounkeyed = %d\n",myrpt->tounkeyed);
06304          ast_log(LOG_NOTICE,"myrpt->tonotify = %d\n",myrpt->tonotify);
06305          ast_log(LOG_NOTICE,"myrpt->retxtimer = %ld\n",myrpt->retxtimer);
06306          ast_log(LOG_NOTICE,"myrpt->totimer = %d\n",myrpt->totimer);
06307          ast_log(LOG_NOTICE,"myrpt->tailtimer = %d\n",myrpt->tailtimer);
06308          ast_log(LOG_NOTICE,"myrpt->tailevent = %d\n",myrpt->tailevent);
06309 
06310          zl = myrpt->links.next;
06311                   while(zl != &myrpt->links){
06312             ast_log(LOG_NOTICE,"*** Link Name: %s ***\n",zl->name);
06313             ast_log(LOG_NOTICE,"        link->lasttx %d\n",zl->lasttx);
06314             ast_log(LOG_NOTICE,"        link->lastrx %d\n",zl->lastrx);
06315             ast_log(LOG_NOTICE,"        link->connected %d\n",zl->connected);
06316             ast_log(LOG_NOTICE,"        link->hasconnected %d\n",zl->hasconnected);
06317             ast_log(LOG_NOTICE,"        link->outbound %d\n",zl->outbound);
06318             ast_log(LOG_NOTICE,"        link->disced %d\n",zl->disced);
06319             ast_log(LOG_NOTICE,"        link->killme %d\n",zl->killme);
06320             ast_log(LOG_NOTICE,"        link->disctime %ld\n",zl->disctime);
06321             ast_log(LOG_NOTICE,"        link->retrytimer %ld\n",zl->retrytimer);
06322             ast_log(LOG_NOTICE,"        link->retries = %d\n",zl->retries);
06323             ast_log(LOG_NOTICE,"        link->reconnects = %d\n",zl->reconnects);
06324                            zl = zl->next;
06325                   }
06326                                                                                                                                
06327          zt = myrpt->tele.next;
06328          if(zt != &myrpt->tele)
06329             ast_log(LOG_NOTICE,"*** Telemetry Queue ***\n");
06330                   while(zt != &myrpt->tele){
06331             ast_log(LOG_NOTICE,"        Telemetry mode: %d\n",zt->mode);
06332                            zt = zt->next;
06333                   }
06334          ast_log(LOG_NOTICE,"******* Variable Dump End (app_rpt) *******\n");
06335 
06336       }  
06337 
06338 
06339       if (myrpt->reload)
06340       {
06341          struct rpt_tele *telem;
06342 
06343          rpt_mutex_lock(&myrpt->lock);
06344          telem = myrpt->tele.next;
06345          while(telem != &myrpt->tele)
06346          {
06347             ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
06348             telem = telem->next;
06349          }
06350          myrpt->reload = 0;
06351          rpt_mutex_unlock(&myrpt->lock);
06352          usleep(10000);
06353          /* find our index, and load the vars */
06354          for(i = 0; i < nrpts; i++)
06355          {
06356             if (&rpt_vars[i] == myrpt)
06357             {
06358                load_rpt_vars(i,0);
06359                break;
06360             }
06361          }
06362       }
06363 
06364       rpt_mutex_lock(&myrpt->lock);
06365       if (ast_check_hangup(myrpt->rxchannel)) break;
06366       if (ast_check_hangup(myrpt->txchannel)) break;
06367       if (ast_check_hangup(myrpt->pchannel)) break;
06368       if (ast_check_hangup(myrpt->txpchannel)) break;
06369 
06370       /* Update local tx with keyed if not parsing a command */
06371       myrpt->localtx = myrpt->keyed && (myrpt->dtmfidx == -1) && (!myrpt->cmdnode[0]);
06372       /* If someone's connected, and they're transmitting from their end to us, set remrx true */
06373       l = myrpt->links.next;
06374       remrx = 0;
06375       while(l != &myrpt->links)
06376       {
06377          if (l->lastrx){
06378             remrx = 1;
06379             if(l->name[0] != '0') /* Ignore '0' nodes */
06380                strcpy(myrpt->lastnodewhichkeyedusup, l->name); /* Note the node which is doing the key up */
06381          }
06382          l = l->next;
06383       }
06384       /* Create a "must_id" flag for the cleanup ID */      
06385       myrpt->mustid |= (myrpt->idtimer) && (myrpt->keyed || remrx) ;
06386       /* Build a fresh totx from myrpt->keyed and autopatch activated */
06387       totx = myrpt->callmode;
06388       /* If full duplex, add local tx to totx */
06389       if (myrpt->p.duplex > 1) totx = totx || myrpt->localtx;
06390       /* Traverse the telemetry list to see what's queued */
06391       identqueued = 0;
06392       othertelemqueued = 0;
06393       tailmessagequeued = 0;
06394       ctqueued = 0;
06395       telem = myrpt->tele.next;
06396       while(telem != &myrpt->tele)
06397       {
06398          if((telem->mode == ID) || (telem->mode == IDTALKOVER)){
06399             identqueued = 1; /* Identification telemetry */
06400          }
06401          else if(telem->mode == TAILMSG)
06402          {
06403             tailmessagequeued = 1; /* Tail message telemetry */
06404          }
06405          else
06406          {
06407             if (telem->mode != UNKEY)
06408                othertelemqueued = 1;  /* Other telemetry */
06409             else
06410                ctqueued = 1; /* Courtesy tone telemetry */
06411          }
06412          telem = telem->next;
06413       }
06414    
06415       /* Add in any "other" telemetry, if 3/4 or full duplex */
06416       if (myrpt->p.duplex > 0) totx = totx || othertelemqueued;
06417       /* Update external (to links) transmitter PTT state with everything but ID, CT, and tailmessage telemetry */
06418       myrpt->exttx = totx;
06419       /* If half or 3/4 duplex, add localtx to external link tx */
06420       if (myrpt->p.duplex < 2) myrpt->exttx = myrpt->exttx || myrpt->localtx;
06421       /* Add in ID telemetry to local transmitter */
06422       totx = totx || remrx;
06423       /* If 3/4 or full duplex, add in ident and CT telemetry */
06424       if (myrpt->p.duplex > 0)
06425          totx = totx || identqueued || ctqueued;
06426       /* Reset time out timer variables if there is no activity */
06427       if (!totx) 
06428       {
06429          myrpt->totimer = myrpt->p.totime;
06430          myrpt->tounkeyed = 0;
06431          myrpt->tonotify = 0;
06432       }
06433       else
06434          myrpt->tailtimer = myrpt->p.hangtime; /* Initialize tail timer */
06435       /* Disable the local transmitter if we are timed out */
06436       totx = totx && myrpt->totimer;
06437       /* if timed-out and not said already, say it */
06438       if ((!myrpt->totimer) && (!myrpt->tonotify))
06439       {
06440          myrpt->tonotify = 1;
06441          myrpt->timeouts++;
06442          rpt_mutex_unlock(&myrpt->lock);
06443          rpt_telemetry(myrpt,TIMEOUT,NULL);
06444          rpt_mutex_lock(&myrpt->lock);
06445       }
06446 
06447       /* If unkey and re-key, reset time out timer */
06448       if ((!totx) && (!myrpt->totimer) && (!myrpt->tounkeyed) && (!myrpt->keyed))
06449       {
06450          myrpt->tounkeyed = 1;
06451       }
06452       if ((!totx) && (!myrpt->totimer) && myrpt->tounkeyed && myrpt->keyed)
06453       {
06454          myrpt->totimer = myrpt->p.totime;
06455          myrpt->tounkeyed = 0;
06456          myrpt->tonotify = 0;
06457          rpt_mutex_unlock(&myrpt->lock);
06458          continue;
06459       }
06460       /* if timed-out and in circuit busy after call */
06461       if ((!totx) && (!myrpt->totimer) && (myrpt->callmode == 4))
06462       {
06463          myrpt->callmode = 0;
06464       }
06465       /* get rid of tail if timed out */
06466       if (!myrpt->totimer) myrpt->tailtimer = 0;
06467       /* if not timed-out, add in tail */
06468       if (myrpt->totimer) totx = totx || myrpt->tailtimer;
06469       /* If user or links key up or are keyed up over standard ID, switch to talkover ID, if one is defined */
06470       /* If tail message, kill the message if someone keys up over it */ 
06471       if ((myrpt->keyed || remrx) && ((identqueued && idtalkover) || (tailmessagequeued))) {
06472          int hasid = 0,hastalkover = 0;
06473 
06474          telem = myrpt->tele.next;
06475          while(telem != &myrpt->tele){
06476             if(telem->mode == ID){
06477                if (telem->chan) ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV); /* Whoosh! */
06478                hasid = 1;
06479             }
06480             if(telem->mode == TAILMSG){
06481                                         if (telem->chan) ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV); /* Whoosh! */
06482                                 }
06483             if (telem->mode == IDTALKOVER) hastalkover = 1;
06484             telem = telem->next;
06485          }
06486          rpt_mutex_unlock(&myrpt->lock);
06487          if (hasid && (!hastalkover)) rpt_telemetry(myrpt, IDTALKOVER, NULL); /* Start Talkover ID */
06488          rpt_mutex_lock(&myrpt->lock);
06489       }
06490       /* Try to be polite */
06491       /* If the repeater has been inactive for longer than the ID time, do an initial ID in the tail*/
06492       /* If within 30 seconds of the time to ID, try do it in the tail */
06493       /* else if at ID time limit, do it right over the top of them */
06494       /* Lastly, if the repeater has been keyed, and the ID timer is expired, do a clean up ID */
06495       if(myrpt->mustid && (!myrpt->idtimer))
06496          queue_id(myrpt);
06497 
06498       if ((totx && (!myrpt->exttx) &&
06499           (myrpt->idtimer <= myrpt->p.politeid) && myrpt->tailtimer)) 
06500          {
06501             myrpt->tailid = 1;
06502          }
06503 
06504       /* If tail timer expires, then check for tail messages */
06505 
06506       if(myrpt->tailevent){
06507          myrpt->tailevent = 0;
06508          if(myrpt->tailid){
06509             totx = 1;
06510             queue_id(myrpt);
06511          }
06512          else if ((myrpt->p.tailmessages[0]) &&
06513             (myrpt->p.tailmessagetime) && (myrpt->tmsgtimer == 0)){
06514                totx = 1;
06515                myrpt->tmsgtimer = myrpt->p.tailmessagetime; 
06516                rpt_mutex_unlock(&myrpt->lock);
06517                rpt_telemetry(myrpt, TAILMSG, NULL);
06518                rpt_mutex_lock(&myrpt->lock);
06519          }  
06520       }
06521 
06522       /* Main TX control */
06523 
06524       /* let telemetry transmit anyway (regardless of timeout) */
06525       if (myrpt->p.duplex > 0) totx = totx || (myrpt->tele.next != &myrpt->tele);
06526       if (totx && (!lasttx))
06527       {
06528          lasttx = 1;
06529          myrpt->dailykeyups++;
06530          myrpt->totalkeyups++;
06531          rpt_mutex_unlock(&myrpt->lock);
06532          ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
06533          rpt_mutex_lock(&myrpt->lock);
06534       }
06535       totx = totx && myrpt->enable;
06536       if ((!totx) && lasttx)
06537       {
06538          lasttx = 0;
06539          rpt_mutex_unlock(&myrpt->lock);
06540          ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
06541          rpt_mutex_lock(&myrpt->lock);
06542       }
06543       time(&t);
06544       /* if DTMF timeout */
06545       if ((!myrpt->cmdnode[0]) && (myrpt->dtmfidx >= 0) && ((myrpt->dtmf_time + DTMF_TIMEOUT) < t))
06546       {
06547          myrpt->dtmfidx = -1;
06548          myrpt->dtmfbuf[0] = 0;
06549       }        
06550       /* if remote DTMF timeout */
06551       if ((myrpt->rem_dtmfidx >= 0) && ((myrpt->rem_dtmf_time + DTMF_TIMEOUT) < t))
06552       {
06553          myrpt->rem_dtmfidx = -1;
06554          myrpt->rem_dtmfbuf[0] = 0;
06555       }  
06556 
06557       /* Reconnect */
06558    
06559       l = myrpt->links.next;
06560       while(l != &myrpt->links)
06561       {
06562          if (l->killme)
06563          {
06564             /* remove from queue */
06565             remque((struct qelem *) l);
06566             if (!strcmp(myrpt->cmdnode,l->name))
06567                myrpt->cmdnode[0] = 0;
06568             rpt_mutex_unlock(&myrpt->lock);
06569             /* hang-up on call to device */
06570             if (l->chan) ast_hangup(l->chan);
06571             ast_hangup(l->pchan);
06572             free(l);
06573             rpt_mutex_lock(&myrpt->lock);
06574             /* re-start link traversal */
06575             l = myrpt->links.next;
06576             continue;
06577          }
06578          l = l->next;
06579       }
06580       n = 0;
06581       cs[n++] = myrpt->rxchannel;
06582       cs[n++] = myrpt->pchannel;
06583       cs[n++] = myrpt->txpchannel;
06584       if (myrpt->txchannel != myrpt->rxchannel) cs[n++] = myrpt->txchannel;
06585       l = myrpt->links.next;
06586       while(l != &myrpt->links)
06587       {
06588          if ((!l->killme) && (!l->disctime) && l->chan)
06589          {
06590             cs[n++] = l->chan;
06591             cs[n++] = l->pchan;
06592          }
06593          l = l->next;
06594       }
06595       rpt_mutex_unlock(&myrpt->lock);
06596       ms = MSWAIT;
06597       who = ast_waitfor_n(cs,n,&ms);
06598       if (who == NULL) ms = 0;
06599       elap = MSWAIT - ms;
06600       rpt_mutex_lock(&myrpt->lock);
06601       l = myrpt->links.next;
06602       while(l != &myrpt->links)
06603       {
06604          if (!l->lasttx)
06605          {
06606             if ((l->retxtimer += elap) >= REDUNDANT_TX_TIME)
06607             {
06608                l->retxtimer = 0;
06609                if (l->chan) ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
06610             }
06611          } else l->retxtimer = 0;
06612          if (l->disctime) /* Disconnect timer active on a channel ? */
06613          {
06614             l->disctime -= elap;
06615             if (l->disctime <= 0) /* Disconnect timer expired on inbound channel ? */
06616                l->disctime = 0; /* Yep */
06617          }
06618 
06619          if (l->retrytimer)
06620          {
06621             l->retrytimer -= elap;
06622             if (l->retrytimer < 0) l->retrytimer = 0;
06623          }
06624 
06625          /* Tally connect time */
06626          l->connecttime += elap;
06627 
06628          /* ignore non-timing channels */
06629          if (l->elaptime < 0)
06630          {
06631             l = l->next;
06632             continue;
06633          }
06634          l->elaptime += elap;
06635          /* if connection has taken too long */
06636          if ((l->elaptime > MAXCONNECTTIME) && 
06637             ((!l->chan) || (l->chan->_state != AST_STATE_UP)))
06638          {
06639             l->elaptime = 0;
06640             rpt_mutex_unlock(&myrpt->lock);
06641             if (l->chan) ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
06642             rpt_mutex_lock(&myrpt->lock);
06643             break;
06644          }
06645          if ((!l->chan) && (!l->retrytimer) && l->outbound && 
06646             (l->retries++ < MAX_RETRIES) && (l->hasconnected))
06647          {
06648             if (l->chan) ast_hangup(l->chan);
06649             rpt_mutex_unlock(&myrpt->lock);
06650             if ((l->name[0] != '0') && (!l->isremote))
06651             {
06652                l->retrytimer = MAX_RETRIES + 1;
06653             }
06654             else 
06655             {
06656                if (attempt_reconnect(myrpt,l) == -1)
06657                {
06658                   l->retrytimer = RETRY_TIMER_MS;
06659                }
06660             }
06661             rpt_mutex_lock(&myrpt->lock);
06662             break;
06663          }
06664          if ((!l->chan) && (!l->retrytimer) && l->outbound &&
06665             (l->retries >= MAX_RETRIES))
06666          {
06667             /* remove from queue */
06668             remque((struct qelem *) l);
06669             if (!strcmp(myrpt->cmdnode,l->name))
06670                myrpt->cmdnode[0] = 0;
06671             rpt_mutex_unlock(&myrpt->lock);
06672             if (l->name[0] != '0')
06673             {
06674                if (!l->hasconnected)
06675                   rpt_telemetry(myrpt,CONNFAIL,l);
06676                else rpt_telemetry(myrpt,REMDISC,l);
06677             }
06678             /* hang-up on call to device */
06679             ast_hangup(l->pchan);
06680             free(l);
06681                                 rpt_mutex_lock(&myrpt->lock);
06682             break;
06683          }
06684                         if ((!l->chan) && (!l->disctime) && (!l->outbound))
06685                         {
06686                                 /* remove from queue */
06687                                 remque((struct qelem *) l);
06688                                 if (!strcmp(myrpt->cmdnode,l->name))
06689                                         myrpt->cmdnode[0] = 0;
06690                                 rpt_mutex_unlock(&myrpt->lock);
06691             if (l->name[0] != '0') 
06692             {
06693                                    rpt_telemetry(myrpt,REMDISC,l);
06694             }
06695                                 /* hang-up on call to device */
06696                                 ast_hangup(l->pchan);
06697                                 free(l);
06698                                 rpt_mutex_lock(&myrpt->lock);
06699                                 break;
06700                         }
06701          l = l->next;
06702       }
06703       if(totx){
06704          myrpt->dailytxtime += elap;
06705          myrpt->totaltxtime += elap;
06706       }
06707       i = myrpt->tailtimer;
06708       if (myrpt->tailtimer) myrpt->tailtimer -= elap;
06709       if (myrpt->tailtimer < 0) myrpt->tailtimer = 0;
06710       if((i) && (myrpt->tailtimer == 0))
06711          myrpt->tailevent = 1;
06712       if (myrpt->totimer) myrpt->totimer -= elap;
06713       if (myrpt->totimer < 0) myrpt->totimer = 0;
06714       if (myrpt->idtimer) myrpt->idtimer -= elap;
06715       if (myrpt->idtimer < 0) myrpt->idtimer = 0;
06716       if (myrpt->tmsgtimer) myrpt->tmsgtimer -= elap;
06717       if (myrpt->tmsgtimer < 0) myrpt->tmsgtimer = 0;
06718       /* do macro timers */
06719       if (myrpt->macrotimer) myrpt->macrotimer -= elap;
06720       if (myrpt->macrotimer < 0) myrpt->macrotimer = 0;
06721       /* Execute scheduler appx. every 2 tenths of a second */
06722       if (myrpt->skedtimer <= 0){
06723          myrpt->skedtimer = 200;
06724          do_scheduler(myrpt);
06725       }
06726       else
06727          myrpt->skedtimer -=elap;
06728       if (!ms) 
06729       {
06730          rpt_mutex_unlock(&myrpt->lock);
06731          continue;
06732       }
06733       c = myrpt->macrobuf[0];
06734       if (c && (!myrpt->macrotimer))
06735       {
06736          myrpt->macrotimer = MACROTIME;
06737          memmove(myrpt->macrobuf,myrpt->macrobuf + 1,MAXMACRO - 1);
06738          if ((c == 'p') || (c == 'P'))
06739             myrpt->macrotimer = MACROPTIME;
06740          rpt_mutex_unlock(&myrpt->lock);
06741          local_dtmf_helper(myrpt,c);
06742       } else rpt_mutex_unlock(&myrpt->lock);
06743       if (who == myrpt->rxchannel) /* if it was a read from rx */
06744       {
06745          f = ast_read(myrpt->rxchannel);
06746          if (!f)
06747          {
06748             if (debug) printf("@@@@ rpt:Hung Up\n");
06749             break;
06750          }
06751          if (f->frametype == AST_FRAME_VOICE)
06752          {
06753 #ifdef   _MDC_DECODE_H_
06754             unsigned char ubuf[2560];
06755             short *sp;
06756             int n;
06757 #endif
06758 
06759             if (!myrpt->localtx) {
06760                memset(f->data,0,f->datalen);
06761             }
06762 
06763 #ifdef   _MDC_DECODE_H_
06764             sp = (short *) f->data;
06765             /* convert block to unsigned char */
06766             for(n = 0; n < f->datalen / 2; n++)
06767             {
06768                ubuf[n] = (*sp++ >> 8) + 128;
06769             }
06770             n = mdc_decoder_process_samples(myrpt->mdc,ubuf,f->datalen / 2);
06771             if (n == 1)
06772             {
06773                   unsigned char op,arg;
06774                   unsigned short unitID;
06775 
06776                   mdc_decoder_get_packet(myrpt->mdc,&op,&arg,&unitID);
06777                   if (debug > 2)
06778                   {
06779                      ast_log(LOG_NOTICE,"Got (single-length) packet:\n");
06780                      ast_log(LOG_NOTICE,"op: %02x, arg: %02x, UnitID: %04x\n",
06781                         op & 255,arg & 255,unitID);
06782                   }
06783                   if ((op == 1) && (arg == 0))
06784                   {
06785                      myrpt->lastunit = unitID;
06786                   }
06787             }
06788             if ((debug > 2) && (i == 2))
06789             {
06790                unsigned char op,arg,ex1,ex2,ex3,ex4;
06791                unsigned short unitID;
06792 
06793                mdc_decoder_get_double_packet(myrpt->mdc,&op,&arg,&unitID,
06794                   &ex1,&ex2,&ex3,&ex4);
06795                ast_log(LOG_NOTICE,"Got (double-length) packet:\n");
06796                ast_log(LOG_NOTICE,"op: %02x, arg: %02x, UnitID: %04x\n",
06797                   op & 255,arg & 255,unitID);
06798                ast_log(LOG_NOTICE,"ex1: %02x, ex2: %02x, ex3: %02x, ex4: %02x\n",
06799                   ex1 & 255, ex2 & 255, ex3 & 255, ex4 & 255);
06800             }
06801 #endif
06802 #ifdef   __RPT_NOTCH
06803             /* apply inbound filters, if any */
06804             rpt_filter(myrpt,f->data,f->datalen / 2);
06805 #endif
06806             ast_write(myrpt->pchannel,f);
06807          }
06808          else if (f->frametype == AST_FRAME_DTMF)
06809          {
06810             c = (char) f->subclass; /* get DTMF char */
06811             ast_frfree(f);
06812             if (!myrpt->keyed) continue;
06813             local_dtmf_helper(myrpt,c);
06814             continue;
06815          }                 
06816          else if (f->frametype == AST_FRAME_CONTROL)
06817          {
06818             if (f->subclass == AST_CONTROL_HANGUP)
06819             {
06820                if (debug) printf("@@@@ rpt:Hung Up\n");
06821                ast_frfree(f);
06822                break;
06823             }
06824             /* if RX key */
06825             if (f->subclass == AST_CONTROL_RADIO_KEY)
06826             {
06827                if ((!lasttx) || (myrpt->p.duplex > 1))
06828                {
06829                   if (debug == 7) printf("@@@@ rx key\n");
06830                   myrpt->keyed = 1;
06831                }
06832             }
06833             /* if RX un-key */
06834             if (f->subclass == AST_CONTROL_RADIO_UNKEY)
06835             {
06836                if ((!lasttx) || (myrpt->p.duplex > 1))
06837                {
06838                   if (debug == 7) printf("@@@@ rx un-key\n");
06839                   if(myrpt->keyed) {
06840                      rpt_telemetry(myrpt,UNKEY,NULL);
06841                   }
06842                   myrpt->keyed = 0;
06843                }
06844             }
06845          }
06846          ast_frfree(f);
06847          continue;
06848       }
06849       if (who == myrpt->pchannel) /* if it was a read from pseudo */
06850       {
06851          f = ast_read(myrpt->pchannel);
06852          if (!f)
06853          {
06854             if (debug) printf("@@@@ rpt:Hung Up\n");
06855             break;
06856          }
06857          if (f->frametype == AST_FRAME_VOICE)
06858          {
06859             ast_write(myrpt->txpchannel,f);
06860          }
06861          if (f->frametype == AST_FRAME_CONTROL)
06862          {
06863             if (f->subclass == AST_CONTROL_HANGUP)
06864             {
06865                if (debug) printf("@@@@ rpt:Hung Up\n");
06866                ast_frfree(f);
06867                break;
06868             }
06869          }
06870          ast_frfree(f);
06871          continue;
06872       }
06873       if (who == myrpt->txchannel) /* if it was a read from tx */
06874       {
06875          f = ast_read(myrpt->txchannel);
06876          if (!f)
06877          {
06878             if (debug) printf("@@@@ rpt:Hung Up\n");
06879             break;
06880          }
06881          if (f->frametype == AST_FRAME_CONTROL)
06882          {
06883             if (f->subclass == AST_CONTROL_HANGUP)
06884             {
06885                if (debug) printf("@@@@ rpt:Hung Up\n");
06886                ast_frfree(f);
06887                break;
06888             }
06889          }
06890          ast_frfree(f);
06891          continue;
06892       }
06893       toexit = 0;
06894       rpt_mutex_lock(&myrpt->lock);
06895       l = myrpt->links.next;
06896       while(l != &myrpt->links)
06897       {
06898          if (l->disctime)
06899          {
06900             l = l->next;
06901             continue;
06902          }
06903          if (who == l->chan) /* if it was a read from rx */
06904          {
06905             remrx = 0;
06906             /* see if any other links are receiving */
06907             m = myrpt->links.next;
06908             while(m != &myrpt->links)
06909             {
06910                /* if not us, count it */
06911                if ((m != l) && (m->lastrx)) remrx = 1;
06912                m = m->next;
06913             }
06914             rpt_mutex_unlock(&myrpt->lock);
06915             totx = (((l->isremote) ? myrpt->localtx : 
06916                myrpt->exttx) || remrx) && l->mode;
06917             if (l->chan && (l->lasttx != totx))
06918             {
06919                if (totx)
06920                {
06921                   ast_indicate(l->chan,AST_CONTROL_RADIO_KEY);
06922                }
06923                else
06924                {
06925                   ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
06926                }
06927             }
06928             l->lasttx = totx;
06929             f = ast_read(l->chan);
06930             if (!f)
06931             {
06932                if ((!l->disced) && (!l->outbound))
06933                {
06934                   if ((l->name[0] == '0') || l->isremote)
06935                      l->disctime = 1;
06936                   else
06937                      l->disctime = DISC_TIME;
06938                   rpt_mutex_lock(&myrpt->lock);
06939                   ast_hangup(l->chan);
06940                   l->chan = 0;
06941                   break;
06942                }
06943 
06944                if (l->retrytimer) 
06945                {
06946                   rpt_mutex_lock(&myrpt->lock);
06947                   break; 
06948                }
06949                if (l->outbound && (l->retries++ < MAX_RETRIES) && (l->hasconnected))
06950                {
06951                   rpt_mutex_lock(&myrpt->lock);
06952                   ast_hangup(l->chan);
06953                   l->chan = 0;
06954                   rpt_mutex_unlock(&myrpt->lock);
06955                   if (attempt_reconnect(myrpt,l) == -1)
06956                   {
06957                      l->retrytimer = RETRY_TIMER_MS;
06958                   }
06959                   rpt_mutex_lock(&myrpt->lock);
06960                   break;
06961                }
06962                rpt_mutex_lock(&myrpt->lock);
06963                /* remove from queue */
06964                remque((struct qelem *) l);
06965                if (!strcmp(myrpt->cmdnode,l->name))
06966                   myrpt->cmdnode[0] = 0;
06967                rpt_mutex_unlock(&myrpt->lock);
06968                if (!l->hasconnected)
06969                   rpt_telemetry(myrpt,CONNFAIL,l);
06970                else if (l->disced != 2) rpt_telemetry(myrpt,REMDISC,l);
06971                /* hang-up on call to device */
06972                ast_hangup(l->chan);
06973                ast_hangup(l->pchan);
06974                free(l);
06975                rpt_mutex_lock(&myrpt->lock);
06976                break;
06977             }
06978             if (f->frametype == AST_FRAME_VOICE)
06979             {
06980                if (!l->lastrx)
06981                {
06982                   memset(f->data,0,f->datalen);
06983                }
06984                ast_write(l->pchan,f);
06985             }
06986             if (f->frametype == AST_FRAME_TEXT)
06987             {
06988                handle_link_data(myrpt,l,f->data);
06989             }
06990             if (f->frametype == AST_FRAME_DTMF)
06991             {
06992                handle_link_phone_dtmf(myrpt,l,f->subclass);
06993             }
06994             if (f->frametype == AST_FRAME_CONTROL)
06995             {
06996                if (f->subclass == AST_CONTROL_ANSWER)
06997                {
06998                   char lconnected = l->connected;
06999                   l->connected = 1;
07000                   l->hasconnected = 1;
07001                   l->elaptime = -1;
07002                   l->retries = 0;
07003                   if (!lconnected) 
07004                      rpt_telemetry(myrpt,CONNECTED,l);
07005                   else
07006                      l->reconnects++;
07007                }
07008                /* if RX key */
07009                if (f->subclass == AST_CONTROL_RADIO_KEY)
07010                {
07011                   if (debug == 7 ) printf("@@@@ rx key\n");
07012                   l->lastrx = 1;
07013                }
07014                /* if RX un-key */
07015                if (f->subclass == AST_CONTROL_RADIO_UNKEY)
07016                {
07017                   if (debug == 7) printf("@@@@ rx un-key\n");
07018                   l->lastrx = 0;
07019                }
07020                if (f->subclass == AST_CONTROL_HANGUP)
07021                {
07022                   ast_frfree(f);
07023                   if ((!l->outbound) && (!l->disced))
07024                   {
07025                      if ((l->name[0] == '0') || l->isremote)
07026                         l->disctime = 1;
07027                      else
07028                         l->disctime = DISC_TIME;
07029                      rpt_mutex_lock(&myrpt->lock);
07030                      ast_hangup(l->chan);
07031                      l->chan = 0;
07032                      break;
07033                   }
07034                   if (l->retrytimer) 
07035                   {
07036                      rpt_mutex_lock(&myrpt->lock);
07037                      break;
07038                   }
07039                   if (l->outbound && (l->retries++ < MAX_RETRIES) && (l->hasconnected))
07040                   {
07041                      rpt_mutex_lock(&myrpt->lock);
07042                      ast_hangup(l->chan);
07043                      l->chan = 0;
07044                      rpt_mutex_unlock(&myrpt->lock);
07045                      if (attempt_reconnect(myrpt,l) == -1)
07046                      {
07047                         l->retrytimer = RETRY_TIMER_MS;
07048                      }
07049                      rpt_mutex_lock(&myrpt->lock);
07050                      break;
07051                   }
07052                   rpt_mutex_lock(&myrpt->lock);
07053                   /* remove from queue */
07054                   remque((struct qelem *) l);
07055                   if (!strcmp(myrpt->cmdnode,l->name))
07056                      myrpt->cmdnode[0] = 0;
07057                   rpt_mutex_unlock(&myrpt->lock);
07058                   if (!l->hasconnected)
07059                      rpt_telemetry(myrpt,CONNFAIL,l);
07060                   else if (l->disced != 2) rpt_telemetry(myrpt,REMDISC,l);
07061                   /* hang-up on call to device */
07062                   ast_hangup(l->chan);
07063                   ast_hangup(l->pchan);
07064                   free(l);
07065                   rpt_mutex_lock(&myrpt->lock);
07066                   break;
07067                }
07068             }
07069             ast_frfree(f);
07070             rpt_mutex_lock(&myrpt->lock);
07071             break;
07072          }
07073          if (who == l->pchan) 
07074          {
07075             rpt_mutex_unlock(&myrpt->lock);
07076             f = ast_read(l->pchan);
07077             if (!f)
07078             {
07079                if (debug) printf("@@@@ rpt:Hung Up\n");
07080                toexit = 1;
07081                rpt_mutex_lock(&myrpt->lock);
07082                break;
07083             }
07084             if (f->frametype == AST_FRAME_VOICE)
07085             {
07086                if (l->chan) ast_write(l->chan,f);
07087             }
07088             if (f->frametype == AST_FRAME_CONTROL)
07089             {
07090                if (f->subclass == AST_CONTROL_HANGUP)
07091                {
07092                   if (debug) printf("@@@@ rpt:Hung Up\n");
07093                   ast_frfree(f);
07094                   toexit = 1;
07095                   rpt_mutex_lock(&myrpt->lock);
07096                   break;
07097                }
07098             }
07099             ast_frfree(f);
07100             rpt_mutex_lock(&myrpt->lock);
07101             break;
07102          }
07103          l = l->next;
07104       }
07105       rpt_mutex_unlock(&myrpt->lock);
07106       if (toexit) break;
07107       if (who == myrpt->txpchannel) /* if it was a read from remote tx */
07108       {
07109          f = ast_read(myrpt->txpchannel);
07110          if (!f)
07111          {
07112             if (debug) printf("@@@@ rpt:Hung Up\n");
07113             break;
07114          }
07115          if (f->frametype == AST_FRAME_CONTROL)
07116          {
07117             if (f->subclass == AST_CONTROL_HANGUP)
07118             {
07119                if (debug) printf("@@@@ rpt:Hung Up\n");
07120                ast_frfree(f);
07121                break;
07122             }
07123          }
07124          ast_frfree(f);
07125          continue;
07126       }
07127    }
07128    usleep(100000);
07129    ast_hangup(myrpt->pchannel);
07130    ast_hangup(myrpt->txpchannel);
07131    if (myrpt->txchannel != myrpt->rxchannel) ast_hangup(myrpt->txchannel);
07132    ast_hangup(myrpt->rxchannel);
07133    rpt_mutex_lock(&myrpt->lock);
07134    l = myrpt->links.next;
07135    while(l != &myrpt->links)
07136    {
07137       struct rpt_link *ll = l;
07138       /* remove from queue */
07139       remque((struct qelem *) l);
07140       /* hang-up on call to device */
07141       if (l->chan) ast_hangup(l->chan);
07142       ast_hangup(l->pchan);
07143       l = l->next;
07144       free(ll);
07145    }
07146    rpt_mutex_unlock(&myrpt->lock);
07147    if (debug) printf("@@@@ rpt:Hung up channel\n");
07148    myrpt->rpt_thread = AST_PTHREADT_STOP;
07149    pthread_exit(NULL); 
07150    return NULL;
07151 }
07152 
07153    
07154 static void *rpt_master(void *config)
07155 {
07156 int   i,n;
07157 pthread_attr_t attr;
07158 struct ast_config *cfg;
07159    char *this;
07160    const char *val;
07161 
07162    /* go thru all the specified repeaters */
07163    this = NULL;
07164    n = 0;
07165    rpt_vars[n].cfg = config;
07166    cfg = rpt_vars[n].cfg;
07167    if (!cfg) {
07168       ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf.  Radio Repeater disabled.\n");
07169       pthread_exit(NULL);
07170    }
07171    while((this = ast_category_browse(cfg,this)) != NULL)
07172    {
07173       for(i = 0 ; i < strlen(this) ; i++){
07174          if((this[i] < '0') || (this[i] > '9'))
07175             break;
07176       }
07177       if(i != strlen(this)) continue; /* Not a node defn */
07178       memset(&rpt_vars[n],0,sizeof(rpt_vars[n]));
07179       rpt_vars[n].name = strdup(this);
07180       val = ast_variable_retrieve(cfg,this,"rxchannel");
07181       if (val) rpt_vars[n].rxchanname = strdup(val);
07182       val = ast_variable_retrieve(cfg,this,"txchannel");
07183       if (val) rpt_vars[n].txchanname = strdup(val);
07184       val = ast_variable_retrieve(cfg,this,"remote");
07185       if (val) rpt_vars[n].remote = strdup(val);
07186       ast_mutex_init(&rpt_vars[n].lock);
07187       rpt_vars[n].tele.next = &rpt_vars[n].tele;
07188       rpt_vars[n].tele.prev = &rpt_vars[n].tele;
07189       rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
07190       rpt_vars[n].tailmessagen = 0;
07191 #ifdef   _MDC_DECODE_H_
07192       rpt_vars[n].mdc = mdc_decoder_new(8000);
07193 #endif
07194       n++;
07195    }
07196    nrpts = n;
07197    ast_config_destroy(cfg);
07198 
07199    /* start em all */
07200    for(i = 0; i < n; i++)
07201    {
07202       load_rpt_vars(i,1);
07203 
07204       /* if is a remote, dont start one for it */
07205       if (rpt_vars[i].remote)
07206       {
07207          strcpy(rpt_vars[i].freq, "146.580");
07208          strcpy(rpt_vars[i].rxpl, "100.0");
07209          strcpy(rpt_vars[i].txpl, "100.0");
07210          rpt_vars[i].remmode = REM_MODE_FM;
07211          rpt_vars[i].offset = REM_SIMPLEX;
07212          rpt_vars[i].powerlevel = REM_MEDPWR;
07213          continue;
07214       }
07215       if (!rpt_vars[i].p.ident)
07216       {
07217          ast_log(LOG_WARNING,"Did not specify ident for node %s\n",rpt_vars[i].name);
07218          ast_config_destroy(cfg);
07219          pthread_exit(NULL);
07220       }
07221            pthread_attr_init(&attr);
07222            pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
07223       ast_pthread_create(&rpt_vars[i].rpt_thread,&attr,rpt,(void *) &rpt_vars[i]);
07224       pthread_attr_destroy(&attr);
07225    }
07226    usleep(500000);
07227    for(;;)
07228    {
07229       /* Now monitor each thread, and restart it if necessary */
07230       for(i = 0; i < n; i++)
07231       { 
07232          int rv;
07233          if (rpt_vars[i].remote) continue;
07234          if (rpt_vars[i].rpt_thread == AST_PTHREADT_STOP) 
07235             rv = -1;
07236          else
07237             rv = pthread_kill(rpt_vars[i].rpt_thread,0);
07238          if (rv)
07239          {
07240             if(time(NULL) - rpt_vars[i].lastthreadrestarttime <= 15)
07241             {
07242                if(rpt_vars[i].threadrestarts >= 5)
07243                {
07244                   ast_log(LOG_ERROR,"Continual RPT thread restarts, killing Asterisk\n");
07245                   exit(1); /* Stuck in a restart loop, kill Asterisk and start over */
07246                }
07247                else
07248                {
07249                   ast_log(LOG_NOTICE,"RPT thread restarted on %s\n",rpt_vars[i].name);
07250                   rpt_vars[i].threadrestarts++;
07251                }
07252             }
07253             else
07254                rpt_vars[i].threadrestarts = 0;
07255 
07256             rpt_vars[i].lastthreadrestarttime = time(NULL);
07257                  pthread_attr_init(&attr);
07258                  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
07259             ast_pthread_create(&rpt_vars[i].rpt_thread,&attr,rpt,(void *) &rpt_vars[i]);
07260             pthread_attr_destroy(&attr);
07261             ast_log(LOG_WARNING, "rpt_thread restarted on node %s\n", rpt_vars[i].name);
07262          }
07263 
07264       }
07265       usleep(2000000);
07266    }
07267    ast_config_destroy(cfg);
07268    pthread_exit(NULL);
07269 }
07270 
07271 static int rpt_exec(struct ast_channel *chan, void *data)
07272 {
07273    int res=-1,i,rem_totx,n,phone_mode = 0;
07274    struct ast_module_user *u;
07275    char tmp[256], keyed = 0;
07276    char *options,*stringp,*tele,c;
07277    struct   rpt *myrpt;
07278    struct ast_frame *f;
07279    struct ast_channel *who;
07280    struct ast_channel *cs[20];
07281    struct   rpt_link *l;
07282    ZT_CONFINFO ci;  /* conference info */
07283    ZT_PARAMS par;
07284    int ms,elap;
07285 
07286    if (ast_strlen_zero(data)) {
07287       ast_log(LOG_WARNING, "Rpt requires an argument (system node)\n");
07288       return -1;
07289    }
07290    ast_copy_string(tmp, (char *)data, sizeof(tmp));
07291    stringp=tmp;
07292    strsep(&stringp, "|");
07293    options = stringp;
07294    myrpt = NULL;
07295    /* see if we can find our specified one */
07296    for(i = 0; i < nrpts; i++)
07297    {
07298       /* if name matches, assign it and exit loop */
07299       if (!strcmp(tmp,rpt_vars[i].name))
07300       {
07301          myrpt = &rpt_vars[i];
07302          break;
07303       }
07304    }
07305    if (myrpt == NULL)
07306    {
07307       ast_log(LOG_WARNING, "Cannot find specified system node %s\n",tmp);
07308       return -1;
07309    }
07310 
07311    /* if not phone access, must be an IAX connection */
07312    if (options && ((*options == 'P') || (*options == 'D') || (*options == 'R')))
07313    {
07314       phone_mode = 1;
07315       if (*options == 'D') phone_mode = 2;
07316       ast_set_callerid(chan,"0","app_rpt user","0");
07317    }
07318    else
07319    {
07320       if (strncmp(chan->name,"IAX2",4))
07321       {
07322          ast_log(LOG_WARNING, "We only accept links via IAX2!!\n");
07323          return -1;
07324       }
07325    }
07326    if (options && (*options == 'R'))
07327    {
07328 
07329       /* Parts of this section taken from app_parkandannounce */
07330       char *return_context;
07331       int l, m, lot, timeout = 0;
07332       char tmp[256],*template;
07333       char *working, *context, *exten, *priority;
07334       char *s,*orig_s;
07335 
07336 
07337       rpt_mutex_lock(&myrpt->lock);
07338       m = myrpt->callmode;
07339       rpt_mutex_unlock(&myrpt->lock);
07340 
07341       if ((!myrpt->p.nobusyout) && m)
07342       {
07343          if (chan->_state != AST_STATE_UP)
07344          {
07345             ast_indicate(chan,AST_CONTROL_BUSY);
07346          }
07347          while(ast_safe_sleep(chan,10000) != -1);
07348          return -1;
07349       }
07350 
07351       if (chan->_state != AST_STATE_UP)
07352       {
07353          ast_answer(chan);
07354       }
07355 
07356       l=strlen(options)+2;
07357       orig_s=malloc(l);
07358       if(!orig_s) {
07359          ast_log(LOG_WARNING, "Out of memory\n");
07360          return -1;
07361       }
07362       s=orig_s;
07363       ast_copy_string(s,options,l);
07364 
07365       template=strsep(&s,"|");
07366       if(!template) {
07367          ast_log(LOG_WARNING, "An announce template must be defined\n");
07368          free(orig_s);
07369          return -1;
07370       } 
07371   
07372       if(s) {
07373          timeout = atoi(strsep(&s, "|"));
07374          timeout *= 1000;
07375       }
07376    
07377       return_context = s;
07378   
07379       if(return_context != NULL) {
07380          /* set the return context. Code borrowed from the Goto builtin */
07381     
07382          working = return_context;
07383          context = strsep(&working, "|");
07384          exten = strsep(&working, "|");
07385          if(!exten) {
07386             /* Only a priority in this one */
07387             priority = context;
07388             exten = NULL;
07389             context = NULL;
07390          } else {
07391             priority = strsep(&working, "|");
07392             if(!priority) {
07393                /* Only an extension and priority in this one */
07394                priority = exten;
07395                exten = context;
07396                context = NULL;
07397          }
07398       }
07399       if(atoi(priority) < 0) {
07400          ast_log(LOG_WARNING, "Priority '%s' must be a number > 0\n", priority);
07401          free(orig_s);
07402          return -1;
07403       }
07404       /* At this point we have a priority and maybe an extension and a context */
07405       chan->priority = atoi(priority);
07406 #ifdef OLD_ASTERISK
07407       if(exten && strcasecmp(exten, "BYEXTENSION"))
07408 #else
07409       if(exten)
07410 #endif
07411          ast_copy_string(chan->exten, exten, sizeof(chan->exten));
07412       if(context)
07413          ast_copy_string(chan->context, context, sizeof(chan->context));
07414       } else {  /* increment the priority by default*/
07415          chan->priority++;
07416       }
07417 
07418       if(option_verbose > 2) {
07419          ast_verbose( VERBOSE_PREFIX_3 "Return Context: (%s,%s,%d) ID: %s\n", chan->context,chan->exten, chan->priority, chan->cid.cid_num);
07420          if(!ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) {
07421             ast_verbose( VERBOSE_PREFIX_3 "Warning: Return Context Invalid, call will return to default|s\n");
07422          }
07423       }
07424   
07425       /* we are using masq_park here to protect * from touching the channel once we park it.  If the channel comes out of timeout
07426       before we are done announcing and the channel is messed with, Kablooeee.  So we use Masq to prevent this.  */
07427 
07428       ast_masq_park_call(chan, NULL, timeout, &lot);
07429 
07430       if (option_verbose > 2) ast_verbose( VERBOSE_PREFIX_3 "Call Parking Called, lot: %d, timeout: %d, context: %s\n", lot, timeout, return_context);
07431 
07432       snprintf(tmp,sizeof(tmp) - 1,"%d,%s",lot,template + 1);
07433 
07434       rpt_telemetry(myrpt,REV_PATCH,tmp);
07435 
07436       free(orig_s);
07437 
07438       return 0;
07439 
07440    }
07441 
07442    if (!options)
07443    {
07444                 struct ast_hostent ahp;
07445                 struct hostent *hp;
07446       struct in_addr ia;
07447       char hisip[100],nodeip[100];
07448       const char *val;
07449       char *s, *s1, *s2, *b,*b1;
07450 
07451       /* look at callerid to see what node this comes from */
07452       if (!chan->cid.cid_num) /* if doesn't have caller id */
07453       {
07454          ast_log(LOG_WARNING, "Doesnt have callerid on %s\n",tmp);
07455          return -1;
07456       }
07457 
07458       /* get his IP from IAX2 module */
07459       memset(hisip,0,sizeof(hisip));
07460       pbx_substitute_variables_helper(chan,"${IAXPEER(CURRENTCHANNEL)}",hisip,sizeof(hisip) - 1);
07461       if (!hisip[0])
07462       {
07463          ast_log(LOG_WARNING, "Link IP address cannot be determined!!\n");
07464          return -1;
07465       }
07466       
07467       ast_callerid_parse(chan->cid.cid_num,&b,&b1);
07468       ast_shrink_phone_number(b1);
07469       if (!strcmp(myrpt->name,b1))
07470       {
07471          ast_log(LOG_WARNING, "Trying to link to self!!\n");
07472          return -1;
07473       }
07474 
07475       if (*b1 < '1')
07476       {
07477          ast_log(LOG_WARNING, "Node %s Invalid for connection here!!\n",b1);
07478          return -1;
07479       }
07480 
07481 
07482       /* look for his reported node string */
07483       val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, b1);
07484       if (!val)
07485       {
07486          ast_log(LOG_WARNING, "Reported node %s cannot be found!!\n",b1);
07487          return -1;
07488       }
07489       ast_copy_string(tmp,val,sizeof(tmp));
07490       s = tmp;
07491       s1 = strsep(&s,",");
07492       s2 = strsep(&s,",");
07493       if (!s2)
07494       {
07495          ast_log(LOG_WARNING, "Reported node %s not in correct format!!\n",b1);
07496          return -1;
07497       }
07498                 if (strcmp(s2,"NONE")) {
07499          hp = ast_gethostbyname(s2, &ahp);
07500          if (!hp)
07501          {
07502             ast_log(LOG_WARNING, "Reported node %s, name %s cannot be found!!\n",b1,s2);
07503             return -1;
07504          }
07505          memcpy(&ia,hp->h_addr,sizeof(in_addr_t));
07506          ast_copy_string(nodeip, ast_inet_ntoa(ia), sizeof(nodeip));
07507          if (strcmp(hisip,nodeip))
07508          {
07509             char *s3 = strchr(s1,'@');
07510             if (s3) s1 = s3 + 1;
07511             s3 = strchr(s1,'/');
07512             if (s3) *s3 = 0;
07513             hp = ast_gethostbyname(s1, &ahp);
07514             if (!hp)
07515             {
07516                ast_log(LOG_WARNING, "Reported node %s, name %s cannot be found!!\n",b1,s1);
07517                return -1;
07518             }
07519             memcpy(&ia,hp->h_addr,sizeof(in_addr_t));
07520             ast_copy_string(nodeip, ast_inet_ntoa(ia), sizeof(nodeip));
07521             if (strcmp(hisip,nodeip))
07522             {
07523                ast_log(LOG_WARNING, "Node %s IP %s does not match link IP %s!!\n",b1,nodeip,hisip);
07524                return -1;
07525             }
07526          }
07527       }
07528    }
07529 
07530    /* if is not a remote */
07531    if (!myrpt->remote)
07532    {
07533 
07534       char *b,*b1;
07535       int reconnects = 0;
07536 
07537       /* look at callerid to see what node this comes from */
07538       if (!chan->cid.cid_num) /* if doesn't have caller id */
07539       {
07540          ast_log(LOG_WARNING, "Doesnt have callerid on %s\n",tmp);
07541          return -1;
07542       }
07543 
07544       ast_callerid_parse(chan->cid.cid_num,&b,&b1);
07545       ast_shrink_phone_number(b1);
07546       if (!strcmp(myrpt->name,b1))
07547       {
07548          ast_log(LOG_WARNING, "Trying to link to self!!\n");
07549          return -1;
07550       }
07551       rpt_mutex_lock(&myrpt->lock);
07552       l = myrpt->links.next;
07553       /* try to find this one in queue */
07554       while(l != &myrpt->links)
07555       {
07556          if (l->name[0] == '0') 
07557          {
07558             l = l->next;
07559             continue;
07560          }
07561          /* if found matching string */
07562          if (!strcmp(l->name,b1)) break;
07563          l = l->next;
07564       }
07565       /* if found */
07566       if (l != &myrpt->links) 
07567       {
07568          l->killme = 1;
07569          l->retries = MAX_RETRIES + 1;
07570          l->disced = 2;
07571          reconnects = l->reconnects;
07572          reconnects++;
07573                         rpt_mutex_unlock(&myrpt->lock);
07574          usleep(500000);   
07575       } else 
07576          rpt_mutex_unlock(&myrpt->lock);
07577       /* establish call in tranceive mode */
07578       l = malloc(sizeof(struct rpt_link));
07579       if (!l)
07580       {
07581          ast_log(LOG_WARNING, "Unable to malloc\n");
07582          pthread_exit(NULL);
07583       }
07584       /* zero the silly thing */
07585       memset((char *)l,0,sizeof(struct rpt_link));
07586       l->mode = 1;
07587       ast_copy_string(l->name,b1,MAXNODESTR);
07588       l->isremote = 0;
07589       l->chan = chan;
07590       l->connected = 1;
07591       l->hasconnected = 1;
07592       l->reconnects = reconnects;
07593       l->phonemode = phone_mode;
07594       ast_set_read_format(l->chan,AST_FORMAT_SLINEAR);
07595       ast_set_write_format(l->chan,AST_FORMAT_SLINEAR);
07596       /* allocate a pseudo-channel thru asterisk */
07597       l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
07598       if (!l->pchan)
07599       {
07600          fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
07601          pthread_exit(NULL);
07602       }
07603       ast_set_read_format(l->pchan,AST_FORMAT_SLINEAR);
07604       ast_set_write_format(l->pchan,AST_FORMAT_SLINEAR);
07605       /* make a conference for the tx */
07606       ci.chan = 0;
07607       ci.confno = myrpt->conf;
07608       ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER;
07609       /* first put the channel on the conference in proper mode */
07610       if (ioctl(l->pchan->fds[0],ZT_SETCONF,&ci) == -1)
07611       {
07612          ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
07613          pthread_exit(NULL);
07614       }
07615       rpt_mutex_lock(&myrpt->lock);
07616       if (phone_mode > 1) l->lastrx = 1;
07617       /* insert at end of queue */
07618       insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
07619       rpt_mutex_unlock(&myrpt->lock);
07620       if (chan->_state != AST_STATE_UP) {
07621          ast_answer(chan);
07622       }
07623       return AST_PBX_KEEPALIVE;
07624    }
07625    rpt_mutex_lock(&myrpt->lock);
07626    /* if remote, error if anyone else already linked */
07627    if (myrpt->remoteon)
07628    {
07629       rpt_mutex_unlock(&myrpt->lock);
07630       usleep(500000);
07631       if (myrpt->remoteon)
07632       {
07633          ast_log(LOG_WARNING, "Trying to use busy link on %s\n",tmp);
07634          return -1;
07635       }     
07636       rpt_mutex_lock(&myrpt->lock);
07637    }
07638    myrpt->remoteon = 1;
07639    if (ioperm(myrpt->p.iobase,1,1) == -1)
07640    {
07641       rpt_mutex_unlock(&myrpt->lock);
07642       ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->p.iobase);
07643       return -1;
07644    }
07645    u = ast_module_user_add(chan);
07646    rpt_mutex_unlock(&myrpt->lock);
07647    /* find our index, and load the vars initially */
07648    for(i = 0; i < nrpts; i++)
07649    {
07650       if (&rpt_vars[i] == myrpt)
07651       {
07652          load_rpt_vars(i,0);
07653          break;
07654       }
07655    }
07656    rpt_mutex_lock(&myrpt->lock);
07657    tele = strchr(myrpt->rxchanname,'/');
07658    if (!tele)
07659    {
07660       fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
07661       rpt_mutex_unlock(&myrpt->lock);
07662       pthread_exit(NULL);
07663    }
07664    *tele++ = 0;
07665    myrpt->rxchannel = ast_request(myrpt->rxchanname,AST_FORMAT_SLINEAR,tele,NULL);
07666    if (myrpt->rxchannel)
07667    {
07668       ast_set_read_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
07669       ast_set_write_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
07670       myrpt->rxchannel->whentohangup = 0;
07671       myrpt->rxchannel->appl = "Apprpt";
07672       myrpt->rxchannel->data = "(Link Rx)";
07673       if (option_verbose > 2)
07674          ast_verbose(VERBOSE_PREFIX_3 "rpt (Rx) initiating call to %s/%s on %s\n",
07675             myrpt->rxchanname,tele,myrpt->rxchannel->name);
07676       rpt_mutex_unlock(&myrpt->lock);
07677       ast_call(myrpt->rxchannel,tele,999);
07678       rpt_mutex_lock(&myrpt->lock);
07679    }
07680    else
07681    {
07682       fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
07683       rpt_mutex_unlock(&myrpt->lock);
07684       pthread_exit(NULL);
07685    }
07686    *--tele = '/';
07687    if (myrpt->txchanname)
07688    {
07689       tele = strchr(myrpt->txchanname,'/');
07690       if (!tele)
07691       {
07692          fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
07693          rpt_mutex_unlock(&myrpt->lock);
07694          ast_hangup(myrpt->rxchannel);
07695          pthread_exit(NULL);
07696       }
07697       *tele++ = 0;
07698       myrpt->txchannel = ast_request(myrpt->txchanname,AST_FORMAT_SLINEAR,tele,NULL);
07699       if (myrpt->txchannel)
07700       {
07701          ast_set_read_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
07702          ast_set_write_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
07703          myrpt->txchannel->whentohangup = 0;
07704          myrpt->txchannel->appl = "Apprpt";
07705          myrpt->txchannel->data = "(Link Tx)";
07706          if (option_verbose > 2)
07707             ast_verbose(VERBOSE_PREFIX_3 "rpt (Tx) initiating call to %s/%s on %s\n",
07708                myrpt->txchanname,tele,myrpt->txchannel->name);
07709          rpt_mutex_unlock(&myrpt->lock);
07710          ast_call(myrpt->txchannel,tele,999);
07711          rpt_mutex_lock(&myrpt->lock);
07712       }
07713       else
07714       {
07715          fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
07716          rpt_mutex_unlock(&myrpt->lock);
07717          ast_hangup(myrpt->rxchannel);
07718          pthread_exit(NULL);
07719       }
07720       *--tele = '/';
07721    }
07722    else
07723    {
07724       myrpt->txchannel = myrpt->rxchannel;
07725    }
07726    myrpt->remoterx = 0;
07727    myrpt->remotetx = 0;
07728    myrpt->retxtimer = 0;
07729    myrpt->remoteon = 1;
07730    myrpt->dtmfidx = -1;
07731    myrpt->dtmfbuf[0] = 0;
07732    myrpt->dtmf_time_rem = 0;
07733    myrpt->hfscanmode = 0;
07734    myrpt->hfscanstatus = 0;
07735    if (myrpt->p.startupmacro)
07736    {
07737       myrpt->remchannel = chan; /* Save copy of channel */
07738       snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro);
07739    }
07740    myrpt->reload = 0;
07741    rpt_mutex_unlock(&myrpt->lock);
07742    setrem(myrpt); 
07743    ast_set_write_format(chan, AST_FORMAT_SLINEAR);
07744    ast_set_read_format(chan, AST_FORMAT_SLINEAR);
07745    /* if we are on 2w loop and are a remote, turn EC on */
07746    if (myrpt->remote && (myrpt->rxchannel == myrpt->txchannel))
07747    {
07748       i = 128;
07749       ioctl(myrpt->rxchannel->fds[0],ZT_ECHOCANCEL,&i);
07750    }
07751    if (chan->_state != AST_STATE_UP) {
07752       ast_answer(chan);
07753    }
07754 
07755    if (ioctl(myrpt->txchannel->fds[0],ZT_GET_PARAMS,&par) != -1)
07756    {
07757       if (par.rxisoffhook)
07758       {
07759          ast_indicate(chan,AST_CONTROL_RADIO_KEY);
07760          myrpt->remoterx = 1;
07761       }
07762    }
07763    n = 0;
07764    cs[n++] = chan;
07765    cs[n++] = myrpt->rxchannel;
07766    if (myrpt->rxchannel != myrpt->txchannel)
07767       cs[n++] = myrpt->txchannel;
07768    for(;;) 
07769    {
07770       if (ast_check_hangup(chan)) break;
07771       if (ast_check_hangup(myrpt->rxchannel)) break;
07772       if (myrpt->reload)
07773       {
07774          myrpt->reload = 0;
07775          rpt_mutex_unlock(&myrpt->lock);
07776          /* find our index, and load the vars */
07777          for(i = 0; i < nrpts; i++)
07778          {
07779             if (&rpt_vars[i] == myrpt)
07780             {
07781                load_rpt_vars(i,0);
07782                break;
07783             }
07784          }
07785          rpt_mutex_lock(&myrpt->lock);
07786       }
07787       ms = MSWAIT;
07788       who = ast_waitfor_n(cs,n,&ms);
07789       if (who == NULL) ms = 0;
07790       elap = MSWAIT - ms;
07791       if (myrpt->macrotimer) myrpt->macrotimer -= elap;
07792       if (myrpt->macrotimer < 0) myrpt->macrotimer = 0;
07793       rpt_mutex_unlock(&myrpt->lock);
07794       if (!ms) continue;
07795       rem_totx = keyed;
07796       
07797       
07798       if ((!myrpt->remoterx) && (!myrpt->remotetx))
07799       {
07800          if ((myrpt->retxtimer += elap) >= REDUNDANT_TX_TIME)
07801          {
07802             myrpt->retxtimer = 0;
07803             ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
07804          }
07805       } else myrpt->retxtimer = 0;
07806       if (rem_totx && (!myrpt->remotetx)) /* Remote base radio TX key */
07807       {
07808          myrpt->remotetx = 1;
07809          ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
07810       }
07811       if ((!rem_totx) && myrpt->remotetx) /* Remote base radio TX unkey */
07812       {
07813          myrpt->remotetx = 0;
07814          ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
07815       }
07816 
07817       if(myrpt->tunerequest && (!strcmp(myrpt->remote, remote_rig_ft897))){ /* ft-897 specific for now... */
07818          myrpt->tunerequest = 0;
07819          set_mode_ft897(myrpt, REM_MODE_AM);
07820          simple_command_ft897(myrpt, 8);
07821          myrpt->remotetx = 0;
07822          ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
07823          if (!myrpt->remoterx)
07824             ast_indicate(chan, AST_CONTROL_RADIO_KEY);
07825          if(play_tone(chan, 800, 6000, 8192) == -1)
07826             break;
07827 
07828          rmt_telem_finish(myrpt,chan);
07829          set_mode_ft897(myrpt, 0x88);
07830          setrem(myrpt);
07831       }
07832    
07833       if (myrpt->hfscanmode){
07834          myrpt->scantimer -= elap;
07835          if(myrpt->scantimer <= 0){
07836             myrpt->scantimer = REM_SCANTIME;
07837             service_scan(myrpt);
07838          }
07839       }
07840       if (who == chan) /* if it was a read from incomming */
07841       {
07842          f = ast_read(chan);
07843          if (!f)
07844          {
07845             if (debug) printf("@@@@ link:Hung Up\n");
07846             break;
07847          }
07848          if (f->frametype == AST_FRAME_VOICE)
07849          {
07850             /* if not transmitting, zero-out audio */
07851             if (!myrpt->remotetx)
07852                memset(f->data,0,f->datalen);
07853             ast_write(myrpt->txchannel,f);
07854          }
07855          if (f->frametype == AST_FRAME_DTMF)
07856          {
07857             myrpt->remchannel = chan; /* Save copy of channel */
07858             if (handle_remote_phone_dtmf(myrpt,f->subclass,&keyed,phone_mode) == -1)
07859             {
07860                if (debug) printf("@@@@ rpt:Hung Up\n");
07861                ast_frfree(f);
07862                break;
07863             }
07864          }
07865          if (f->frametype == AST_FRAME_TEXT)
07866          {
07867             myrpt->remchannel = chan; /* Save copy of channel */
07868             if (handle_remote_data(myrpt,f->data) == -1)
07869             {
07870                if (debug) printf("@@@@ rpt:Hung Up\n");
07871                ast_frfree(f);
07872                break;
07873             }
07874          }
07875          if (f->frametype == AST_FRAME_CONTROL)
07876          {
07877             if (f->subclass == AST_CONTROL_HANGUP)
07878             {
07879                if (debug) printf("@@@@ rpt:Hung Up\n");
07880                ast_frfree(f);
07881                break;
07882             }
07883             /* if RX key */
07884             if (f->subclass == AST_CONTROL_RADIO_KEY)
07885             {
07886                if (debug == 7) printf("@@@@ rx key\n");
07887                keyed = 1;
07888             }
07889             /* if RX un-key */
07890             if (f->subclass == AST_CONTROL_RADIO_UNKEY)
07891             {
07892                if (debug == 7) printf("@@@@ rx un-key\n");
07893                keyed = 0;
07894             }
07895          }
07896          if (myrpt->hfscanstatus){
07897             myrpt->remchannel = chan; /* Save copy of channel */
07898             myrpt->remotetx = 0;
07899             ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
07900             if (!myrpt->remoterx)
07901             {
07902                ast_indicate(myrpt->remchannel,AST_CONTROL_RADIO_KEY);
07903             }
07904             if(myrpt->hfscanstatus < 0) {
07905                if (myrpt->hfscanstatus == -1) {
07906                   if (ast_safe_sleep(myrpt->remchannel,1000) == -1) break;
07907                }
07908                sayfile(myrpt->remchannel, "rpt/stop");
07909             }
07910             else
07911             {
07912                saynum(myrpt->remchannel, myrpt->hfscanstatus );
07913             }  
07914             rmt_telem_finish(myrpt,myrpt->remchannel);
07915             myrpt->hfscanstatus = 0;
07916          }
07917          ast_frfree(f);
07918          rpt_mutex_lock(&myrpt->lock);
07919          c = myrpt->macrobuf[0];
07920          if (c && (!myrpt->macrotimer))
07921          {
07922             myrpt->macrotimer = MACROTIME;
07923             memmove(myrpt->macrobuf,myrpt->macrobuf + 1,MAXMACRO - 1);
07924             if ((c == 'p') || (c == 'P'))
07925                myrpt->macrotimer = MACROPTIME;
07926             rpt_mutex_unlock(&myrpt->lock);
07927             if (handle_remote_dtmf_digit(myrpt,c,&keyed,0) == -1) break;
07928             continue;
07929          } 
07930          rpt_mutex_unlock(&myrpt->lock);
07931          continue;
07932       }
07933       if (who == myrpt->rxchannel) /* if it was a read from radio */
07934       {
07935          f = ast_read(myrpt->rxchannel);
07936          if (!f)
07937          {
07938             if (debug) printf("@@@@ link:Hung Up\n");
07939             break;
07940          }
07941          if (f->frametype == AST_FRAME_VOICE)
07942          {
07943             if ((myrpt->remote) && (myrpt->remotetx))
07944                memset(f->data,0,f->datalen);
07945              ast_write(chan,f);
07946          }
07947          else if (f->frametype == AST_FRAME_CONTROL)
07948          {
07949             if (f->subclass == AST_CONTROL_HANGUP)
07950             {
07951                if (debug) printf("@@@@ rpt:Hung Up\n");
07952                ast_frfree(f);
07953                break;
07954             }
07955             /* if RX key */
07956             if (f->subclass == AST_CONTROL_RADIO_KEY)
07957             {
07958                if (debug == 7) printf("@@@@ remote rx key\n");
07959                if (!myrpt->remotetx)
07960                {
07961                   ast_indicate(chan,AST_CONTROL_RADIO_KEY);
07962                   myrpt->remoterx = 1;
07963                }
07964             }
07965             /* if RX un-key */
07966             if (f->subclass == AST_CONTROL_RADIO_UNKEY)
07967             {
07968                if (debug == 7) printf("@@@@ remote rx un-key\n");
07969                if (!myrpt->remotetx) 
07970                {
07971                   ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
07972                   myrpt->remoterx = 0;
07973                }
07974             }
07975          }
07976          ast_frfree(f);
07977          continue;
07978       }
07979       if ((myrpt->rxchannel != myrpt->txchannel) && 
07980          (who == myrpt->txchannel)) /* do this cuz you have to */
07981       {
07982          f = ast_read(myrpt->txchannel);
07983          if (!f)
07984          {
07985             if (debug) printf("@@@@ link:Hung Up\n");
07986             break;
07987          }
07988          if (f->frametype == AST_FRAME_CONTROL)
07989          {
07990             if (f->subclass == AST_CONTROL_HANGUP)
07991             {
07992                if (debug) printf("@@@@ rpt:Hung Up\n");
07993                ast_frfree(f);
07994                break;
07995             }
07996          }
07997          ast_frfree(f);
07998          continue;
07999       }
08000 
08001    }
08002    rpt_mutex_lock(&myrpt->lock);
08003    if (myrpt->rxchannel != myrpt->txchannel) ast_hangup(myrpt->txchannel);
08004    ast_hangup(myrpt->rxchannel);
08005    myrpt->hfscanmode = 0;
08006    myrpt->hfscanstatus = 0;
08007    myrpt->remoteon = 0;
08008    rpt_mutex_unlock(&myrpt->lock);
08009    closerem(myrpt);
08010    ast_module_user_remove(u);
08011    return res;
08012 }
08013 
08014 static int unload_module(void)
08015 {
08016    int i;
08017 
08018    ast_module_user_hangup_all();
08019    for(i = 0; i < nrpts; i++) {
08020       if (!strcmp(rpt_vars[i].name,rpt_vars[i].p.nodes)) continue;
08021                 ast_mutex_destroy(&rpt_vars[i].lock);
08022    }
08023    i = ast_unregister_application(app);
08024 
08025    /* Unregister cli extensions */
08026    ast_cli_unregister_multiple(cli_rpt, sizeof(cli_rpt) / sizeof(struct ast_cli_entry));
08027 
08028    return i;
08029 }
08030 
08031 static int load_module(void)
08032 {
08033    struct ast_config *cfg = ast_config_load("rpt.conf");
08034    if (!cfg) {
08035       ast_log(LOG_WARNING, "No such configuration file rpt.conf\n");
08036       return AST_MODULE_LOAD_DECLINE;
08037    }
08038    ast_pthread_create(&rpt_master_thread,NULL,rpt_master,cfg);
08039 
08040    /* Register cli extensions */
08041    ast_cli_register_multiple(cli_rpt, sizeof(cli_rpt) / sizeof(struct ast_cli_entry));
08042 
08043    return ast_register_application(app, rpt_exec, synopsis, descrip);
08044 }
08045 
08046 static int reload(void)
08047 {
08048    int n;
08049 
08050    for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
08051    return(0);
08052 }
08053 
08054 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Radio Repeater / Remote Base",
08055       .load = load_module,
08056       .unload = unload_module,
08057       .reload = reload,
08058           );

Generated on Mon May 14 04:42:51 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1