1 /* Copyright (C) 2002 GFRN systems
2 
3    This program is free software; you can redistribute it and/or
4    modify it under the terms of the GNU General Public License as
5    published by the Free Software Foundation; either version 2 of the
6    License, or (at your option) any later version.
7 
8    This program is distributed in the hope that it will be useful, but
9    WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11    See the GNU General Public License for more details.
12 
13    You should have received a copy of the GNU General Public License
14    along with this program; if not, write to the Free Software
15    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
16    02111-1307, USA.
17 
18    The latest version of this program may be found at
19    http://CQiNet.sourceforge.net
20 
21    $Log: configvars.c,v $
22    Revision 1.37  2012/12/09 19:32:13  wb6ymh
23    1. Removed old chan_rptdir style Asterisk support variables AsteriskIP,
24    AsteriskBind2IP, AsteriskDesc, AsteriskPort, and AsteriskEnable.
25    Asterisk is now supported by G.726 and Ulaw RTP connections.
26    2. Added ConfTextEnable and ConfCmdEnable.
27 
28    Revision 1.36  2012/12/09 18:52:40  wb6ymh
29    Corrected bug in LoadFile which caused odd crashes and general bad behavor
30    when the configuration variables HelpFile or InfoFile where used.
31 
32    Revision 1.35  2011/11/06 14:34:06  wb6ymh
33    Added RTP_Port.  NB: not tested in thebridge build, added to fix
34    compile error.  Tested on thelinkbox build, probably works here too.
35 
36    Revision 1.34  2009/09/14 21:45:32  wb6ymh
37    1. Added TempDir.
38    2. Added new argument to the StartCmdHandler call.
39 
40    Revision 1.33  2009/04/04 20:17:39  wb6ymh
41    Added LogIPAddresses.
42 
43    Revision 1.32  2008/07/23 14:47:12  wb6ymh
44    Added AsteriskEnable, CompressionType, and FullDuplex configuration variables.
45 
46    Revision 1.31  2008/07/16 22:40:23  wb6ymh
47    Added AsteriskBind2IP, AsteriskIP, AsteriskDesc, EnableRemoteDTMF,
48    FullDuplex, and AsteriskPort.
49 
50    Revision 1.30  2008/04/11 14:08:24  wb6ymh
51    Added missing argument to error logging in CheckEmailAdr.  Fixes segfault
52    when email address lacks '@' or '.' characters.
53 
54    Revision 1.29  2008/02/26 17:35:47  wb6ymh
55    1. Added dmalloc support.
56    2. Added AllowADPCM, EchoLinkEnable, and Debug config variables.
57 
58    Revision 1.28  2008/02/09 16:53:26  wb6ymh
59    Added ShowStatusInInfo.
60 
61    Revision 1.27  2008/01/03 16:07:15  wb6ymh
62    1. Added SFBind2IP.
63    2. Restored default AppName to "tbd".
64 
65    Revision 1.26  2007/12/27 18:36:05  wb6ymh
66    Added FullName.
67 
68    Revision 1.25  2007/12/22 18:58:13  wb6ymh
69    Changed calling convention of all SetFuncs (now called AccessFunc).
70 
71    Revision 1.24  2007/12/07 22:41:08  wb6ymh
72    1. Removed thelinkbox variables, they are now elsewhere.
73    2. Added ConfigGetVarPtr() stub.
74 
75    Revision 1.23  2007/11/26 15:03:27  wb6ymh
76    Undeleted.  Converting to C++ was a bad idea because it would have required
77    a C++ compiler to build thebrige as well as thelinkbox.  This file is now
78    used for thebrige only.  Configuration variables for thelinkbox are defined
79    in ../linkbox/configvars.cpp.
80 
81    Revision 1.21  2007/11/21 17:29:43  wb6ymh
82    1. Added configuration variables AudioDongleSN, COS_KeyCode, and ShareIRLP_Port.
83    2. Added bMonitor so it's accessable to the set command.
84 
85    Revision 1.20  2007/06/29 18:16:15  wb6ymh
86    Added QthInHostsFile configuration variable to allow Qth information to
87    be optionally included in the host file.  NB: As of today the inclusion
88    of Qth information breaks the EchoIRLP scripts.
89 
90    Revision 1.19  2007/06/29 17:14:55  wb6ymh
91    Edit, COMPILE, then commit!
92 
93    Revision 1.18  2007/06/29 17:11:28  wb6ymh
94    Corrected CONFIG_FILE_PATH, thelinkbox and thebridge version were swapped.
95 
96    Revision 1.17  2007/06/13 00:05:08  wb6ymh
97    1. Added ChatPort.
98    2. Added thelinkbox configuration variables.
99    3. Changed LoadHelp file to LoadFile and made it more generic so it can
100       be used to load command files as well as help files.
101 
102    Revision 1.16  2004/11/27 22:12:45  wb6ymh
103    Added new configuration variables UserName, ConfEnable, AvrsEnable,
104    AvrsInterval, bEchoIrlpMode, Latitude, Longitude, TxPower, Hatt, AntGain,
105    Frequency and CTCSS.  Added AVRS_Validate() to check entered values.
106 
107    Revision 1.15  2004/11/22 00:42:20  wb6ymh
108    1. "%f" -> "%F" so we can support floating point numbers in the
109       configuration file.
110    2. Added configuration variable IncludeAllHosts.
111    3. Warn about needing a "-L", "-R", or conference callsign for all
112       configurations, not just EchoIRLP.
113 
114    Revision 1.14  2004/05/29 17:22:47  wb6ymh
115    Add warning about "conference" callsign needing to be a "-R" or "-L" when
116    thebridge is configured for use with EchoIRLP.
117 
118    Revision 1.13  2003/09/06 19:05:16  wb6ymh
119    Added MaxDups.
120    Changed default value for StationListInterval to 600 (10 minutes).
121 
122    Revision 1.12  2003/09/01 15:15:01  wb6ymh
123    1. Added configuration variables EmailAdr, CmdPort, IdleTimeout, SF_ReplyPort,
124       DirCompression, EventScript, StartupCmd, HelpFile and WelcomeDelay.
125    2. Modified for multipass initialization, primarily to support StartupCmd.
126 
127    Revision 1.11  2003/04/30 21:35:58  wb6ymh
128    1. Added configuration varibles Bind2IP, AppName, RunDir, AutoLurkTimeout,
129       DefaultAutoLurk, BlabOffTimer, and LogLevel.
130    2. Added SetQth() to verify that the default Qth has been edited (sigh).
131 
132    Revision 1.10  2002/12/21 18:17:24  wb6ymh
133    Added configuration variables MaxPlayWithoutPause, SaveInfoFiles,
134    ShowStationInfo and WriteHostFile.
135 
136    Revision 1.9  2002/12/18 00:56:59  wb6ymh
137    Added WelcomeFile, MaxPlayBackPause, MinPlayBackPause, LogFileRolloverType,
138    and AudioTestConf.
139 
140    Revision 1.8  2002/11/02 18:15:23  wb6ymh
141    1. Added config variables RTP_Pass, PrivateConference, EnableDiskCommands,
142       iLinkDirServer, DnsUpdateInterval, BelchTime, InactiveDirTimeout and
143       bQuickStart.
144    2. Added routine to set ConferenceCall so we can check for an unedited
145       config file earlier in the game. (Otherwise a bad working directory
146       is reported before the default conference call is detected confusing
147       lusers).
148 
149    Revision 1.7  2002/10/25 14:27:30  wb6ymh
150    Added iLinkDirServer config variable.
151 
152    Revision 1.6  2002/09/29 16:32:55  wb6ymh
153    Added configuration variables SysopPass and PauseTime.
154 
155    Revision 1.5  2002/09/14 16:49:21  wb6ymh
156    Added WorkingDir, RunAsUser, Banner, UserCountEnable, MaxCountEnable, and
157    UserCountInLocation variables. Deleted BannerEable and ConnectTo variables.
158 
159    Revision 1.4  2002/09/01 04:55:40  wb6ymh
160    Fixed yet another more pointer to pointer bug.... sigh.
161 
162    Revision 1.3  2002/09/01 03:05:16  wb6ymh
163    Pointers to pointers make my head hurt!  Fixed bug in SetConfigDefaults().
164    GCC V 2.95.3 under FreeBSD didn't issue a warning, but GCC V 2.95.3 on
165    Linux and Visual C++ did.  Weird!
166 
167    Revision 1.2  2002/08/31 23:42:36  wb6ymh
168    Added configuration variables DirServerHost1 ...3, AdminPass, BannerEnable,
169    SF_Port, SF_Enable, SF_SWL_Only, LinkConferences. Modified SetConfigDefaults()
170    to free all "%s" type variables.  Changed DirServerHost to be an array of
171    NUM_DIRECTORY_SERVERS strings.  Changed ConfAudioTimeout default to 800
172    milliseconds.
173 
174    Revision 1.1.1.1  2002/08/10 20:33:41  wb6ymh
175    initial import
176 
177 */
178 
179 #include "common.h"
180 #include <stdio.h>
181 #include <stdlib.h>
182 #include <string.h>
183 #include <errno.h>
184 #ifndef _WIN32
185    #include <unistd.h>
186    #include <sys/socket.h>
187    #include <netinet/in.h>
188    #include <arpa/inet.h>
189    #include <sys/types.h>
190    #ifdef TIME_WITH_SYS_TIME
191       #include <sys/time.h>
192       #include <time.h>
193    #else
194       #ifdef HAVE_SYS_TIME_H
195          #include <sys/time.h>
196       #else
197          #include <time.h>
198       #endif
199    #endif
200    #include <sys/stat.h>
201    #define CONFIG_FILE_PATH   SYSCON_DIR "/tbd.conf"
202 
203    #include <netdb.h>
204 #else
205    #include <direct.h>
206    #include <time.h>
207    #include <sys\timeb.h>
208    #include <winsock2.h>
209    #include <sys\stat.h>
210    #define CONFIG_FILE_PATH   "tbd.conf"
211 #endif
212 
213 #include "configfile.h"
214 #include "configvars.h"
215 #include "main.h"
216 #include "conference.h"
217 #include "sf.h"
218 #include "hostfile.h"
219 #include "rtp.h"
220 
221 #ifdef USE_DMALLOC
222 #include "dmalloc.h"
223 #endif
224 
225 // Configuration variables
226 
227 // String variables: Dynamically allocated
228 char *ConferenceCall;
229 char *ConferencePass;
230 char *ConferenceQth;
231 char *EmailAdr;
232 char *ConferenceID;
233 char *DirServerHost[NUM_DIRECTORY_SERVERS];
234 char *AdminPass;
235 char *SysopPass;
236 char *Banner;
237 char *WorkingDir;
238 char *RunAsUser;
239 char *RTP_Pass;
240 char *WelcomeFile;
241 char *Bind2IP;
242 char *SFBind2IP;
243 char *AppName;
244 char *RunDir;
245 char *EventScript;
246 char *CustomHelp;
247 char *AntType;
248 char *UserName;
249 char *FullName;
250 char *TempDir;
251 char *RTP_Port;
252 
253 // Integer variables
254 int ConfAudioTimeout    = 800;   // in milliseconds (> 8 frames)
255 int ConfMemberTimeout   = 40;    // in seconds (>= 4 missed frames)
256 int LoginInterval       = 360;   // in seconds
257 int StationListInterval = 600;   // in seconds
258 int SDES_Interval       = 10;    // in seconds
259 int MaxConferenceClients= 8;
260 int SF_Port             = SF_AUDIO_PORT;
261 int SF_Enable           = 0;
262 int bAllowADPCM         = 0;
263 int bEchoLinkEnabled    = 1;
264 int LinkConferences     = 1;
265 int SF_SWL_Only         = 0;
266 int SB_Enable           = 0;
267 int UserCountEnable     = 1;
268 int MaxCountEnable      = 1;
269 int UserCountInLocation = 1;
270 int PauseTime           = 0;
271 int iLinkDirServer      = 0;
272 int PrivateConference   = 0;
273 int EnableDiskCommands  = 1;
274 int DnsUpdateInterval   = 15 * 60;
275 int BelchTime           = 0;
276 int InactiveDirTimeout  = 60 * 60 * 24;   // one day
277 int EnableRemoteDTMF    = 0;
278 int CompressionType     = RTP_PT_GSM;
279 int FullDuplex          = 0;
280 int LogIPAddresses      = 0;
281 
282 extern int LogFileRolloverType;
283 
284 int MaxPlayBackPause    = 5;
285 int MinPlayBackPause    = 0;
286 int AudioTestConf       = 0;
287 int MaxPlayWithoutPause = (10 * 60);   // 10 minutes
288 int SaveInfoFiles       = 0;
289 int ShowStationInfo     = 0;
290 int WriteHostFile       = 0;
291 int AutoLurkTimeout     = (15 * 60);   // 15 minutes
292 int DefaultAutoLurk     = 0;
293 int BlabOffTimer        = 0;
294 int LogLevel            = 0;
295 int CmdPort             = 0;
296 int ChatPort            = 0;
297 int IdleTimeout         = 3 * 60;
298 int SF_ReplyPort        = SF_AUDIO_PORT;
299 int DirCompression      = 1;
300 int WelcomeDelay        = 0;
301 int MaxDups             = 100;
302 int IncludeAllHosts     = 0;
303 int QthInHostsFile      = 0;
304 int AvrsEnable          = 0;
305 int AvrsInterval        = (10 * 60);   // 10 minutes
306 int bEchoIrlpMode       = 0;
307 int ConfEnable          = 1;
308 int ConfTextEnable      = 1;
309 int ConfCmdEnable       = 1;
310 int ShowStatusInInfo    = 0;     // Default to disabled
311 
312 float Latitude         = 200.0;
313 float Longitude        = 200.0;
314 float TxPower          = 0.0;
315 float Haat             = 0.0;
316 float AntGain          = 0.0;
317 float AntDir           = 0.0; // 0.0 = omni, heading of zero encoded as 360.0
318 float Frequency        = 0.0;
319 float CTCSS            = 0.0;
320 
321 int AddBannerLine(struct config_entry *p, char *Arg, AfCmd Cmd, int x);
322 int SetWorkingDir(struct config_entry *p, char *Arg, AfCmd Cmd, int x);
323 int SetConferenceCall(struct config_entry *p, char *Arg, AfCmd Cmd, int x);
324 int SetQth(struct config_entry *p, char *Arg, AfCmd Cmd, int x);
325 int CheckEmailAdr(struct config_entry *p, char *Arg, AfCmd Cmd, int x);
326 int StartupCommand(struct config_entry *p, char *Arg, AfCmd Cmd, int x);
327 int LoadFile(struct config_entry *p, char *Arg, AfCmd Cmd, int x);
328 int AVRS_Validate(void);
329 int AccessRtpPort(struct config_entry *p, char *Arg, AfCmd Cmd, int x);
330 
331 // Pass 1 variables: processed before initialization
332 // Pass 2 variables: processed immediately after initialization
333 // Pass 3 variables: processed after first station list has been downloaded
334 // Pass 4 variables: processed after second successful directory server login
335 //                   (approximately one minute after pass 3)
336 // Pass 5: Manual set command
337 #define NUM_CONFIG_PASSES  4
338 
339 struct config_entry ConfigVars[] = {
340 // Required parameters
341    { "ConferenceCall", "%F", &ConferenceCall, CON_FLG_REQUIRED, SetConferenceCall},
342    { "ConferencePass", "%s", &ConferencePass, CON_FLG_REQUIRED},
343    { "ConferenceQth", "%s", &ConferenceQth, CON_FLG_REQUIRED},
344    { "WorkingDir", "%F", &WorkingDir, CON_FLG_REQUIRED | CON_FLG_ONCE_ONLY, SetWorkingDir},
345    { "EmailAdr", "%F", &EmailAdr, CON_FLG_REQUIRED, CheckEmailAdr },
346 // Optional parameters
347    { "TempDir", "%s", &TempDir, 0},
348    { "ConferenceID", "%s", &ConferenceID, 0},
349    { "DirServerHost", "%s", &DirServerHost[0], 0},
350    { "DirServerHost1", "%s", &DirServerHost[1], 0},
351    { "DirServerHost2", "%s", &DirServerHost[2], 0},
352    { "DirServerHost3", "%s", &DirServerHost[3], 0},
353    { "RunAsUser", "%s", &RunAsUser, 0},
354    { "AdminPass", "%s", &AdminPass, 0},
355    { "SysopPass", "%s", &SysopPass, 0},
356    { "RTP_Pass", "%s", &RTP_Pass, 0},
357    { "WelcomeFile", "%s", &WelcomeFile, 0},
358    { "Bind2IP", "%s", &Bind2IP, 0},
359    { "SFBind2IP", "%s", &SFBind2IP, 0},
360    { "AppName", "%s", &AppName, 0},
361    { "RunDir", "%s", &RunDir, 0},
362    { "Banner", "%F", &Banner, 0, AddBannerLine},
363    { "ConfMemberTimeout", "%d", &ConfMemberTimeout, 0},
364    { "ConfAudioTimeout", "%d", &ConfAudioTimeout, 0},
365    { "LoginInterval", "%d", &LoginInterval, 0},
366    { "StationListInterval", "%d", &StationListInterval, 0},
367    { "SDES_Interval", "%d", &SDES_Interval, 0},
368    { "MaxConferenceClients", "%d", &MaxConferenceClients, 0},
369    { "SF_Port", "%d", &SF_Port, 0},
370    { "SF_Enable", "%d", &SF_Enable, 0},
371    { "SF_SWL_Only", "%d", &SF_SWL_Only, 0},
372    { "SB_Enable", "%d", &SB_Enable, 0},
373    { "UserCountEnable", "%d", &UserCountEnable, 0},
374    { "MaxCountEnable", "%d", &MaxCountEnable, 0},
375    { "UserCountInLocation", "%d", &UserCountInLocation, 0},
376    { "LinkConferences", "%d", &LinkConferences, 0},
377    { "PauseTime", "%d", &PauseTime, 0},
378    { "iLinkDirServer", "%d", &iLinkDirServer, 0},
379    { "PrivateConference", "%d", &PrivateConference, 0},
380    { "EnableDiskCommands", "%d", &EnableDiskCommands, 0},
381    { "DnsUpdateInterval", "%d", &DnsUpdateInterval, 0},
382    { "BelchTime", "%d", &BelchTime, 0},
383    { "InactiveDirTimeout", "%d", &InactiveDirTimeout, 0},
384    { "LogFileRolloverType", "%d", &LogFileRolloverType, 0},
385    { "MaxPlayBackPause", "%d", &MaxPlayBackPause, 0},
386    { "MinPlayBackPause", "%d", &MinPlayBackPause, 0},
387    { "AudioTestConf", "%d", &AudioTestConf, 0},
388    { "MaxPlayWithoutPause", "%d", &MaxPlayWithoutPause, 0},
389    { "SaveInfoFiles", "%d", &SaveInfoFiles, 0},
390    { "ShowStationInfo", "%d", &ShowStationInfo, 0},
391    { "WriteHostFile", "%d", &WriteHostFile, 0},
392    { "AutoLurkTimeout", "%d", &AutoLurkTimeout, 0},
393    { "DefaultAutoLurk", "%d", &DefaultAutoLurk, 0},
394    { "BlabOffTimer", "%d", &BlabOffTimer, 0},
395    { "LogLevel", "%d", &LogLevel, 0},
396    { "CmdPort", "%d", &CmdPort, 0},
397    { "ChatPort", "%d", &ChatPort, 0},
398    { "IdleTimeout", "%d", &IdleTimeout, 0},
399    { "SF_ReplyPort", "%d", &SF_ReplyPort, 0},
400    { "DirCompression", "%d", &DirCompression, 0},
401    { "EventScript", "%s", &EventScript, 0},
402    { "StartupCmd", "%F", NULL, CON_FLG_PASS4, StartupCommand},
403    { "HelpFile", "%F", &CustomHelp, 0, LoadFile},
404    { "WelcomeDelay", "%d", &WelcomeDelay, 0},
405    { "MaxDups", "%d", &MaxDups, 0},
406    { "ConfEnable", "%d", &ConfEnable, 0},
407    { "UserName", "%s", &UserName, 0},
408    { "IncludeAllHosts", "%d", &IncludeAllHosts, 0},
409    { "QthInHostsFile", "%d", &QthInHostsFile, 0},
410    { "Latitude", "%f", &Latitude, 0},
411    { "Longitude", "%f", &Longitude, 0},
412    { "TxPower", "%f", &TxPower, 0},
413    { "Haat", "%f", &Haat, 0},
414    { "AntGain", "%f", &AntGain, 0},
415    { "Frequency", "%f", &Frequency, 0},
416    { "CTCSS", "%f", &CTCSS, 0},
417    { "AntType", "%s", &AntType, 0},
418    { "AntDir", "%f", &AntDir, 0},
419    { "AvrsEnable", "%d", &AvrsEnable, 0},
420    { "AvrsInterval", "%d", &AvrsInterval, 0},
421    { "ShowStatusInInfo", "%d", &ShowStatusInInfo},
422    { "AllowADPCM", "%d", &bAllowADPCM, 0},
423    { "EchoLinkEnable", "%d", &bEchoLinkEnabled, 0},
424    { "Debug", "%d", &Debug, 0},
425    { "EnableRemoteDTMF", "%d", &EnableRemoteDTMF, 0},
426    { "CompressionType", "%d", &CompressionType, 0},
427    { "FullDuplex", "%d", &FullDuplex, 0},
428    { "LogIPAddresses", "%d", &LogIPAddresses, 0},
429    { "RTP_Port", "%F", NULL, 0, AccessRtpPort},
430    { "" }   /* end of table marker */
431 };
432 
SetConfigDefaults(int bSet)433 void SetConfigDefaults(int bSet)
434 {
435    int i;
436    void *var_ptr = NULL;
437 
438    for(i = 0; ConfigVars[i].var_name[0] != 0; i++) {
439       if(strcmp(ConfigVars[i].var_type,"%s") == 0) {
440          if(ConfigVars[i].Flags & CON_FLG_BASED_VAR) {
441             if(ConfigPass == 0) {
442             // Prior to first pass, class variables haven't been created yet
443                continue;
444             }
445          }
446          else {
447             var_ptr = ConfigVars[i].var_ptr;
448          }
449 
450          if(*((char **) var_ptr) != NULL)
451          {
452             free(*((char **) var_ptr));
453             *((char **) var_ptr) = NULL;
454          }
455       }
456       else if(strcmp(ConfigVars[i].var_type,"%F") == 0) {
457          ConfigVars[i].AccessFunc(&ConfigVars[i],NULL,AF_SET_DEFAULT,0);
458       }
459    }
460 
461    if(bSet) {
462       ConferenceID = strdup(PACKAGE " V " VERSION);
463       DirServerHost[0] = strdup("server1.echolink.org");
464       AppName = strdup("tbd");
465       RunDir = strdup("/var/run/");
466    }
467 }
468 
AddBannerLine(struct config_entry * p,char * Arg,AfCmd Cmd,int x)469 int AddBannerLine(struct config_entry *p, char *Arg, AfCmd Cmd, int x)
470 {
471    char *Temp;
472 
473    switch(Cmd) {
474       case AF_SET_VAR:
475          if(Banner != NULL) {
476          // Banner already has line(s)
477             Temp = Banner;
478             Banner = (char *) malloc(strlen(Temp)+strlen(Arg)+2);
479             if(Banner != NULL) {
480                strcpy(Banner,Temp);
481                strcat(Banner,"\r");
482                strcat(Banner,Arg);
483             }
484             free(Temp);
485          }
486          else {
487          // First banner line
488             Banner = strdup(Arg);
489          }
490          break;
491 
492       case AF_SET_DEFAULT:
493          if(Banner != NULL) {
494             free(Banner);
495             Banner = NULL;
496          }
497          break;
498 
499       case AF_DISPLAY_VAR:
500          break;
501    }
502 
503    return 0;
504 }
505 
SetConferenceCall(struct config_entry * p,char * Arg,AfCmd Cmd,int x)506 int SetConferenceCall(struct config_entry *p, char *Arg, AfCmd Cmd, int x)
507 {
508    int Ret = 0;
509 
510    switch(Cmd) {
511       case AF_SET_VAR:
512          if(ConferenceCall != NULL) {
513             free(ConferenceCall);
514          }
515 
516          ConferenceCall = strdup(Arg);
517 
518          if(strcmp(ConferenceCall,"W1AW") == 0) {
519             LOG_ERROR(("Come on now, your call isn't really W1AW is it!\n"));
520             LOG_ERROR(("Please read the documentation, edit tbd.conf and try again.\n"));
521             Ret = ERR_CONFIG_FILE;
522          }
523          p->Flags |= CON_FLG_SET;
524          break;
525 
526       case AF_SET_DEFAULT:
527          if(ConferenceCall != NULL) {
528             free(ConferenceCall);
529             ConferenceCall = NULL;
530          }
531          break;
532 
533       case AF_DISPLAY_VAR:
534          strncpy(Arg,ConferenceCall,x);
535          break;
536    }
537    return Ret;
538 }
539 
SetQth(struct config_entry * p,char * Arg,AfCmd Cmd,int x)540 int SetQth(struct config_entry *p, char *Arg, AfCmd Cmd, int x)
541 {
542    int Ret = 0;
543 
544    switch(Cmd) {
545       case AF_SET_VAR:
546          if(ConferenceQth!= NULL) {
547             free(ConferenceQth);
548          }
549 
550          ConferenceQth = strdup(Arg);
551 
552          if(strcmp(ConferenceQth,"Newington, Ct.") == 0) {
553             LOG_ERROR(("Come on now, you don't live in \"Newington, Ct.\" do you!\n"));
554             LOG_ERROR(("Please read the documentation, edit tbd.conf and try again.\n"));
555             Ret = ERR_CONFIG_FILE;
556          }
557          p->Flags |= CON_FLG_SET;
558          break;
559 
560       case AF_SET_DEFAULT:
561          if(ConferenceQth != NULL) {
562             free(ConferenceQth);
563             ConferenceQth = NULL;
564          }
565          break;
566 
567       case AF_DISPLAY_VAR:
568          strncpy(Arg,ConferenceQth,x);
569          break;
570    }
571 
572    return Ret;
573 }
574 
SetWorkingDir(struct config_entry * p,char * Arg,AfCmd Cmd,int x)575 int SetWorkingDir(struct config_entry *p, char *Arg, AfCmd Cmd, int x)
576 {
577    int Ret = 0;
578 
579    switch(Cmd) {
580       case AF_SET_VAR:
581          if(WorkingDir != NULL) {
582             free(WorkingDir);
583          }
584          WorkingDir = strdup(Arg);
585          if(WorkingDir != NULL) {
586             if(chdir(WorkingDir)) {
587                LOG_ERROR(("Unable to change to working directory \"%s\", %s",
588                           WorkingDir,Err2String(errno)));
589                free(WorkingDir);
590                WorkingDir = NULL;
591                Ret = ERR_WORKING_DIR;
592             }
593             p->Flags |= CON_FLG_SET;
594          }
595          break;
596 
597       case AF_SET_DEFAULT:
598          if(WorkingDir != NULL) {
599             free(WorkingDir);
600             WorkingDir = NULL;
601          }
602          break;
603 
604       case AF_DISPLAY_VAR:
605          strncpy(Arg,WorkingDir,x);
606          break;
607    }
608 
609    return Ret;
610 }
611 
CheckEmailAdr(struct config_entry * p,char * Arg,AfCmd Cmd,int x)612 int CheckEmailAdr(struct config_entry *p, char *Arg, AfCmd Cmd, int x)
613 {
614    int Ret = 0;
615 
616    switch(Cmd) {
617       case AF_SET_VAR:
618          if(EmailAdr != NULL) {
619             free(EmailAdr);
620          }
621 
622          EmailAdr = strdup(Arg);
623 
624          if(strcmp(EmailAdr,"w1aw@arrl.net") == 0) {
625             LOG_ERROR(("Come on now, your email address isn't \"w1aw@arrl.net\" "
626                        "is it?\n"));
627             Ret = ERR_CONFIG_FILE;
628          }
629          else if(!strchr(EmailAdr,'@') || !strchr(EmailAdr,'.')) {
630             LOG_ERROR(("Error: Invalid email address \"%s\".\n",EmailAdr));
631             Ret = ERR_CONFIG_FILE;
632          }
633 
634          if(Ret != 0) {
635             LOG_ERROR(("The email address is optional, please either delete the "
636                        "entry\n"));
637             LOG_ERROR(("or provide a valid email address.\n"));
638          }
639          p->Flags |= CON_FLG_SET;
640          break;
641 
642       case AF_SET_DEFAULT:
643          if(EmailAdr != NULL) {
644             free(EmailAdr);
645             EmailAdr = NULL;
646          }
647          break;
648 
649       case AF_DISPLAY_VAR:
650          break;
651    }
652    return Ret;
653 }
654 
StartupCommand(struct config_entry * p,char * Arg,AfCmd Cmd,int x)655 int StartupCommand(struct config_entry *p, char *Arg, AfCmd Cmd, int x)
656 {
657    switch(Cmd) {
658       case AF_SET_VAR:
659          StartCmdHandler(Arg,"StartupCmd");
660          break;
661 
662       case AF_SET_DEFAULT:
663          break;
664 
665       case AF_DISPLAY_VAR:
666          break;
667    }
668    return 0;
669 }
670 
LoadFile(struct config_entry * p,char * Arg,AfCmd Cmd,int x)671 int LoadFile(struct config_entry *p, char *Arg, AfCmd Cmd, int x)
672 {
673    struct stat FileStats;
674    FILE *fp;
675    char *cp;
676    char **pBuf;
677    int Ret = 0;
678 
679    pBuf = (char **) p->var_ptr;
680    if(p->var_ptr != NULL && *pBuf != NULL) {
681       free(*pBuf);
682       *pBuf = NULL;
683    }
684 
685    switch(Cmd) {
686       case AF_SET_VAR:
687          if(stat(Arg,&FileStats) != 0 || (fp = fopen(Arg,"r")) == NULL) {
688             LOG_ERROR(("Error: unable to open %s \"%s\" %s",p->var_name,Arg,
689                        Err2String(errno)));
690             Ret = ERR_CONFIG_FILE;
691          }
692          else if((*pBuf = (char *) malloc(FileStats.st_size)) != NULL) {
693             if(fread(*pBuf,FileStats.st_size,1,fp) != 1) {
694                LOG_ERROR(("Error reading help file \"%s\", %s",Arg,
695                           Err2String(errno)));
696                free(*pBuf);
697                *pBuf = NULL;
698                Ret = ERR_CONFIG_FILE;
699             }
700             else {
701             // Convert the '\n' end of line convention to '\r' used by EchoLink
702                cp = (char *) p->var_ptr;
703                while((cp = strchr(cp,'\n')) != NULL) {
704                   *cp++ = '\r';
705                }
706             }
707             fclose(fp);
708          }
709          break;
710 
711       case AF_SET_DEFAULT:
712          break;
713 
714       case AF_DISPLAY_VAR:
715          break;
716    }
717    return Ret;
718 }
719 
720 
721 // Configuration passes:
722 // 1 - first pass (duh!)
723 // 2 - Initialization complete.
724 // 3 - Station list downloaded from EchoLink directory server.
725 // 4 - Station list downloaded a second time from EchoLink directory server.
726 // 5 - Manual variable set
DoConfigPass(int Pass)727 int DoConfigPass(int Pass)
728 {
729    char *ConfigFile = ConfigFilePath;
730    static FILE *fp = NULL;
731    int Ret = 0;
732 
733    ConfigPass = Pass;
734    if(ConfigFile == NULL) {
735       ConfigFile = CONFIG_FILE_PATH;
736    }
737 
738    if(Pass == 1 && (fp = fopen(ConfigFile,"r")) == NULL) {
739       LOG_ERROR(("Fatal error opening configuration file, \"%s\".\n",
740                  ConfigFile));
741       Ret = CONFIG_OPEN_ERROR;
742    }
743    else {
744       fseek(fp,0,SEEK_SET);
745       Ret = read_config(fp,ConfigVars,Pass);
746       if(Pass == NUM_CONFIG_PASSES) {
747          fclose(fp);
748          fp = NULL;
749       }
750    }
751 
752    if(Pass == 1 && Ret == 0) do {
753    // Require that the callsign be a link, repeater or conference callsign
754       if(ConferenceCall != NULL &&
755          ConferenceCall[0] != '*' &&
756          strstr(ConferenceCall,"-R") == NULL &&
757          strstr(ConferenceCall,"-L") == NULL)
758       {  // Must be a bare callsign ... not allowed.
759          LOG_ERROR(("Error: Invalid ConferenceCall \"%s\".\n"
760                     "ConferenceCall must be a callsign folllowed by \"-R\", "
761                     "or \"-L\" or \n"
762                     "be an assigned conference name.\n",
763                     ConferenceCall));
764          Ret = ERR_CONFIG_FILE;
765          break;
766       }
767 
768       if(AvrsEnable && !AVRS_Validate()) {
769          Ret = ERR_CONFIG_FILE;
770          break;
771       }
772 
773       if(SF_Port != SF_ReplyPort) {
774          bEchoIrlpMode = TRUE;
775       }
776    } while(FALSE);
777 
778    return Ret;
779 }
780 
781 
782 // We're connected to the EchoLink network see if we have any AVRS
783 // info to send
AVRS_Validate()784 int AVRS_Validate()
785 {
786    struct hostent *pHost;
787    int Ret = FALSE;
788 
789 // We require Longitude, Latitude, and Frequency to be set
790    if(ConferenceCall[0] == '*') {
791       LOG_ERROR(("Error: AVRS reporting not available for conferences, "
792                  "AVRS disabled.\n"));
793    }
794    else if(Longitude > 180.0 || Longitude < -180.0) {
795       LOG_ERROR(("Error: Invalid Longitude, AVRS disabled.\n"));
796    }
797    else if(Latitude > 90.0 || Latitude < -90.0) {
798       LOG_ERROR(("Error: Invalid Latitude, AVRS disabled.\n"));
799    }
800    else if(AntDir > 360.0 || AntDir < 0.0) {
801       LOG_ERROR(("Error: Invalid Antenna direction, AVRS disabled.\n"));
802    }
803    else if(CTCSS < 0.0 || CTCSS > 229.1) {
804       LOG_ERROR(("Error: Invalid CTCSS frequency, AVRS disabled.\n"));
805    }
806    else {
807       Ret = TRUE;
808 
809    // Prime the DNS cache so we'll have the IP address later when we need it
810       pHost = GetHostByName("aprs.echolink.org");
811    }
812 
813    AvrsEnable = Ret;
814 
815    return Ret;
816 }
817 
ConfigGetVarPtr(struct config_entry * pConfig)818 void *ConfigGetVarPtr(struct config_entry *pConfig)
819 {
820    return NULL;
821 }
822 
CheckRTP_PortSpec(char * Spec)823 int CheckRTP_PortSpec(char *Spec)
824 {
825    int Ret = ERR_CONFIG_FILE; // assume the worse
826    char *cp = strchr(Spec,'-');
827    int FirstPort;
828    int LastPort;
829 
830    do {
831       if(sscanf(Spec,"%d",&FirstPort) != 1) {
832          LOG_ERROR(("Error:  Invalid RTP_Port \"%s\"\n",Spec));
833          break;
834       }
835       else if(FirstPort & 1) {
836          LOG_ERROR(("Error: First RTP port must be even\n"));
837          break;
838       }
839 
840       if(cp != NULL) {
841       // Range
842          if(sscanf(&cp[1],"%d",&LastPort) != 1) {
843             LOG_ERROR(("Error: Invalid RTP_Port \"%s\"\n",Spec));
844             break;
845          }
846          else if(!(LastPort & 1)) {
847             LOG_ERROR(("Error: Last RTP port must be odd\n"));
848             break;
849          }
850          else if(LastPort <= FirstPort) {
851             LOG_ERROR(("Error: The last port must larger the first port\n"));
852             break;
853          }
854       }
855       Ret = 0;
856    } while(FALSE);
857 
858 
859    return Ret;
860 }
861 
862 
863 // Rtp_port = 0   // disable
864 // Rtp_port = <evenport>
865 // Rtp_port = <evenport>-<oddport> for a range
AccessRtpPort(struct config_entry * p,char * Arg,AfCmd Cmd,int x)866 int AccessRtpPort(struct config_entry *p, char *Arg, AfCmd Cmd, int x)
867 {
868    int Ret = ERR_CONFIG_FILE; // assume the worse
869 
870    switch(Cmd) {
871       case AF_SET_VAR:
872          if((Ret = CheckRTP_PortSpec(Arg)) != 0) {
873             break;
874          }
875          if(RTP_Port != NULL) {
876             free(RTP_Port);
877          }
878          RTP_Port = strdup(Arg);
879 
880          printf("ConfigPass: %d\n",ConfigPass);
881          if(ConfigPass == MANUAL_SET) {
882             RtpInit();
883          }
884          break;
885 
886       case AF_SET_DEFAULT:
887          Ret = 0;
888          break;
889 
890       case AF_DISPLAY_VAR:
891          snprintf(Arg,x,"%s",RTP_Port != NULL ? RTP_Port : "not set");
892          Ret = 0;
893          break;
894    }
895 
896    return Ret;
897 }
898 
899