Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:47:48 2009

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