1 /*----------------------------------------------------------------------------+
2 | |
3 | HEYU Configuration |
4 | Copyright 2002,2003,2004-2008 Charles W. Sullivan |
5 | |
6 | |
7 | As used herein, HEYU is a trademark of Daniel B. Suthers. |
8 | X10, CM11A, and ActiveHome are trademarks of X-10 (USA) Inc. |
9 | The author is not affiliated with either entity. |
10 | |
11 | Charles W. Sullivan |
12 | Co-author and Maintainer |
13 | Greensboro, North Carolina |
14 | Email ID: cwsulliv01 |
15 | Email domain: -at- heyu -dot- org |
16 | |
17 +----------------------------------------------------------------------------*/
18
19 /*
20 * This program is free software: you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation, either version 3 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program. If not, see <http://www.gnu.org/licenses/>.
32 *
33 */
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39
40 #include <ctype.h>
41 #include <unistd.h>
42 #if defined(SYSV) || defined(FREEBSD) || defined(OPENBSD)
43 #include <string.h>
44 #else
45 #include <strings.h>
46 #endif
47
48 #include <syslog.h>
49 #include <time.h>
50
51 #include "x10.h"
52 #include "process.h"
53 #include "sun.h"
54 #include "x10state.h"
55
56 extern int line_no, verbose;
57 extern int i_am_relay, i_am_aux, i_am_state, i_am_monitor;
58 extern char heyu_path[PATH_LEN + 1];
59 extern char alt_path[PATH_LEN + 1];
60 extern char heyu_script[PATH_LEN + 1];
61 extern long std_tzone;
62 extern char default_housecode;
63 extern char heyu_config[PATH_LEN + 1];
64
65 extern int fetch_x10state ( void );
66 extern int fetch_x10state_old ( void );
67 extern struct x10global_st x10global;
68
69 char statefile[PATH_LEN + 1];
70 char enginelockfile[PATH_LEN + 1];
71 char auxfile[PATH_LEN + 1];
72
73 unsigned int transceive_list[16];
74
75 unsigned int ore_ignore[32];
76 int ore_ignore_size;
77
78 unsigned int sec_ignore[32];
79 int sec_ignore_size;
80
81 CONFIG config;
82 CONFIG *configp = NULL;
83
84 enum {
85 OldAlias, Alias, UserSyn, Launcher, Script, Scene, RFBursts,
86 /* Directives with multiple instances allowed */
87 /* must be before 'Separator'. */
88 Separator,
89 Tty, TtyAux, HouseCode, ForceAddr,
90 NewFormat, ScheduleFile, MaxPParms, RcsTemp, StatusTimeout,
91 SpfTimeout, DispExpMac, AckHails, Mode, ProgramDays,
92 AsIfDate, AsIfTime, CombineEvents, CompressMacros, FebKluge,
93 Latitude, Longitude, DawnOption, DuskOption, DawnSubstitute,
94 DuskSubstitute, MinDawn, MaxDawn, MinDusk, MaxDusk, CheckFiles,
95 ReportPath, ReplDelay, Ignored, ResvTimers, TrigTag, XrefApp,
96 MacTerm, AutoChain, ResOverlap, ModuleTypes, LaunchMode,
97 FunctionMode, LaunchSrc, DefaultModule, ScriptShell, ScriptMode,
98 LogDir, IsDarkOffset, EnvAliasPrefix, DevType, SunMode, Fix5A,
99 AutoFetch, PfailUpdate, BitDelay, DefRFBursts, BurstSpacing,
100 TimerTweak, RFPostDelay, RFFarbDelay, RFFarwDelay, DispRFX, LoopCount,
101 RestrictDims, StateFmt, /* StateDir, */PfailScript, CM11PostDelay,
102 StartEngine, IgnoreSilent, NoSwitch, RespoolPerms, SpoolMax,
103 CheckRILine, RIdisable, SendRetries, ScriptCtrl, Transceive, TransMissp,
104 RFForward, TransDim, StateCtrl, RFFuncMask, RingCtrl, AuxRepcounts,
105 AuxMincountRFX, HideUnchg, HideUnchgInactive, ShowChange, DispRFNoise, ArmMaxDelay, DispRawRF, ArmLogic,
106 InactiveTimeout, HeyuUmask, AutoWait, FullBright, EnginePoll,
107 RfxTscale, RfxVadscale, RfxBPscale, DispSubdir, RfxComDtrRts, RfxHiBaud,
108 RfxPowerScale, RfxWaterScale, RfxGasScale, RfxPulseScale, RfxComEnable, RfxComDisable,
109 LockupCheck, TailPath, RfxJam, DispDmxTemp, SecID16, SecIDPar, LogDateYr,
110 DmxTscale, OreTscale, OreBPscale, OreWgtscale, OreLowBatt, DispOreAll,
111 OreChgBitsT, OreChgBitsRH, OreChgBitsBP, OreChgBitsWgt, OreDataEntry, OreDispChan, OreID16,
112 OreDispFcast, LogDateUnix, InactiveTimeoutOre, DispSensorIntv, DateFormat, LockTimeout,
113 CM11QueryDelay, ElsNumber, ElsVoltage, ElsChgBitsCurr, OreWindscale, OreWindSensorDir,
114 OreRainRatescale, OreRainTotscale, OreDispBatLvl, OreWindDirMode, OreDispCount,
115 OreDispBft, OreChgBitsWsp, OreChgBitsWavsp, OreChgBitsWdir, OreChgBitsRrate, OreChgBitsRtot,
116 OreChgBitsUV, ScanMode, RfxInline,
117 OwlVoltage, OwlCalibPower, OwlCalibEnergy, OwlChgBitsPower, OwlChgBitsEnergy, OwlDispCount,
118 ArmRemote, ActiveChange, InactiveHandling, ProcessXmit, ShowFlagsMode,
119 LaunchPathAppend, LaunchPathPrefix, FixStopStartError, TtyRFXmit, ChkSumTimeout
120
121 };
122
123 #define CSTP 1 /* Minimal config for stop command */
124 #define CCAL 2 /* Minimal config for syscheck command */
125 #define CMLT 4 /* Multiple instances allowed */
126 #define COVR 8 /* Allow override in sched file */
127 #define CHLP 16 /* Minimal config for help command */
128 #define CIGN 32 /* Ignored (usually obsolete) */
129 #define CHID 64 /* Don't display */
130
131 static struct conf {
132 char *name;
133 int mintoken;
134 int maxtoken;
135 unsigned char isparsed;
136 unsigned char override; /* Allow override in sched file */
137 unsigned int flags;
138 unsigned int switchval;
139 } command[] = {
140 {"(_alias_)", 3, 3, 0, 0, CMLT, OldAlias },
141 {"ALIAS", 3,16, 0, 0, CMLT, Alias },
142 {"LAUNCHER", 2,-1, 0, 0, CMLT, Launcher},
143 {"SCRIPT", 2,-1, 0, 0, CMLT, Script },
144 {"USERSYN", 2,-1, 0, 0, CMLT, UserSyn },
145 {"SCENE", 2,-1, 0, 0, CMLT, Scene },
146 {"SECTION", 1,-1, 0, 0, COVR|CMLT, IgnoreSilent},
147 /* Multiple instances OK for switchval above */
148 {"TTY", 2, 4, 0, 0, CSTP, Tty },
149 {"TTY_AUX", 3, 5, 0, 0, CSTP, TtyAux},
150 {"TTY_RFXMIT", 3, 3, 0, 0, CSTP, TtyRFXmit},
151 {"HOUSECODE", 2, 2, 0, 0, 0, HouseCode },
152 {"FORCE_ADDR", 2, 2, 0, 0, 0, ForceAddr },
153 {"NEWFORMAT", 1, 1, 0, 0, CIGN, Ignored },
154 {"MACROXREF", 2, 2, 0, 0, CIGN, Ignored },
155 {"SCHEDULE_FILE", 2, 2, 0, 0, 0, ScheduleFile },
156 {"MAX_PPARMS", 2, 2, 0, 0, 0, MaxPParms },
157 {"STATUS_TIMEOUT", 2, 2, 0, 0, 0, StatusTimeout },
158 {"SPF_TIMEOUT", 2, 2, 0, 0, 0, SpfTimeout },
159 {"RCS_TEMPERATURE", 2, 2, 0, 0, 0, RcsTemp },
160 {"RCS_DECODE", 2, 2, 0, 0, 0, RcsTemp },
161 {"DISPLAY_EXP_MACROS", 2, 2, 0, 0, CIGN, Ignored },
162 {"ACK_HAILS", 2, 2, 0, 0, 0, AckHails },
163 {"MODE", 2, 2, 0, 1, COVR, Mode },
164 {"PROGRAM_DAYS", 2, 2, 0, 1, COVR, ProgramDays },
165 {"ASIF_DATE", 2, 2, 0, 1, COVR, AsIfDate },
166 {"ASIF_TIME", 2, 2, 0, 1, COVR, AsIfTime },
167 {"COMBINE_EVENTS", 2, 2, 0, 1, COVR, CombineEvents },
168 {"COMPRESS_MACROS", 2, 2, 0, 1, COVR, CompressMacros },
169 {"FEB_KLUGE", 2, 2, 0, 1, COVR, FebKluge },
170 {"LATITUDE", 2, 2, 0, 1, COVR, Latitude },
171 {"LONGITUDE", 2, 2, 0, 1, COVR, Longitude },
172 {"DAWN_OPTION", 2, 2, 0, 1, COVR, DawnOption },
173 {"DUSK_OPTION", 2, 2, 0, 1, COVR, DuskOption },
174 {"DAWN_SUBSTITUTE", 2, 2, 0, 1, COVR|CIGN, Ignored },
175 {"DUSK_SUBSTITUTE", 2, 2, 0, 1, COVR|CIGN, Ignored },
176 {"MIN_DAWN", 2, 2, 0, 1, COVR, MinDawn },
177 {"MAX_DAWN", 2, 2, 0, 1, COVR, MaxDawn },
178 {"MIN_DUSK", 2, 2, 0, 1, COVR, MinDusk },
179 {"MAX_DUSK", 2, 2, 0, 1, COVR, MaxDusk },
180 {"WRITE_CHECK_FILES", 2, 2, 0, 1, COVR, CheckFiles },
181 {"REPORT_PATH", 2, 2, 0, 1, COVR, ReportPath },
182 {"REPL_DELAYED_MACROS", 2, 2, 0, 1, COVR, ReplDelay },
183 {"RESERVED_TIMERS", 2, 2, 0, 1, COVR|CHID, ResvTimers }, /* WIP */
184 {"TRIGGER_TAG", 2, 2, 0, 1, COVR|CIGN, Ignored },
185 {"XREF_APPEND", 2, 2, 0, 1, COVR|CIGN, Ignored },
186 {"MACTERM", 2, 2, 0, 1, COVR, MacTerm }, /* WIP */
187 {"RESOLVE_OVERLAP", 2, 2, 0, 1, COVR, ResOverlap },
188 {"DAWNDUSK_DEF", 2, 3, 0, 1, COVR, SunMode },
189 {"SCRIPT_MODE", 2, 2, 0, 0, 0, ScriptMode },
190 {"SCRIPT_SHELL", 2, 2, 0, 0, 0, ScriptShell },
191 {"LAUNCH_SOURCE", 2, 6, 0, 0, 0, LaunchSrc },
192 {"DEFAULT_MODULE", 2, 2, 0, 0, 0, DefaultModule },
193 {"LOG_DIR", 2, 3, 0, 0, 0, LogDir },
194 {"DISPLAY_SUBDIR", 2, 2, 0, 0, 0, DispSubdir },
195 {"ISDARK_OFFSET", 2, 2, 0, 0, 0, IsDarkOffset },
196 {"ENV_ALIAS_PREFIX", 2, 2, 0, 0, 0, EnvAliasPrefix },
197 {"FIX_5A", 2, 2, 0, 0, CHID, Fix5A },
198 {"AUTOFETCH", 2, 2, 0, 0, 0, AutoFetch },
199 {"POWERFAIL_UPDATE", 2, 2, 0, 0, 0, PfailUpdate },
200 {"CM17A_BIT_DELAY", 2, 2, 0, 0, 0, BitDelay },
201 {"DEF_RF_BURSTS", 2, 2, 0, 0, 0, DefRFBursts },
202 {"RF_BURSTS", 3,21, 0, 0, 0, RFBursts},
203 {"TIMER_LOOPCOUNT", 2, 2, 0, 0, 0, LoopCount },
204 {"RF_BURST_SPACING", 2, 2, 0, 0, 0, BurstSpacing },
205 {"RF_TIMER_TWEAK", 2, 2, 0, 0, 0, TimerTweak },
206 {"RF_POST_DELAY", 2, 2, 0, 0, 0, RFPostDelay },
207 {"RF_FARB_DELAY", 2, 2, 0, 0, 0, RFFarbDelay },
208 {"RF_FARW_DELAY", 2, 2, 0, 0, 0, RFFarwDelay },
209 {"DISPLAY_RF_XMIT", 2, 2, 0, 0, 0, DispRFX },
210 {"RESTRICT_DIMS", 2, 2, 0, 0, 0, RestrictDims },
211 {"STATE_FORMAT", 2, 2, 0, 0, 0, StateFmt },
212 {"RELAY_POWERFAIL_SCRIPT", 2,-1, 0, 0, CHID, PfailScript},
213 {"CM11_POST_DELAY", 2, 2, 0, 0, 0, CM11PostDelay},
214 {"START_ENGINE", 2, 2, 0, 0, 0, StartEngine},
215 {"RF_NOSWITCH", 2, 2, 0, 0, 0, NoSwitch},
216 {"RESPOOL_PERMISSIONS", 2, 2, 0, 0, CHID, RespoolPerms},
217 {"SPOOLFILE_MAX", 2, 2, 0, 0, 0, SpoolMax},
218 {"CHECK_RI_LINE", 2, 2, 0, 0, 0, CheckRILine},
219 {"RI_DISABLE", 2, 2, 0, 0, 0, RIdisable},
220 {"SEND_RETRIES", 2, 2, 0, 0, 0, SendRetries},
221 {"TRANSCEIVE", 2, 3, 0, 0, 0, Transceive},
222 {"TRANSCIEVE", 2, 3, 0, 0, CHID, TransMissp},
223 {"RFFORWARD", 2, 3, 0, 0, 0, RFForward},
224 {"TRANS_DIMLEVEL", 2, 2, 0, 0, 0, TransDim},
225 {"SCRIPT_CTRL", 2, 2, 0, 0, 0, ScriptCtrl},
226 {"STATE_CTRL", 2, 2, 0, 0, 0, StateCtrl},
227 {"RING_CTRL", 2, 2, 0, 0, 0, RingCtrl},
228 {"RF_FUNCMASK", 2,-1, 0, 0, 0, RFFuncMask},
229 {"AUX_REPCOUNTS", 4, 4, 0, 0, 0, AuxRepcounts},
230 {"AUX_MINCOUNT_RFX", 2, 2, 0, 0, 0, AuxMincountRFX},
231 {"HIDE_UNCHANGED", 2, 2, 0, 0, 0, HideUnchg},
232 {"HIDE_UNCHANGED_INACTIVE", 2, 2, 0, 0, 0, HideUnchgInactive},
233 {"SHOW_CHANGE", 2, 2, 0, 0, 0, ShowChange},
234 {"DISPLAY_RF_NOISE", 2, 2, 0, 0, 0, DispRFNoise},
235 {"ARM_MAX_DELAY", 2, 2, 0, 0, 0, ArmMaxDelay},
236 {"DISPLAY_RAW_RF", 2, 2, 0, 0, 0, DispRawRF},
237 {"ARM_LOGIC", 2, 2, 0, 0, 0, ArmLogic},
238 {"INACTIVE_TIMEOUT", 2, 2, 0, 0, 0, InactiveTimeout},
239 {"HEYU_UMASK", 2, 2, 0, 0, 0, HeyuUmask},
240 {"AUTO_WAIT", 2, 2, 0, 0, 0, AutoWait},
241 {"FULL_BRIGHT", 2, 2, 0, 0, 0, FullBright},
242 {"ENGINE_POLL", 2, 2, 0, 0, 0, EnginePoll},
243 {"DMX_TSCALE", 2, 3, 0, 0, 0, DmxTscale},
244 {"ORE_LOWBATTERY", 2, 2, 0, 0, 0, OreLowBatt},
245 {"ORE_TSCALE", 2, 3, 0, 0, 0, OreTscale},
246 {"ORE_BPSCALE", 3, 4, 0, 0, 0, OreBPscale},
247 {"ORE_WGTSCALE", 3, 3, 0, 0, 0, OreWgtscale},
248 {"ORE_WINDSCALE", 3, 3, 0, 0, 0, OreWindscale},
249 {"ORE_WINDSENSORDIR", 2, 2, 0, 0, 0, OreWindSensorDir},
250 {"ORE_WINDDIR_MODE", 2, 2, 0, 0, 0, OreWindDirMode},
251 {"ORE_RAINRATESCALE", 3, 3, 0, 0, 0, OreRainRatescale},
252 {"ORE_RAINTOTSCALE", 3, 3, 0, 0, 0, OreRainTotscale},
253 {"RFX_TSCALE", 2, 3, 0, 0, 0, RfxTscale},
254 {"RFX_VADSCALE", 3, 4, 0, 0, 0, RfxVadscale},
255 {"RFX_BPSCALE", 3, 4, 0, 0, 0, RfxBPscale},
256 {"RFXCOM_DTR_RTS", 2, 2, 0, 0, 0, RfxComDtrRts},
257 {"RFXCOM_HIBAUD", 2, 2, 0, 0, CHID, RfxHiBaud},
258 {"RFX_POWERSCALE", 3, 3, 0, 0, 0, RfxPowerScale},
259 {"RFX_WATERSCALE", 3, 3, 0, 0, 0, RfxWaterScale},
260 {"RFX_GASSCALE", 3, 3, 0, 0, 0, RfxGasScale},
261 {"RFX_PULSESCALE", 3, 3, 0, 0, 0, RfxPulseScale},
262 {"RFXCOM_ENABLE", 2, 4, 0, 0, 0, RfxComEnable},
263 {"RFXCOM_DISABLE", 2,16, 0, 0, 0, RfxComDisable},
264 {"LOCKUP_CHECK", 2, 2, 0, 0, CHID, LockupCheck},
265 {"TAILPATH", 2, 2, 0, 0, 0, TailPath},
266 {"SUPPRESS_RFXJAM", 2, 2, 0, 0, 0, RfxJam},
267 {"DISPLAY_DMXTEMP", 2, 2, 0, 0, 0, DispDmxTemp},
268 {"SECURID_16", 2, 2, 0, 0, 0, SecID16},
269 {"SECURID_PARITY", 2, 2, 0, 0, 0, SecIDPar},
270 {"LOGDATE_YEAR", 2, 2, 0, 0, 0, LogDateYr},
271 {"DISPLAY_ORE_ALL", 2, 2, 0, 0, 0, DispOreAll},
272 {"ORE_CHGBITS_T", 2, 2, 0, 0, 0, OreChgBitsT},
273 {"ORE_CHGBITS_RH", 2, 2, 0, 0, 0, OreChgBitsRH},
274 {"ORE_CHGBITS_BP", 2, 2, 0, 0, 0, OreChgBitsBP},
275 {"ORE_CHGBITS_WGT", 2, 2, 0, 0, 0, OreChgBitsWgt},
276 {"ORE_CHGBITS_WSP", 2, 2, 0, 0, CIGN, Ignored},
277 {"ORE_CHGBITS_WINDSP", 2, 2, 0, 0, 0, OreChgBitsWsp},
278 {"ORE_CHGBITS_WAVSP", 2, 2, 0, 0, CIGN, Ignored},
279 {"ORE_CHGBITS_WINDAVSP", 2, 2, 0, 0, 0, OreChgBitsWavsp},
280 {"ORE_CHGBITS_WDIR", 2, 2, 0, 0, CIGN, Ignored},
281 {"ORE_CHGBITS_WINDDIR", 2, 2, 0, 0, 0, OreChgBitsWdir},
282 {"ORE_CHGBITS_RRATE", 2, 2, 0, 0, CIGN, Ignored},
283 {"ORE_CHGBITS_RAINRATE", 2, 2, 0, 0, 0, OreChgBitsRrate},
284 {"ORE_CHGBITS_RTOT", 2, 2, 0, 0, CIGN, Ignored},
285 {"ORE_CHGBITS_RAINTOT", 2, 2, 0, 0, 0, OreChgBitsRtot},
286 {"ORE_CHGBITS_UV", 2, 2, 0, 0, 0, OreChgBitsUV},
287 {"ORE_DATA_ENTRY", 2, 2, 0, 0, 0, OreDataEntry},
288 {"ORE_DISPLAY_CHAN", 2, 2, 0, 0, 0, OreDispChan},
289 {"ORE_DISPLAY_BATLVL", 2, 2, 0, 0, 0, OreDispBatLvl},
290 {"ORE_DISPLAY_RAW", 2, 2, 0, 0, CIGN, Ignored},
291 {"ORE_DISPLAY_COUNT", 2, 2, 0, 0, 0, OreDispCount},
292 {"ORE_DISPLAY_BEAUFORT", 2, 2, 0, 0, 0, OreDispBft},
293 {"ORE_ID_16", 2, 2, 0, 0, 0, OreID16},
294 {"ORE_DISPLAY_FCAST", 2, 2, 0, 0, 0, OreDispFcast},
295 {"LOGDATE_UNIX", 2, 2, 0, 0, 0, LogDateUnix},
296 {"DISPLAY_SENSOR_INTV", 2, 2, 0, 0, 0, DispSensorIntv},
297 {"DATE_FORMAT", 2, 3, 0, 1, COVR, DateFormat},
298 {"LOCK_TIMEOUT", 2, 2, 0, 0, 0, LockTimeout},
299 {"CM11A_QUERY_DELAY", 2, 2, 0, 0, 0, CM11QueryDelay},
300 {"ELS_VOLTAGE", 2, 2, 0, 0, 0, ElsVoltage},
301 {"ELS_CHGBITS_CURR", 2, 2, 0, 0, 0, ElsChgBitsCurr},
302 {"LAUNCHER_SCANMODE", 2, 2, 0, 0, 0, ScanMode},
303 {"RFXMETER_SETUP_INLINE", 2, 2, 0, 0, 0, RfxInline},
304 {"OWL_VOLTAGE", 2, 2, 0, 0, 0, OwlVoltage},
305 {"OWL_CALIB_POWER", 2, 2, 0, 0, 0, OwlCalibPower},
306 {"OWL_CALIB_ENERGY", 2, 2, 0, 0, 0, OwlCalibEnergy},
307 {"OWL_CHGBITS_POWER", 2, 2, 0, 0, 0, OwlChgBitsPower},
308 {"OWL_CHGBITS_ENERGY", 2, 2, 0, 0, 0, OwlChgBitsEnergy},
309 {"OWL_DISPLAY_COUNT", 2, 2, 0, 0, 0, OwlDispCount},
310 {"ARM_REMOTE", 2, 2, 0, 0, 0, ArmRemote},
311 // {"ACTIVE_CHANGE", 2, 2, 0, 0, CIGN, Ignored},
312 {"INACTIVE_HANDLING", 2, 2, 0, 0, 0, InactiveHandling},
313 {"PROCESS_XMIT", 2, 2, 0, 0, 0, ProcessXmit},
314 {"SHOW_FLAGS_MODE", 2, 2, 0, 0, 0, ShowFlagsMode},
315 {"LAUNCHPATH_APPEND", 2, 2, 2, 0, 0, LaunchPathAppend},
316 {"LAUNCHPATH_PREFIX", 2, 2, 2, 0, 0, LaunchPathPrefix},
317 {"FIX_STOPSTART_ERROR", 2, 2, 0, 1, COVR, FixStopStartError},
318 // {"CHKSUM_TIMEOUT", 2, 2, 0, 0, 0, ChkSumTimeout},
319
320 #if 0
321 {"ELS_NUMBER", 2, 2, 0, 0, 0, ElsNumber},
322 #endif
323 #if 0
324 {"INACTIVE_TIMEOUT_ORE", 2, 2, 0, 0, 0, InactiveTimeoutOre}, /* WIP */
325 #endif
326 };
327 int ncommands = ( sizeof(command)/sizeof(struct conf) );
328
329 /* Dawn/Dusk options */
330 static struct ddopt {
331 char *label;
332 unsigned char value;
333 } dd_option[] = {
334 {"FIRST", FIRST },
335 {"EARLIEST", EARLIEST },
336 {"LATEST", LATEST },
337 {"AVERAGE", AVERAGE },
338 {"MEDIAN", MEDIAN },
339 };
340 int nddopt = ( sizeof(dd_option)/sizeof(struct ddopt) );
341
342 /* Launch source options - set default sources of signal */
343 /* permitted to launch a script. */
344 static struct lsopt {
345 char *label;
346 unsigned int value;
347 } ls_option[] = {
348 {"SNDC", SNDC }, /* Sent from command line */
349 {"SNDM", SNDM }, /* Sent from macro executed by Timer */
350 {"SNDT", SNDT }, /* Sent from macro executed by Trigger */
351 {"SNDP", SNDP }, /* Sent from a relay powerfail script */
352 {"SNDS", SNDS }, /* Sent from a script */
353 {"RCVI", RCVI }, /* Received from the interface */
354 {"RCVT", RCVT }, /* Trigger which executed a macro */
355 {"SNDA", SNDA }, /* Transceived by aux daemon */
356 {"RCVA", RCVA }, /* Received via sptty from aux daemon */
357 {"ANYSRC", LSALL }, /* Any of the above (SNDS and SNDP not included!) */
358 {"NOSRC", LSNONE }, /* No sources are the default */
359 };
360 int nlsopt = ( sizeof(ls_option)/sizeof(struct lsopt) );
361
362 /* CM17A function labels. Note: CONFIG.rf_bursts[] in */
363 /* process.h must be at least the size of nrflabels below */
364 static struct cm17a_label {
365 char *label;
366 unsigned char subcode;
367 } rf_label[] = {
368 {"falloff", 0 },
369 {"flightson", 1 },
370 {"fon", 2 },
371 {"foff", 3 },
372 {"fdim", 4 },
373 {"fbright", 5 },
374 {"flightsoff", 6 },
375 {"_", 7 },
376 {"_", 8 },
377 {"farb", 9 },
378 {"farw", 10 },
379 };
380 int nrflabels = ( sizeof(rf_label)/sizeof(struct cm17a_label) );
381
382 /*---------------------------------------------------------------------+
383 | Reset the isparsed flags in the conf struct array. |
384 +---------------------------------------------------------------------*/
reset_isparsed_flags(void)385 void reset_isparsed_flags ( void )
386 {
387 int j;
388
389 for ( j = 0; j < ncommands; j++ )
390 command[j].isparsed = 0;
391
392 return;
393 }
394
395 /*---------------------------------------------------------------------+
396 | Return 1 if all valid characters within alias label, otherwise 0 |
397 +---------------------------------------------------------------------*/
is_valid_alias_label(char * label,char ** sp)398 int is_valid_alias_label ( char *label, char **sp )
399 {
400 *sp = label;
401 while ( **sp ) {
402 if ( isalnum((int)(**sp)) || strchr("-_.", **sp) ) {
403 (*sp)++;
404 continue;
405 }
406 return 0;
407 }
408 return 1;
409 }
410
411 /*---------------------------------------------------------------------+
412 | Initialize the CONFIG structure with default values. |
413 +---------------------------------------------------------------------*/
initialize_config(void)414 void initialize_config ( void )
415 {
416 char *sp1;
417 int j;
418
419 /* Load default configuration values */
420 configp->read_flag = 0;
421 configp->mode = DEF_MODE;
422 (void) strncpy2(configp->schedfile, DEF_SCHEDFILE, sizeof(config.schedfile) - 1);
423 configp->asif_date = -1;
424 configp->asif_time = -1;
425 configp->program_days_in = DEF_PROGRAM_DAYS;
426 configp->program_days = DEF_PROGRAM_DAYS;
427 configp->combine_events = DEF_COMBINE_EVENTS;
428 configp->compress_macros = DEF_COMPRESS_MACROS;
429 configp->feb_kluge = DEF_FEB_KLUGE;
430 configp->housecode = DEF_HOUSECODE;
431 configp->force_addr = DEF_FORCE_ADDR;
432 configp->loc_flag = 0;
433 configp->dawn_option = DEF_DAWN_OPTION;
434 configp->dusk_option = DEF_DUSK_OPTION;
435 configp->dawn_substitute = DEF_DAWN_SUBSTITUTE;
436 configp->dusk_substitute = DEF_DUSK_SUBSTITUTE;
437 configp->min_dawn = DEF_MIN_DAWN;
438 configp->max_dawn = DEF_MAX_DAWN;
439 configp->min_dusk = DEF_MIN_DUSK;
440 configp->max_dusk = DEF_MAX_DUSK;
441 strncpy2(configp->tty, DEF_TTY, sizeof(config.tty) - 1);
442 configp->ttyaux[0] = '\0';
443 configp->auxhost[0] = '\0';
444 configp->auxport[0] = '\0';
445 configp->suffixaux[0] = '\0';
446 configp->auxdev = 0;
447 configp->newformat = 0;
448 configp->checkfiles = DEF_CHECK_FILES;
449 configp->repl_delay = DEF_REPL_DELAYED_MACROS;
450 configp->reserved_timers = DEF_RESERVED_TIMERS;
451 configp->alias_size = 0;
452 configp->aliasp = NULL;
453 configp->scenep = NULL;
454 configp->scriptp = NULL;
455 configp->launcherp = NULL;
456 configp->pfail_script = NULL;
457 configp->max_pparms = DEF_MAX_PPARMS;
458 configp->rcs_temperature = DEF_RCS_TEMPERATURE;
459 configp->trigger_tag = DEF_TRIGGER_TAG;
460 configp->display_offset = DEF_DISPLAY_OFFSET;
461 configp->xref_append = DEF_XREF_APPEND;
462 configp->ack_hails = DEF_ACK_HAILS;
463 configp->macterm = DEF_MACTERM;
464 configp->status_timeout = DEF_STATUS_TIMEOUT;
465 configp->spf_timeout = DEF_SPF_TIMEOUT;
466 configp->disp_exp_mac = DEF_DISPLAY_EXP_MACROS;
467 configp->module_types = DEF_MODULE_TYPES;
468 configp->launch_mode = DEF_LAUNCH_MODE;
469 configp->function_mode = DEF_FUNCTION_MODE;
470 configp->launch_source = DEF_LAUNCH_SOURCE;
471 configp->res_overlap = DEF_RES_OVERLAP;
472 configp->default_module = lookup_module_type(DEF_DEFAULT_MODULE);
473 configp->script_mode = DEF_SCRIPT_MODE;
474 if ( (sp1 = getenv("SHELL")) != NULL )
475 strncpy2(configp->script_shell, sp1, sizeof(config.script_shell) - 1);
476 else
477 strncpy2(configp->script_shell, "/bin/sh", sizeof(config.script_shell) - 1);
478 *configp->logfile = '\0';
479 configp->logcommon = NO;
480 configp->disp_subdir = NO_ANSWER;
481 configp->isdark_offset = DEF_ISDARK_OFFSET;
482 strncpy2(configp->env_alias_prefix, DEF_ENV_ALIAS_PREFIX, sizeof(config.env_alias_prefix) - 1);
483 configp->sunmode = DEF_SUNMODE;
484 configp->fix_5a = DEF_FIX_5A;
485 configp->cm11_post_delay = DEF_CM11_POST_DELAY;
486 configp->pfail_update = DEF_PFAIL_UPDATE;
487 configp->cm17a_bit_delay = DEF_CM17A_BIT_DELAY;
488 configp->rf_burst_spacing = DEF_RF_BURST_SPACING;
489 configp->rf_timer_tweak = DEF_RF_TIMER_TWEAK;
490 configp->rf_post_delay = DEF_RF_POST_DELAY;
491 configp->rf_farb_delay = DEF_RF_FARB_DELAY;
492 configp->rf_farw_delay = DEF_RF_FARW_DELAY;
493 configp->disp_rf_xmit = DEF_DISP_RF_XMIT;
494 configp->def_rf_bursts = DEF_RF_BURSTS;
495 for ( j = 0; j < nrflabels; j++ )
496 configp->rf_bursts[j] = DEF_RF_BURSTS;
497 configp->timer_loopcount = 0;
498 configp->restrict_dims = DEF_RESTRICT_DIMS;
499 configp->state_format = DEF_STATE_FORMAT;
500 configp->start_engine = DEF_START_ENGINE;
501 configp->rf_noswitch = DEF_RF_NOSWITCH;
502 configp->respool_perms = DEF_RESPOOL_PERMS;
503 configp->spool_max = DEF_SPOOLFILE_MAX;
504 configp->check_RI_line = DEF_CHECK_RI_LINE;
505 configp->send_retries = DEF_SEND_RETRIES;
506 configp->script_ctrl = DEF_SCRIPT_CTRL;
507 configp->transceive = DEF_TRANSCEIVE;
508 configp->rfforward = DEF_RFFORWARD;
509 configp->trans_dim = DEF_TRANS_DIMLEVEL;
510 configp->state_ctrl = DEF_STATE_CTRL;
511 configp->ring_ctrl = DEF_RING_CTRL;
512 configp->heyu_umask = DEF_HEYU_UMASK;
513 configp->log_umask = DEF_LOG_UMASK;
514 configp->rf_funcmask = DEF_RF_FUNCMASK;
515 configp->aux_repcounts[0] = 0; /* Value set at finalize_config() */
516 configp->aux_repcounts[1] = DEF_AUX_REPCOUNT;
517 configp->aux_repcounts[2] = DEF_AUX_MAXCOUNT;
518 configp->aux_repcounts[3] = DEF_AUX_FLOODREP;
519 configp->aux_mincount_rfx = 0; /* Value set at finalize_config() */
520 configp->hide_unchanged = DEF_HIDE_UNCHANGED;
521 configp->hide_unchanged_inactive = DEF_HIDE_UNCHANGED_INACTIVE;
522 configp->show_change = DEF_SHOW_CHANGE;
523 configp->disp_rf_noise = DEF_DISP_RF_NOISE;
524 configp->arm_max_delay = DEF_ARM_MAX_DELAY;
525 configp->disp_raw_rf = DEF_DISP_RAW_RF;
526 configp->arm_logic = DEF_ARM_LOGIC;
527 configp->inactive_timeout = DEF_INACTIVE_TIMEOUT;
528 configp->device_type = DEF_DEVICE_TYPE;
529 configp->auto_wait = DEF_AUTO_WAIT;
530 configp->full_bright = DEF_FULL_BRIGHT;
531 configp->engine_poll = DEF_ENGINE_POLL;
532 configp->dmx_tscale = DEF_DMX_TSCALE;
533 configp->dmx_toffset = DEF_DMX_TOFFSET;
534 configp->ore_lobat = DEF_ORE_LOWBATTERY;
535 configp->ore_tscale = DEF_ORE_TSCALE;
536 configp->ore_toffset = DEF_ORE_TOFFSET;
537 configp->ore_bpscale = DEF_ORE_BPSCALE;
538 configp->ore_bpoffset = DEF_ORE_BPOFFSET;
539 strncpy2(configp->ore_bpunits, DEF_ORE_BPUNITS, NAME_LEN - 1);
540 configp->ore_wgtscale = DEF_ORE_WGTSCALE;
541 strncpy2(configp->ore_wgtunits, DEF_ORE_WGTUNITS, NAME_LEN - 1);
542 configp->rfx_tscale = DEF_RFX_TSCALE;
543 configp->rfx_toffset = DEF_RFX_TOFFSET;
544 configp->rfx_vadscale = DEF_RFX_VADSCALE;
545 configp->rfx_vadoffset = DEF_RFX_VADOFFSET;
546 strncpy2(configp->rfx_vadunits, DEF_RFX_VADUNITS, NAME_LEN - 1);
547 configp->rfx_bpscale = DEF_RFX_BPSCALE;
548 configp->rfx_bpoffset = DEF_RFX_BPOFFSET;
549 strncpy2(configp->rfx_bpunits, DEF_RFX_BPUNITS, NAME_LEN - 1);
550 configp->rfxcom_dtr_rts = DEF_RFXCOM_DTR_RTS;
551 configp->rfxcom_hibaud = DEF_RFXCOM_HIBAUD;
552 configp->rfx_powerscale = DEF_RFX_POWERSCALE;
553 strncpy2(configp->rfx_powerunits, DEF_RFX_POWERUNITS, NAME_LEN - 1);
554 configp->rfx_waterscale = DEF_RFX_WATERSCALE;
555 strncpy2(configp->rfx_waterunits, DEF_RFX_WATERUNITS, NAME_LEN - 1);
556 configp->rfx_gasscale = DEF_RFX_GASSCALE;
557 strncpy2(configp->rfx_gasunits, DEF_RFX_GASUNITS, NAME_LEN - 1);
558 configp->rfx_pulsescale = DEF_RFX_PULSESCALE;
559 strncpy2(configp->rfx_pulseunits, DEF_RFX_PULSEUNITS, NAME_LEN - 1);
560 configp->rfxcom_enable = DEF_RFXCOM_ENABLE;
561 configp->rfxcom_disable = DEF_RFXCOM_DISABLE;
562 configp->lockup_check = DEF_LOCKUP_CHECK;
563 strncpy2(configp->tailpath, DEF_TAILPATH, sizeof(config.tailpath) - 1);
564 configp->suppress_rfxjam = DEF_SUPPRESS_RFXJAM;
565 configp->display_dmxtemp = DEF_DISPLAY_DMXTEMP;
566 configp->securid_16 = DEF_SECURID_16;
567 configp->securid_mask = DEF_SECURID_MASK;
568 configp->securid_parity = DEF_SECURID_PARITY;
569 configp->logdate_year = DEF_LOGDATE_YEAR;
570 configp->disp_ore_all = DEF_DISPLAY_ORE_ALL;
571 configp->ore_chgbits_t = DEF_ORE_CHGBITS_T;
572 configp->ore_chgbits_rh = DEF_ORE_CHGBITS_RH;
573 configp->ore_chgbits_bp = DEF_ORE_CHGBITS_BP;
574 configp->ore_chgbits_wgt = DEF_ORE_CHGBITS_WGT;
575 configp->ore_chgbits_wsp = DEF_ORE_CHGBITS_WSP;
576 configp->ore_chgbits_wavsp = DEF_ORE_CHGBITS_WAVSP;
577 configp->ore_chgbits_wdir = DEF_ORE_CHGBITS_WDIR;
578 configp->ore_chgbits_rrate = DEF_ORE_CHGBITS_RRATE;
579 configp->ore_chgbits_rtot = DEF_ORE_CHGBITS_RTOT;
580 configp->ore_chgbits_uv = DEF_ORE_CHGBITS_UV;
581 configp->ore_data_entry = DEF_ORE_DATA_ENTRY;
582 configp->ore_display_chan = DEF_ORE_DISPLAY_CHAN;
583 configp->ore_display_batlvl = DEF_ORE_DISPLAY_BATLVL;
584 configp->ore_display_count = DEF_ORE_DISPLAY_COUNT;
585 configp->oreid_16 = DEF_OREID_16;
586 configp->ore_display_fcast = DEF_ORE_DISPLAY_FCAST;
587 configp->oreid_mask = DEF_OREID_MASK;
588 configp->logdate_unix = DEF_LOGDATE_UNIX;
589 configp->inactive_timeout_ore = DEF_INACTIVE_TIMEOUT_ORE;
590 configp->display_sensor_intv = DEF_DISPLAY_SENSOR_INTV;
591 configp->date_format = DEF_DATE_FORMAT;
592 configp->date_separator = DEF_DATE_SEPARATOR;
593 configp->lock_timeout = DEF_LOCK_TIMEOUT;
594 configp->cm11a_query_delay = DEF_CM11A_QUERY_DELAY;
595 configp->els_number = DEF_ELS_NUMBER;
596 configp->els_voltage = DEF_ELS_VOLTAGE;
597 configp->els_chgbits_curr = DEF_ELS_CHGBITS_CURR;
598 configp->ore_windscale = DEF_ORE_WINDSCALE;
599 strcpy(configp->ore_windunits, DEF_ORE_WINDUNITS);
600 configp->ore_windsensordir = DEF_ORE_WINDSENSORDIR;
601 configp->ore_winddir_mode = DEF_ORE_WINDDIR_MODE;
602 configp->ore_rainratescale = DEF_ORE_RAINRATESCALE;
603 strcpy(configp->ore_rainrateunits, DEF_ORE_RAINRATEUNITS);
604 configp->ore_raintotscale = DEF_ORE_RAINTOTSCALE;
605 strcpy(configp->ore_raintotunits, DEF_ORE_RAINTOTUNITS);
606 configp->scanmode = DEF_SCANMODE;
607 configp->rfx_inline = DEF_RFX_INLINE;
608 configp->owl_voltage = DEF_OWL_VOLTAGE;
609 configp->owl_calib_power = DEF_OWL_CALIB_POWER;
610 configp->owl_calib_energy = DEF_OWL_CALIB_ENERGY;
611 configp->owl_chgbits_power = DEF_OWL_CHGBITS_POWER;
612 configp->owl_chgbits_energy = DEF_OWL_CHGBITS_ENERGY;
613 configp->owl_display_count = DEF_OWL_DISPLAY_COUNT;
614 configp->arm_remote = DEF_ARM_REMOTE;
615 configp->active_change = DEF_ACTIVE_CHANGE;
616 configp->inactive_handling = DEF_INACTIVE_HANDLING;
617 configp->process_xmit = DEF_PROCESS_XMIT;
618 configp->show_flags_mode = DEF_SHOW_FLAGS_MODE;
619 configp->rfx_master = DEF_RFX_MASTER;
620 configp->rfx_slave = DEF_RFX_SLAVE;
621 strcpy(configp->launchpath_append, DEF_LAUNCHPATH_APPEND);
622 strcpy(configp->launchpath_prefix, DEF_LAUNCHPATH_PREFIX);
623 configp->fix_stopstart_error = DEF_FIX_STOPSTART_ERROR;
624 configp->ttyrfxmit[0] = '\0';
625 configp->rfxmit_freq = 0;
626 configp->chksum_timeout = DEF_CHKSUM_TIMEOUT;
627
628 return;
629 }
630
631 /*---------------------------------------------------------------------+
632 | Parse the users configuration file and save info in CONFIG struct |
633 | for only the minimal directives required for some specific commands.|
634 | E.g., the 'heyu stop' command needs only the TTY directive. |
635 +---------------------------------------------------------------------*/
parse_minimal_config(FILE * fd_conf,unsigned char mode,unsigned char source)636 int parse_minimal_config ( FILE *fd_conf, unsigned char mode, unsigned char source )
637 {
638 char buffer[LINE_LEN];
639 char *sp1;
640 int err, errors;
641 CONFIG configtmp;
642
643 configp = &configtmp;
644
645 /* Make sure the isparsed flags are reset in the command list */
646 reset_isparsed_flags();
647
648 /* Load some default configuration values */
649 initialize_config();
650
651 line_no = 0;
652 errors = 0;
653 while ( fgets(buffer, LINE_LEN, fd_conf) != NULL ) {
654 line_no++ ;
655 buffer[LINE_LEN - 1] = '\0';
656
657 /* Get rid of comments and blank lines */
658 if ( (sp1 = strchr(buffer, '#')) != NULL )
659 *sp1 = '\0';
660 (void) strtrim(buffer);
661 if ( buffer[0] == '\0' )
662 continue;
663
664 err = parse_config_tail(buffer, source);
665 if ( err || *error_message() != '\0' ) {
666 fprintf(stderr, "Config Line %02d: %s\n", line_no, error_message());
667 clear_error_message();
668 }
669
670 errors += err;
671 if ( errors > MAX_ERRORS )
672 return 1;
673 }
674
675 /* Determine and load the user's timezone */
676 get_std_timezone();
677 configp->tzone = std_tzone;
678
679 /* Determine if Daylight Time is ever in effect and if so, */
680 /* the minutes after midnight it goes into and out of effect. */
681 configp->isdst = get_dst_info(0);
682
683 /* Add configuration items from environment */
684 errors += environment_config();
685
686 errors += finalize_config(mode);
687
688 if ( *error_message() != '\0' ) {
689 fprintf(stderr, "%s\n", error_message());
690 clear_error_message();
691 }
692
693 /* Free the allocated memory in the original config structure */
694 free_all_arrays(&config);
695
696 /* Copy the temporary config into the global structure */
697 memcpy(&config, configp, sizeof(config));
698
699 configp = &config;
700
701 /* Done with config file */
702 line_no = 0;
703
704 return errors;
705 }
706
707
708 /*---------------------------------------------------------------------+
709 | Parse the users configuration file and save info in CONFIG struct. |
710 | First check to see if it's already been read. |
711 +---------------------------------------------------------------------*/
parse_config(FILE * fd_conf,unsigned char mode)712 int parse_config ( FILE *fd_conf, unsigned char mode )
713 {
714 char buffer[LINE_LEN];
715 char *sp1;
716 int err, errors;
717 int j;
718 SCENE *scenep;
719 extern char *typename[];
720 CONFIG configtmp;
721
722
723 /* If the configuration file has already been read into memory, */
724 /* just return. */
725 if ( config.read_flag != 0 ) {
726 return 0;
727 }
728
729 configp = &configtmp;
730
731 /* Make sure the isparsed flags are reset in the command list */
732 reset_isparsed_flags();
733
734 /* Load some default configuration values */
735 initialize_config();
736
737 line_no = 0;
738 errors = 0;
739 while ( fgets(buffer, LINE_LEN, fd_conf) != NULL ) {
740 line_no++ ;
741 buffer[LINE_LEN - 1] = '\0';
742
743 /* Get rid of comments and blank lines */
744 if ( (sp1 = strchr(buffer, '#')) != NULL )
745 *sp1 = '\0';
746 (void) strtrim(buffer);
747 if ( buffer[0] == '\0' )
748 continue;
749
750 err = parse_config_tail(buffer, SRC_CONFIG);
751 if ( err || *error_message() != '\0') {
752 if ( !i_am_relay && !i_am_aux && !i_am_monitor )
753 fprintf(stderr, "Config Line %02d: %s\n", line_no, error_message());
754 clear_error_message();
755 }
756
757 errors += err;
758 if ( errors > MAX_ERRORS )
759 return 1;
760 }
761
762 /* Everything has now been read from the config file and stored */
763
764 /* Verify the syntax of user-defined scenes/usersyns */
765 scenep = configp->scenep;
766 j = 0;
767 while ( scenep && scenep[j].line_no > 0 ) {
768 if ( verify_scene(scenep[j].body) != 0 ) {
769 fprintf(stderr, "Config Line %02d: %s '%s': %s\n",
770 scenep[j].line_no, typename[scenep[j].type], scenep[j].label,
771 error_message());
772 clear_error_message();
773 if ( ++errors > MAX_ERRORS )
774 return errors;
775 }
776 else if ( *error_message() != '\0' ) {
777 /* Check warning messages */
778 fprintf(stderr, "Config Line %02d: %s '%s': %s\n",
779 scenep[j].line_no, typename[scenep[j].type], scenep[j].label,
780 error_message());
781 clear_error_message();
782 }
783 j++;
784 }
785
786 /* Configure module masks */
787 set_module_masks( configp->aliasp );
788
789 /* Use the Heyu path if the user hasn't provided an alternate */
790 if ( !(*alt_path) )
791 (void)strncpy2(alt_path, heyu_path, sizeof(alt_path) - 1);
792
793 /* Determine and load the user's timezone */
794 get_std_timezone();
795 configp->tzone = std_tzone;
796
797 /* Determine if Daylight Time is ever in effect and if so, */
798 /* the minutes after midnight it goes into and out of effect. */
799 configp->isdst = get_dst_info(0);
800
801 /* Add configuration items from environment */
802 errors += environment_config();
803
804 errors += finalize_config(mode);
805 if ( *error_message() != '\0' ) {
806 fprintf(stderr, "%s\n", error_message());
807 clear_error_message();
808 }
809 configp->read_flag = (errors == 0) ? 1 : 0;
810
811 if ( errors > 0 )
812 return errors;
813
814 /* Free the allocated memory in the original config structure */
815 free_all_arrays(&config);
816
817 /* Copy the temporary config into the global structure */
818 memcpy(&config, configp, sizeof(config));
819
820 configp = &config;
821
822 /* Done with config file */
823 line_no = 0;
824
825 return errors;
826 }
827
828
829 /*---------------------------------------------------------------------+
830 | Parse the config line in buffer. Argument 'source' can be |
831 | SRC_CONFIG if called from parse_config() or SRC_SCHED if called |
832 | from parse_sched(), for configuration items which may be overridden |
833 | in the latter. |
834 +---------------------------------------------------------------------*/
parse_config_tail(char * buffer,unsigned char source)835 int parse_config_tail ( char *buffer, unsigned char source )
836 {
837 char errbuffer[80];
838 char searchstr[128];
839 char directive[128];
840 char label[(NAME_LEN + SCENE_LEN + MACRO_LEN + 1)];
841 char token[50];
842 char hc;
843 char *bufp, *sp;
844 int errors = 0;
845 int num, value, hour, minut, len, modtype;
846 long longvalue;
847 int bursts;
848 int j, k, commj, switchval;
849 int tokc;
850 char **tokv = NULL;
851 int perms;
852 double dblvalue;
853
854 extern struct rfx_disable_st rfx_disable[];
855 extern int nrfxdisable;
856
857 bufp = buffer;
858 get_token(directive, &bufp, " \t", sizeof(directive)/sizeof(char));
859 strtrim(bufp);
860 strncpy2(searchstr, directive, sizeof(searchstr) - 1);
861 strupper(searchstr);
862
863
864 /* Search list of configuration commands starting */
865 /* past "oldalias". */
866
867 commj = 0; switchval = OldAlias;
868 for ( j = 1; j < ncommands; j++ ) {
869 if ( !strcmp(searchstr, command[j].name) ) {
870 switchval = command[j].switchval;
871 commj = j;
872 break;
873 }
874 }
875
876 /* See if override in schedule file is permitted */
877 if ( (source == SRC_SCHED || source == SRC_ENVIRON) &&
878 (command[commj].flags & COVR) == 0 ) {
879 if ( commj )
880 sprintf(errbuffer, "Configuration directive %s not allowed here.",
881 command[commj].name);
882 else
883 sprintf(errbuffer, "Invalid configuration directive");
884 store_error_message(errbuffer);
885 return 1;
886 }
887
888 /* Minimal configurations for some commands */
889 if ( source == SRC_STOP && (command[commj].flags & CSTP) == 0 )
890 return 0;
891 if ( source == SRC_HELP && (command[commj].flags & CHLP) == 0 )
892 return 0;
893 if ( source == SRC_SYSCHECK && (command[commj].flags & CCAL) == 0 )
894 return 0;
895
896
897 /* If the directive has a fixed number of tokens (as denoted */
898 /* by maxtokens > 0) or _might_ be an old-style alias, */
899 /* tokenize the tail immediately. */
900
901 if ( commj == 0 || command[j].maxtoken > 0 ) {
902 tokenize(bufp, " \t", &tokc, &tokv);
903 }
904 else {
905 tokc = (*bufp == '\0') ? 0 : 1 ;
906 }
907
908
909 /* If not found in list and it doesn't have the correct */
910 /* number of items for an alias, reject it. */
911 if ( commj == 0 && tokc != 2 ) {
912 sprintf(errbuffer, "Invalid Directive '%s'", directive);
913 store_error_message(errbuffer);
914 return 1;
915 }
916
917
918 /* Unless allowed, check to see it's not a duplicate */
919 /* of an earlier directive. */
920 if ( command[commj].isparsed & source && (command[commj].flags & CMLT) == 0) {
921 sprintf(errbuffer,
922 "Directive '%s' appears more than once in the file", searchstr);
923 store_error_message(errbuffer);
924 return 1;
925 }
926 else {
927 command[commj].isparsed |= source;
928 }
929
930 /* Check that commands found on the list have the correct */
931 /* number of tokens on the line. */
932 if ( (tokc + 1) < command[commj].mintoken ) {
933 store_error_message("Too few items on line.");
934 return 1;
935 }
936 else if ( (command[commj].maxtoken != -1) && ((tokc + 1) > command[commj].maxtoken) ) {
937 store_error_message("Too many items on line.");
938 return 1;
939 }
940
941 errors = 0;
942 switch ( switchval ) {
943 case Ignored :
944 sprintf(errbuffer,
945 "Directive %s is obsolete and is being ignored.", searchstr);
946 store_error_message(errbuffer);
947 break;
948
949 case Mode :
950 (void) strupper(tokv[0]);
951 if ( !strcmp(tokv[0], "COMPATIBLE") )
952 configp->mode = COMPATIBLE;
953 else if ( !strcmp(tokv[0], "HEYU") )
954 configp->mode = HEYU_MODE;
955 else {
956 store_error_message("MODE must be COMPATIBLE or HEYU");
957 errors++;
958 }
959 break;
960
961 case OldAlias : /* Possible alias, else invalid command */
962 /* Check if it matches the form of an alias */
963 if ( tokc != 2 || strlen(tokv[0]) != 1 ||
964 (hc = toupper((int)(*tokv[0]))) < 'A' || hc > 'P' ) {
965 store_error_message("Invalid Directive.");
966 errors++;
967 break;
968 }
969 if ( !is_valid_alias_label(directive, &sp) ) {
970 sprintf(errbuffer, "Invalid character '%c' in alias label.", *sp);
971 store_error_message(errbuffer);
972 errors++;
973 break;
974 }
975
976 if ( strcmp(tokv[0], "macro") == 0 ) {
977 store_error_message("An alias label may not be the word \"macro\".");
978 errors++;
979 break;
980 }
981
982 if ( strchr("_-", *directive ) ) {
983 store_error_message("Alias labels may not begin with '_' or '-'");
984 errors++;
985 break;
986 }
987
988 if ( add_alias(&configp->aliasp, directive, line_no,
989 hc, tokv[1], -1) < 0 ) {
990 errors++;
991 }
992 break;
993
994 case Alias : /* New alias format using ALIAS directive */
995 /* Expects housecode and unit code(s) to be concatenated, */
996 /* the same as they are for the command line or macro. */
997
998 if ( !is_valid_alias_label(tokv[0], &sp) ) {
999 sprintf(errbuffer, "Invalid character '%c' in alias label.", *sp);
1000 store_error_message(errbuffer);
1001 errors++;
1002 break;
1003 }
1004
1005 if ( strcmp(tokv[0], "macro") == 0 ) {
1006 store_error_message("An alias label may not be the word \"macro\".");
1007 errors++;
1008 break;
1009 }
1010
1011 if ( strchr("_-", *tokv[0] ) ) {
1012 store_error_message("Alias labels may not begin with '_' or '-'");
1013 errors++;
1014 break;
1015 }
1016
1017 hc = toupper((int)(*tokv[1]));
1018 *tokv[1] = ' ';
1019 strtrim(tokv[1]);
1020
1021 modtype = -1;
1022 if ( tokc > 2 ) {
1023 if ( (modtype = lookup_module_type(tokv[2])) < 0 ) {
1024 sprintf(errbuffer, "Invalid module model '%s'", tokv[2]);
1025 store_error_message(errbuffer);
1026 errors++;
1027 break;
1028 }
1029 }
1030
1031 if ( (j = add_alias(&configp->aliasp, tokv[0], line_no,
1032 hc, tokv[1], modtype)) < 0 ) {
1033 errors++;
1034 break;
1035 }
1036
1037 if ( modtype >= 0 && tokc >= 3 ) {
1038 if ( add_module_options(configp->aliasp, j, tokv + 3, tokc - 3) != 0 ) {
1039 errors++;
1040 break;
1041 }
1042 }
1043
1044 break;
1045
1046 case UserSyn :
1047 get_token(label, &bufp, " \t", sizeof(label)/sizeof(char));
1048 if ( add_scene(&configp->scenep, label, line_no, bufp, F_USYN) < 0 ) {
1049 errors++;
1050 }
1051 break;
1052
1053 case Scene :
1054 get_token(label, &bufp, " \t", sizeof(label)/sizeof(char));
1055 if ( add_scene(&configp->scenep, label, line_no, bufp, F_SCENE) < 0 ) {
1056 errors++;
1057 }
1058 break;
1059
1060 case AsIfDate :
1061 configp->asif_date = strtol(tokv[0], &sp, 10);
1062 if ( !strchr(" \t\n", *sp) ||
1063 configp->asif_date < 19700101 ||
1064 configp->asif_date > 20380101 ) {
1065 store_error_message("ASIF_DATE must be yyyymmdd between 19700101 and 20380101");
1066 errors++;
1067 }
1068 break;
1069
1070 case AsIfTime :
1071 num = sscanf(tokv[0], "%d:%d", &hour, &minut) ;
1072 value = 60 * hour + minut ;
1073 configp->asif_time = value;
1074 if ( num != 2 || value < 0 || value > 1439 ) {
1075 store_error_message("ASIF_TIME must be hh:mm between 00:00-23:59");
1076 errors++;
1077 }
1078 break;
1079
1080 case ScheduleFile :
1081 strncpy2(configp->schedfile, tokv[0], sizeof(config.schedfile) - 1);
1082 break;
1083
1084 case ProgramDays :
1085 strupper(tokv[0]);
1086 configp->program_days_in = (int)strtol(tokv[0], &sp, 10);
1087
1088 if ( !strchr(" \t\n", *sp) ||
1089 configp->program_days_in < 1 ||
1090 configp->program_days_in > 366 ) {
1091 store_error_message("PROGRAM_DAYS outside range 1-366");
1092 errors++;
1093 }
1094 break;
1095
1096 case CombineEvents :
1097 strupper(tokv[0]);
1098 if ( !strcmp(tokv[0], "YES") )
1099 configp->combine_events = YES;
1100 else if ( !strcmp(tokv[0], "NO") )
1101 configp->combine_events = NO;
1102 else {
1103 store_error_message("COMBINE_EVENTS must be YES or NO");
1104 errors++;
1105 }
1106 break;
1107
1108 case CompressMacros :
1109 (void) strupper(tokv[0]);
1110 if ( !strcmp(tokv[0], "YES") )
1111 configp->compress_macros = YES;
1112 else if ( !strcmp(tokv[0], "NO") )
1113 configp->compress_macros = NO;
1114 else {
1115 store_error_message("COMPRESS_MACROS must be YES or NO");
1116 errors++;
1117 }
1118 break;
1119
1120 case FebKluge :
1121 (void) strupper(tokv[0]);
1122 if ( !strcmp(tokv[0], "YES") )
1123 configp->feb_kluge = YES;
1124 else if ( !strcmp(tokv[0], "NO") )
1125 configp->feb_kluge = NO;
1126 else {
1127 store_error_message("FEB_KLUGE must be YES or NO");
1128 errors++;
1129 }
1130 break;
1131
1132 case Latitude :
1133 errors += parse_latitude(tokv[0]);
1134 break;
1135
1136 case Longitude :
1137 errors += parse_longitude(tokv[0]);
1138 break;
1139
1140 case DawnOption :
1141 (void) strupper(tokv[0]);
1142 for ( j = 0; j < nddopt; j++ ) {
1143 if ( !strcmp(tokv[0], dd_option[j].label) )
1144 break;
1145 }
1146 if ( j == nddopt ) {
1147 store_error_message("Invalid DAWN_OPTION");
1148 errors++;
1149 break;
1150 }
1151 configp->dawn_option = dd_option[j].value;
1152 break;
1153
1154 case DuskOption :
1155 (void) strupper(tokv[0]);
1156 for ( j = 0; j < nddopt; j++ ) {
1157 if ( !strcmp(tokv[0], dd_option[j].label) )
1158 break;
1159 }
1160 if ( j == nddopt ) {
1161 store_error_message("Invalid DUSK_OPTION");
1162 errors++;
1163 break;
1164 }
1165 configp->dusk_option = dd_option[j].value;
1166 break;
1167
1168 case DawnSubstitute :
1169 num = sscanf(tokv[0], "%d:%d", &hour, &minut) ;
1170 value = 60 * hour + minut ;
1171 if ( num != 2 || value < 0 || value > 1439 ) {
1172 store_error_message("DAWN_SUBSTITUTE - must be 00:00-23:59 (hh:mm)");
1173 errors++;
1174 break;
1175 }
1176 configp->dawn_substitute = value;
1177 break;
1178
1179 case DuskSubstitute :
1180 num = sscanf(tokv[0], "%d:%d", &hour, &minut) ;
1181 value = 60 * hour + minut ;
1182 if ( num != 2 || value < 0 || value > 1439 ) {
1183 store_error_message("DUSK_SUBSTITUTE must be 00:00-23:59 (hh:mm)");
1184 errors++;
1185 break;
1186 }
1187 configp->dusk_substitute = value;
1188 break;
1189
1190 case MinDawn :
1191 if ( strcmp(strupper(tokv[0]), "OFF") == 0 ) {
1192 configp->min_dawn = OFF;
1193 break;
1194 }
1195 num = sscanf(tokv[0], "%d:%d", &hour, &minut);
1196 value = 60 * hour + minut ;
1197 if ( num != 2 || value < 0 || value > 1439 ) {
1198 store_error_message("MIN_DAWN must be 00:00-23:59 (hh:mm) or OFF");
1199 errors++;
1200 break;
1201 }
1202 configp->min_dawn = value;
1203 break;
1204
1205 case MaxDawn :
1206 if ( strcmp( strupper(tokv[0]), "OFF") == 0 ) {
1207 configp->max_dawn = OFF;
1208 break;
1209 }
1210 num = sscanf(tokv[0], "%d:%d", &hour, &minut);
1211 value = 60 * hour + minut ;
1212 if ( num != 2 || value < 0 || value > 1439 ) {
1213 store_error_message("MAX_DAWN must be 00:00-23:59 (hh:mm) or OFF");
1214 errors++;
1215 break;
1216 }
1217 configp->max_dawn = value;
1218 break;
1219
1220 case MinDusk :
1221 if ( strcmp( strupper(tokv[0]), "OFF") == 0 ) {
1222 configp->min_dusk = OFF;
1223 break;
1224 }
1225 num = sscanf(tokv[0], "%d:%d", &hour, &minut);
1226 value = 60 * hour + minut ;
1227 if ( num != 2 || value < 0 || value > 1439 ) {
1228 store_error_message("MIN_DUSK must be 00:00-23:59 (hh:mm) or OFF");
1229 errors++;
1230 break;
1231 }
1232 configp->min_dusk = value;
1233 break;
1234
1235 case MaxDusk :
1236 if ( strcmp( strupper(tokv[0]), "OFF") == 0 ) {
1237 configp->max_dusk = OFF;
1238 break;
1239 }
1240 num = sscanf(tokv[0], "%d:%d", &hour, &minut);
1241 value = 60 * hour + minut ;
1242 if ( num != 2 || value < 0 || value > 1439 ) {
1243 store_error_message("MAX_DUSK must be 00:00-23:59 (hh:mm) or OFF");
1244 errors++;
1245 break;
1246 }
1247 configp->max_dusk = value;
1248 break;
1249
1250 case Tty :
1251 (void) strncpy2(configp->tty, tokv[0], sizeof(config.tty) - 1);
1252
1253 for ( j = 1; j < tokc; j++) {
1254 strupper(tokv[j]);
1255 if ( strncmp(tokv[j], "CM10A", 4) == 0 ) {
1256 configp->device_type |= DEV_CM10A;
1257 }
1258 else if ( strncmp(tokv[j], "CM17A", 4) == 0 ) {
1259 configp->device_type |= DEV_CM17A;
1260 }
1261 else if ( !(strncmp(tokv[j], "CM11A", 4) == 0 ||
1262 strncmp(tokv[j], "CM12U", 4) == 0) ) {
1263 sprintf(errbuffer, "Unsupported interface type '%s'", tokv[j]);
1264 store_error_message(errbuffer);
1265 errors++;
1266 break;
1267 }
1268 }
1269 break;
1270
1271 case TtyAux :
1272 (void) strncpy2(configp->ttyaux, tokv[0], sizeof(config.ttyaux) - 1);
1273
1274 strupper(tokv[1]);
1275 if ( strncmp(tokv[1], "W800RF32", 8) == 0 ) {
1276 configp->auxdev = DEV_W800RF32;
1277 }
1278 else if ( strncmp(tokv[1], "MR26A", 4) == 0 ) {
1279 configp->auxdev = DEV_MR26A;
1280 }
1281 else if ( strcmp(tokv[1], "RFXCOM32") == 0 ) {
1282 configp->auxdev = DEV_RFXCOM32;
1283 }
1284 else if ( strcmp(tokv[1], "RFXCOM") == 0 ) {
1285 configp->auxdev = DEF_DEV_RFXCOM;
1286 }
1287 else if ( strcmp(tokv[1], "RFXCOMVL") == 0 ) {
1288 configp->auxdev = DEV_RFXCOMVL;
1289 }
1290 else {
1291 sprintf(errbuffer, "Unsupported aux device '%s'", tokv[1]);
1292 store_error_message(errbuffer);
1293 errors++;
1294 break;
1295 }
1296
1297 if ( ( configp->auxdev == DEV_RFXCOM32 || configp->auxdev == DEV_RFXCOMVL ) && *configp->ttyaux != '/' ) {
1298 sp = strchr(tokv[0], ':');
1299
1300 if ( sp ) {
1301 j = sp++ - tokv[0];
1302 if ( j > sizeof(config.auxhost) - 1 )
1303 j = sizeof(config.auxhost) - 1;
1304
1305 (void) strncpy2(configp->auxhost, tokv[0], j);
1306 (void) strncpy2(configp->auxport, sp, sizeof(config.auxport) - 1);
1307 }
1308 }
1309
1310 if ( configp->auxdev == DEV_RFXCOMVL && tokc > 2 ) {
1311 strupper(tokv[2]);
1312 if ( strcmp(tokv[2], "VISONIC") == 0 )
1313 configp->rfx_master = VISONIC;
1314 else if ( strcmp(tokv[2], "X10") == 0 )
1315 configp->rfx_master = RFXX10;
1316 else {
1317 sprintf(errbuffer, "Invalid RFXCOM receiver type '%s'", tokv[2]);
1318 store_error_message(errbuffer);
1319 errors++;
1320 break;
1321 }
1322 if ( tokc > 3 ) {
1323 strupper(tokv[3]);
1324 if ( strcmp(tokv[3], "VISONIC") == 0 )
1325 configp->rfx_slave = VISONIC;
1326 else if ( strcmp(tokv[3], "X10") == 0 )
1327 configp->rfx_slave = RFXX10;
1328 else {
1329 sprintf(errbuffer, "Invalid RFXCOM receiver type '%s'", tokv[3]);
1330 store_error_message(errbuffer);
1331 errors++;
1332 break;
1333 }
1334 }
1335 }
1336
1337 break;
1338
1339 case TtyRFXmit :
1340 strncpy2(configp->ttyrfxmit, tokv[0], sizeof(config.ttyrfxmit) - 1);
1341 if ( strncmp(tokv[1], "310", 3) == 0 )
1342 configp->rfxmit_freq = MHZ310;
1343 else if ( strncmp(tokv[1], "433", 3) == 0 )
1344 configp->rfxmit_freq = MHZ433;
1345 else {
1346 store_error_message("TTY_RFXMIT frequency parameter must be 310 or 433");
1347 errors++;
1348 break;
1349 }
1350
1351 break;
1352
1353 case HouseCode : /* Base housecode */
1354 hc = toupper((int)(*tokv[0]));
1355 if ( (int)strlen(tokv[0]) > 1 || hc < 'A' || hc > 'Z' ) {
1356 store_error_message("Invalid HOUSECODE - must be A though P");
1357 errors++;
1358 break;
1359 }
1360 configp->housecode = hc;
1361 default_housecode = hc;
1362 break;
1363
1364 case ForceAddr :
1365 (void) strupper(tokv[0]);
1366 if ( !strcmp(tokv[0], "YES") )
1367 configp->force_addr = YES;
1368 else if ( !strcmp(tokv[0], "NO") )
1369 configp->force_addr = NO;
1370 else {
1371 store_error_message("FORCE_ADDR must be YES or NO");
1372 errors++;
1373 }
1374 break;
1375
1376 case NewFormat : /* New Format - allow for additional choices in future */
1377 if ( (tokc + 1) == 1 )
1378 configp->newformat = 1;
1379 else
1380 configp->newformat = (unsigned char)strtol(tokv[0], NULL, 10);
1381 break;
1382
1383 case CheckFiles :
1384 (void) strupper(tokv[0]);
1385 if ( !strcmp(tokv[0], "YES") )
1386 configp->checkfiles = YES;
1387 else if ( !strcmp(tokv[0], "NO") )
1388 configp->checkfiles = NO;
1389 else {
1390 store_error_message("WRITE_CHECK_FILES must be YES or NO");
1391 errors++;
1392 }
1393 break;
1394
1395 case ReportPath : /* Alternate path for report files */
1396 (void)strncpy2(alt_path, tokv[0], sizeof(alt_path) - 1);
1397 if ( alt_path[strlen(alt_path) - 1] != '/' )
1398 (void)strncat(alt_path, "/", sizeof(alt_path) - 1 - strlen(alt_path));
1399 break;
1400
1401 case ReplDelay :
1402 (void) strupper(tokv[0]);
1403 if ( !strcmp(tokv[0], "YES") )
1404 configp->repl_delay = YES;
1405 else if ( !strcmp(tokv[0], "NO") )
1406 configp->repl_delay = NO;
1407 else {
1408 store_error_message("REPL_DELAYED_MACROS must be YES or NO");
1409 errors++;
1410 }
1411 break;
1412
1413 case ResvTimers :
1414 (void) strupper(tokv[0]);
1415 configp->reserved_timers = (int)strtol(tokv[0], &sp, 10);
1416
1417 if ( !strchr(" \t\n", *sp) ||
1418 configp->reserved_timers < 0 || configp->reserved_timers > 50 ) {
1419 store_error_message("RESERVED_TIMERS outside range 0-50");
1420 errors++;
1421 }
1422 break;
1423
1424 case TrigTag :
1425 (void) strupper(tokv[0]);
1426 if ( !strcmp(tokv[0], "YES") )
1427 configp->trigger_tag = YES;
1428 else if ( !strcmp(tokv[0], "NO") )
1429 configp->trigger_tag = NO;
1430 else {
1431 store_error_message("TRIGGER_TAG must be YES or NO");
1432 errors++;
1433 }
1434 break;
1435
1436 case MaxPParms :
1437 (void) strupper(tokv[0]);
1438 configp->max_pparms = (int)strtol(tokv[0], &sp, 10);
1439
1440 if ( !strchr(" \t\n", *sp) ||
1441 configp->max_pparms < 1 || configp->max_pparms > 999 ) {
1442 store_error_message("MAX_PPARMS outside range 1-999");
1443 errors++;
1444 }
1445 break;
1446
1447 case RcsTemp :
1448 /* Housecodes for which Preset commands received from */
1449 /* thermostats are to be decoded into temperature. */
1450 /* Information is stored as a housecode bitmap. */
1451 sp = tokv[0];
1452 (void) strlower(sp);
1453 configp->rcs_temperature = 0;
1454 if ( !strcmp(sp, "off") || !strcmp(sp, "none") ) {
1455 break;
1456 }
1457 if ( !strcmp(sp, "all") || !strcmp(sp, "yes") ) {
1458 configp->rcs_temperature = 0xffff;
1459 break;
1460 }
1461
1462 len = strlen(sp);
1463 if ( *sp == '[' && *(sp + len - 1) == ']' ) {
1464 /* Create the housecode bitmap */
1465 for ( j = 1; j < len - 1; j++ ) {
1466 /* Ignore spaces and commas */
1467 if ( sp[j] == ' ' || sp[j] == ',' )
1468 continue;
1469 if ( sp[j] < 'a' || sp[j] > 'p' )
1470 break;
1471 configp->rcs_temperature |= (1 << hc2code(sp[j]));
1472 }
1473 if ( j != len - 1 ) {
1474 store_error_message("Invalid character in RCS_DECODE housecode list");
1475 errors++;
1476 break;
1477 }
1478 break;
1479 }
1480 store_error_message("RCS_DECODE must be OFF or [<housecode list>] or ALL");
1481 errors++;
1482 break;
1483
1484 case TransMissp :
1485 store_error_message("TRANSCEIVE misspelled");
1486 case Transceive :
1487 value = 0;
1488 /* Housecodes to be transceived by the aux daemon */
1489 sp = tokv[0];
1490 (void) strlower(sp);
1491 if ( !strcmp(sp, "all") ) {
1492 configp->transceive = TR_ALL;
1493 break;
1494 }
1495
1496 if ( !strcmp(sp, "none") ) {
1497 configp->transceive = TR_NONE;
1498 break;
1499 }
1500
1501 if ( !strcmp(sp, "allexcept") ) {
1502 if ( tokc < 2 ) {
1503 store_error_message("Too few parameters for TRANSCEIVE ALLEXCEPT");
1504 errors++;
1505 break;
1506 }
1507 sp = tokv[1];
1508 strlower(sp);
1509 value = 1;
1510 }
1511
1512 len = strlen(sp);
1513 if ( *sp == '[' && *(sp + len - 1) == ']' ) {
1514 /* Create the housecode bitmap */
1515 configp->transceive = 0;
1516 for ( j = 1; j < len - 1; j++ ) {
1517 /* Ignore periods and commas */
1518 if ( sp[j] == '.' || sp[j] == ',' )
1519 continue;
1520 if ( sp[j] < 'a' || sp[j] > 'p' ) {
1521 store_error_message("Invalid character in TRANSCEIVE housecode list");
1522 errors++;
1523 break;
1524 }
1525 configp->transceive |= (1 << hc2code(sp[j]));
1526 }
1527 if ( value == 1 )
1528 configp->transceive = 0xffff & ~configp->transceive;
1529
1530 break;
1531 }
1532 store_error_message("TRANSCEIVE must be ALL or NONE or ALLEXCEPT [<housecode list>]");
1533 errors++;
1534 break;
1535
1536 case RFForward :
1537 value = 0;
1538 /* Housecodes to be transceived by the aux daemon */
1539 sp = tokv[0];
1540 (void) strlower(sp);
1541 if ( !strcmp(sp, "all") ) {
1542 configp->rfforward = TR_ALL;
1543 break;
1544 }
1545
1546 if ( !strcmp(sp, "none") ) {
1547 configp->rfforward = TR_NONE;
1548 break;
1549 }
1550
1551 if ( !strcmp(sp, "allexcept") ) {
1552 if ( tokc < 2 ) {
1553 store_error_message("Too few parameters for RFFORWARD ALLEXCEPT");
1554 errors++;
1555 break;
1556 }
1557 sp = tokv[1];
1558 strlower(sp);
1559 value = 1;
1560 }
1561
1562 len = strlen(sp);
1563 if ( *sp == '[' && *(sp + len - 1) == ']' ) {
1564 /* Create the housecode bitmap */
1565 configp->rfforward = 0;
1566 for ( j = 1; j < len - 1; j++ ) {
1567 /* Ignore periods and commas */
1568 if ( sp[j] == '.' || sp[j] == ',' )
1569 continue;
1570 if ( sp[j] < 'a' || sp[j] > 'p' ) {
1571 store_error_message("Invalid character in RFFORWARD housecode list");
1572 errors++;
1573 break;
1574 }
1575 configp->rfforward |= (1 << hc2code(sp[j]));
1576 }
1577 if ( value == 1 )
1578 configp->rfforward = 0xffff & ~configp->rfforward;
1579
1580 break;
1581 }
1582 store_error_message("RFFORWARD must be ALL or NONE or ALLEXCEPT [<housecode list>]");
1583 errors++;
1584 break;
1585
1586
1587 case TransDim :
1588 configp->trans_dim = (unsigned char)strtol(tokv[0], &sp, 10);
1589
1590 if ( !strchr(" \t\n", *sp) ||
1591 configp->trans_dim < 1 || configp->trans_dim > 22 ) {
1592 store_error_message("TRANS_DIMLEVEL outside range 1-22");
1593 errors++;
1594 }
1595 break;
1596
1597 case StatusTimeout :
1598 configp->status_timeout = (int)strtol(tokv[0], &sp, 10);
1599
1600 if ( !strchr(" \t\n", *sp) ||
1601 configp->status_timeout < 1 || configp->status_timeout > 5 ) {
1602 store_error_message("STATUS_TIMEOUT outside range 1-5");
1603 errors++;
1604 }
1605 break;
1606
1607
1608 case SpfTimeout :
1609 configp->spf_timeout = (int)strtol(tokv[0], &sp, 10);
1610
1611 if ( !strchr(" \t\n", *sp) ||
1612 configp->spf_timeout < 1 || configp->spf_timeout > 10 ) {
1613 store_error_message("SPF_TIMEOUT outside range 1-10");
1614 errors++;
1615 }
1616 break;
1617
1618 case XrefApp :
1619 (void) strupper(tokv[0]);
1620 if ( !strcmp(tokv[0], "YES") )
1621 configp->xref_append = YES;
1622 else if ( !strcmp(tokv[0], "NO") )
1623 configp->xref_append = NO;
1624 else {
1625 store_error_message("XREF_APPEND must be YES or NO");
1626 errors++;
1627 }
1628 break;
1629
1630 case AckHails :
1631 (void) strupper(tokv[0]);
1632 if ( !strcmp(tokv[0], "YES") )
1633 configp->ack_hails = YES;
1634 else if ( !strcmp(tokv[0], "NO") )
1635 configp->ack_hails = NO;
1636 else {
1637 store_error_message("ACK_HAILS must be YES or NO");
1638 errors++;
1639 }
1640 break;
1641
1642 case DispExpMac :
1643 (void) strupper(tokv[0]);
1644 if ( !strcmp(tokv[0], "YES") )
1645 configp->disp_exp_mac = YES;
1646 else if ( !strcmp(tokv[0], "NO") )
1647 configp->disp_exp_mac = NO;
1648 else {
1649 store_error_message("DISPLAY_EXP_MACROS must be YES or NO");
1650 errors++;
1651 }
1652 break;
1653
1654 case MacTerm :
1655 (void) strupper(tokv[0]);
1656 if ( !strcmp(tokv[0], "YES") )
1657 configp->macterm = YES;
1658 else if ( !strcmp(tokv[0], "NO") )
1659 configp->macterm = NO;
1660 else {
1661 store_error_message("MACTERM must be YES or NO");
1662 errors++;
1663 }
1664 break;
1665
1666 case AutoChain :
1667 (void) strupper(tokv[0]);
1668 if ( !strcmp(tokv[0], "YES") )
1669 configp->auto_chain = YES;
1670 else if ( !strcmp(tokv[0], "NO") )
1671 configp->auto_chain = NO;
1672 else {
1673 store_error_message("AUTO_CHAIN must be YES or NO");
1674 errors++;
1675 }
1676 break;
1677
1678 case Launcher :
1679 if ( add_launchers(&configp->launcherp, line_no, bufp) < 0 )
1680 errors++;
1681 break;
1682
1683 case Script :
1684 if ( add_script(&configp->scriptp, &configp->launcherp, line_no, bufp) < 0 )
1685 errors++;
1686 break;
1687
1688 case ModuleTypes :
1689 (void) strupper(tokv[0]);
1690 if ( !strcmp(tokv[0], "YES") )
1691 configp->module_types = YES;
1692 else if ( !strcmp(tokv[0], "NO") )
1693 configp->module_types = NO;
1694 else {
1695 store_error_message("MODULE_TYPES must be YES or NO");
1696 errors++;
1697 }
1698 break;
1699
1700 case FunctionMode :
1701 (void) strupper(tokv[0]);
1702 if ( !strcmp(tokv[0], "ACTUAL") )
1703 configp->function_mode = FUNC_ACTUAL;
1704 else if ( !strcmp(tokv[0], "GENERIC") )
1705 configp->function_mode = FUNC_GENERIC;
1706 else {
1707 store_error_message("FUNCTION_MODE must be ACTUAL or GENERIC");
1708 errors++;
1709 }
1710 break;
1711
1712 case LaunchMode :
1713 (void) strupper(tokv[0]);
1714 if ( !strcmp(tokv[0], "SIGNAL") )
1715 configp->launch_mode = TMODE_SIGNAL;
1716 else if ( !strcmp(tokv[0], "MODULE") )
1717 configp->launch_mode = TMODE_MODULE;
1718 else {
1719 store_error_message("LAUNCH_MODE must be SIGNAL or MODULE");
1720 errors++;
1721 }
1722 break;
1723
1724 case LaunchSrc :
1725 value = 0;
1726 for ( j = 0; j < tokc; j++ ) {
1727 strncpy2(token, tokv[j], sizeof(token));
1728 strupper(token);
1729 if ( strcmp(token, "SNDS") == 0 ) {
1730 sprintf(errbuffer, "LAUNCH_SOURCE '%s' not allowed as a default.", tokv[j]);
1731 store_error_message(errbuffer);
1732 errors++;
1733 break;
1734 }
1735 for ( k = 0; k < nlsopt; k++ ) {
1736 if ( strcmp(token, ls_option[k].label) == 0 ) {
1737 value |= ls_option[k].value;
1738 break;
1739 }
1740 }
1741 if ( k >= nlsopt ) {
1742 sprintf(errbuffer, "Invalid LAUNCH_SOURCE option '%s'", tokv[j]);
1743 store_error_message(errbuffer);
1744 errors++;
1745 break;
1746 }
1747 }
1748 if ( value & LSNONE ) {
1749 if ( value & ~LSNONE )
1750 store_error_message("Warning: LAUNCH_SOURCE 'nosrc' cancels all others on line.");
1751 configp->launch_source = 0;
1752 }
1753 else
1754 configp->launch_source = (unsigned int)value;
1755 break;
1756
1757 case ResOverlap :
1758 (void) strupper(tokv[0]);
1759 if ( !strcmp(tokv[0], "OLD") )
1760 configp->res_overlap = RES_OVLAP_COMBINED;
1761 else if ( !strcmp(tokv[0], "NEW") )
1762 configp->res_overlap = RES_OVLAP_SEPARATE;
1763 else {
1764 store_error_message("RESOLVE_OVERLAP must be OLD or NEW");
1765 errors++;
1766 }
1767 break;
1768
1769 case DefaultModule :
1770 if ( (configp->default_module = lookup_module_type(tokv[0])) < 0 ) {
1771 sprintf(errbuffer, "Module type '%s' is unknown.", tokv[0]);
1772 store_error_message(errbuffer);
1773 errors++;
1774 }
1775 break;
1776
1777 case ScriptShell :
1778 if ( access(tokv[0], X_OK) == 0 ) {
1779 strncpy2(configp->script_shell, tokv[0], sizeof(config.script_shell) - 1);
1780 }
1781 else {
1782 sprintf(errbuffer,
1783 "An executable shell '%s' is not found.", tokv[0]);
1784 store_error_message(errbuffer);
1785 errors++;
1786 }
1787 break;
1788
1789 case ScriptMode :
1790 (void) strupper(tokv[0]);
1791 if ( !strcmp(tokv[0], "HEYUHELPER") )
1792 configp->script_mode = HEYU_HELPER;
1793 else if ( !strncmp(tokv[0], "SCRIPT", 6) )
1794 configp->script_mode = HEYU_SCRIPT;
1795 else {
1796 store_error_message("SCRIPT_MODE must be HEYUHELPER or SCRIPT");
1797 errors++;
1798 }
1799 break;
1800
1801 case LogDir :
1802 strncpy2(token, tokv[0], sizeof(token) - 1);
1803 strupper(token);
1804 if ( strcmp(token, "NONE") == 0 ) {
1805 *configp->logfile = '\0';
1806 break;
1807 }
1808
1809 strncpy2(token, tokv[0], sizeof(token) - 1);
1810 strcat(token, "/");
1811 if ( check_dir_rw(token, "LOG_DIR") != 0 ) {
1812 #if 0
1813 store_error_message(
1814 "LOG_DIR does not exist or is not writable.");
1815 #endif
1816 errors++;
1817 }
1818 else {
1819 sprintf(configp->logfile, "%s/%s",
1820 tokv[0], LOGFILE);
1821 }
1822
1823 if ( tokc == 2 ) {
1824 strncpy2(token, tokv[1], sizeof(token) - 1);
1825 strupper(token);
1826 if ( strcmp(token, "COMMON") == 0 ) {
1827 configp->logcommon = YES;
1828 }
1829 else {
1830 sprintf(errbuffer,
1831 "Token '%s' not recognized. Do you mean COMMON ?", tokv[1]);
1832 store_error_message(errbuffer);
1833 errors++;
1834 }
1835 }
1836
1837 break;
1838
1839 case DispSubdir :
1840 strupper(tokv[0]);
1841 if ( !strcmp(tokv[0], "YES") )
1842 configp->disp_subdir = YES;
1843 else if ( !strcmp(tokv[0], "NO") )
1844 configp->disp_subdir = NO;
1845 else {
1846 store_error_message("DISPLAY_SUBDIR must be YES or NO");
1847 errors++;
1848 }
1849 break;
1850
1851
1852 case IsDarkOffset :
1853 configp->isdark_offset = (int)strtol(tokv[0], &sp, 10);
1854
1855 if ( !strchr(" \t\n", *sp) ||
1856 configp->isdark_offset < -360 || configp->isdark_offset > 360 ) {
1857 store_error_message("ISDARK_OFFSET outside range +/-360 minutes");
1858 errors++;
1859 }
1860 break;
1861
1862 case EnvAliasPrefix :
1863 strupper(tokv[0]);
1864 if ( strcmp(tokv[0], "UC") == 0 )
1865 strncpy2(configp->env_alias_prefix, "X10", sizeof(config.env_alias_prefix) - 1);
1866 else if ( strcmp(tokv[0], "LC") == 0 )
1867 strncpy2(configp->env_alias_prefix, "x10", sizeof(config.env_alias_prefix) - 1);
1868 else {
1869 store_error_message("ENV_ALIAS_PREFIX must be UC or LC");
1870 errors++;
1871 }
1872 break;
1873
1874 case SunMode :
1875 strupper(tokv[0]);
1876 if ( tokc == 1 ) {
1877 if ( strncmp(tokv[0], "RISESET", 1) == 0 ) {
1878 configp->sunmode = RiseSet;
1879 break;
1880 }
1881 else if ( strncmp(tokv[0], "CIVILTWI", 1) == 0 ) {
1882 configp->sunmode = CivilTwi;
1883 break;
1884 }
1885 else if ( strncmp(tokv[0], "NAUTTWI", 1) == 0 ) {
1886 configp->sunmode = NautTwi;
1887 break;
1888 }
1889 else if ( strncmp(tokv[0], "ASTROTWI", 1) == 0 ) {
1890 configp->sunmode = AstroTwi;
1891 break;
1892 }
1893 }
1894 else {
1895 sp = NULL;
1896 if ( strncmp(tokv[0], "OFFSET", 1) == 0 ) {
1897 configp->sunmode = AngleOffset;
1898 configp->sunmode_offset = (int)strtol(tokv[1], &sp, 10);
1899 }
1900 if ( sp && strchr(" \t\n", *sp) )
1901 break;
1902 }
1903 store_error_message("DAWNDUSK_DEF must be R, C, N, A or O <int>");
1904 errors++;
1905 break;
1906
1907 case Fix5A :
1908 (void) strupper(tokv[0]);
1909 if ( !strcmp(tokv[0], "YES") )
1910 configp->fix_5a = YES;
1911 else if ( !strcmp(tokv[0], "NO") )
1912 configp->fix_5a = NO;
1913 else {
1914 store_error_message("FIX_5A must be YES or NO");
1915 errors++;
1916 }
1917 break;
1918
1919 case CM11PostDelay :
1920 configp->cm11_post_delay = (int)strtol(tokv[0], &sp, 10);
1921 if ( !strchr(" \t\n", *sp) ||
1922 configp->cm11_post_delay < 0 ||
1923 configp->cm11_post_delay > 1000 ) {
1924 store_error_message("CM11_POST_DELAY must be 0-1000");
1925 errors++;
1926 }
1927 break;
1928
1929 case AutoFetch :
1930 (void) strupper(tokv[0]);
1931 if ( !strcmp(tokv[0], "YES") )
1932 configp->autofetch = YES;
1933 else if ( !strcmp(tokv[0], "NO") )
1934 configp->autofetch = NO;
1935 else {
1936 store_error_message("AUTOFETCH must be YES or NO");
1937 errors++;
1938 }
1939 break;
1940
1941 case PfailUpdate :
1942 (void) strupper(tokv[0]);
1943 if ( !strcmp(tokv[0], "YES") )
1944 configp->pfail_update = YES;
1945 else if ( !strcmp(tokv[0], "NO") )
1946 configp->pfail_update = NO;
1947 else {
1948 store_error_message("POWERFAIL_UPDATE must be YES or NO");
1949 errors++;
1950 }
1951 break;
1952
1953 case BitDelay :
1954 configp->cm17a_bit_delay = (int)strtol(tokv[0], &sp, 10);
1955 if ( !strchr(" \t\n", *sp) ||
1956 configp->cm17a_bit_delay < 100 ||
1957 configp->cm17a_bit_delay > 10000 ) {
1958 store_error_message("CM17A_BIT_DELAY must be 100-10000");
1959 errors++;
1960 }
1961 break;
1962
1963 case BurstSpacing :
1964 configp->rf_burst_spacing = (int)strtol(tokv[0], &sp, 10);
1965 if ( !strchr(" \t\n", *sp) ||
1966 configp->rf_burst_spacing < 80 ||
1967 configp->rf_burst_spacing > 160 ) {
1968 store_error_message("RF_BURST_SPACING must be 80-160");
1969 errors++;
1970 }
1971 break;
1972
1973 case TimerTweak :
1974 configp->rf_timer_tweak = (int)strtol(tokv[0], &sp, 10);
1975 if ( !strchr(" \t\n", *sp) ||
1976 configp->rf_timer_tweak < 0 ||
1977 configp->rf_timer_tweak > 50 ) {
1978 store_error_message("RF_TIMER_TWEAK must be 0-50");
1979 errors++;
1980 }
1981 break;
1982
1983 case RFPostDelay :
1984 configp->rf_post_delay = (int)strtol(tokv[0], &sp, 10);
1985 if ( !strchr(" \t\n", *sp) ||
1986 configp->rf_post_delay < 0 ||
1987 configp->rf_post_delay > 10000 ) {
1988 store_error_message("RF_POST_DELAY must be 0-10000");
1989 errors++;
1990 }
1991 break;
1992
1993 case RFFarbDelay :
1994 configp->rf_farb_delay = (int)strtol(tokv[0], &sp, 10);
1995 if ( !strchr(" \t\n", *sp) ||
1996 configp->rf_farb_delay < 0 ||
1997 configp->rf_farb_delay > 10000 ) {
1998 store_error_message("RF_FARB_DELAY must be 0-10000");
1999 errors++;
2000 }
2001 break;
2002
2003 case RFFarwDelay :
2004 configp->rf_farw_delay = (int)strtol(tokv[0], &sp, 10);
2005 if ( !strchr(" \t\n", *sp) ||
2006 configp->rf_farw_delay < 0 ||
2007 configp->rf_farw_delay > 10000 ) {
2008 store_error_message("RF_FARW_DELAY must be 0-10000");
2009 errors++;
2010 }
2011 break;
2012
2013 case DispRFX :
2014 (void) strupper(tokv[0]);
2015 if ( !strcmp(tokv[0], "YES") )
2016 configp->disp_rf_xmit = YES;
2017 else if ( !strcmp(tokv[0], "NO") )
2018 configp->disp_rf_xmit = NO;
2019 else if ( !strcmp(tokv[0], "VERBOSE") )
2020 configp->disp_rf_xmit = VERBOSE;
2021 else {
2022 store_error_message("DISPLAY_RF_XMIT must be NO or YES or VERBOSE");
2023 errors++;
2024 }
2025 break;
2026
2027 case DefRFBursts :
2028 configp->def_rf_bursts = (int)strtol(tokv[0], &sp, 10);
2029 if ( !strchr(" \t\n", *sp) ||
2030 configp->def_rf_bursts < 5 ||
2031 configp->def_rf_bursts > 6 ) {
2032 store_error_message("DEF_RF_BURSTS must be 5 or 6");
2033 errors++;
2034 }
2035 break;
2036
2037 case RFBursts :
2038 if ( tokc % 2 ) {
2039 store_error_message("Missing RF_BURSTS parameter");
2040 errors++;
2041 break;
2042 }
2043
2044 for ( j = 0; j < tokc; j+=2 ) {
2045 bursts = strtol(tokv[j + 1], &sp, 10);
2046 if ( !strchr(" \t\r\n", *sp) || bursts < 1 ) {
2047 sprintf(errbuffer, "Invalid RF_BURSTS bursts '%s'", tokv[j + 1]);
2048 store_error_message(errbuffer);
2049 errors++;
2050 break;
2051 }
2052 strlower(tokv[j]);
2053 for ( k = 0; k < nrflabels; k++ ) {
2054 if ( !strcmp(tokv[j], rf_label[k].label) ) {
2055 configp->rf_bursts[rf_label[k].subcode] = bursts;
2056 break;
2057 }
2058 }
2059 if ( k >= nrflabels ) {
2060 sprintf(errbuffer, "Unknown CM17A function '%s'", tokv[j]);
2061 store_error_message(errbuffer);
2062 errors++;
2063 break;
2064 }
2065 }
2066
2067 break;
2068
2069 #if 0
2070 case RFBursts :
2071 bursts = strtol(tokv[1], &sp, 10);
2072 if ( !strchr(" \t\n", *sp) || bursts < 1 ) {
2073 store_error_message("Invalid RF_BURSTS");
2074 errors++;
2075 break;
2076 }
2077 (void) strlower(tokv[0]);
2078 for ( j = 0; j < nrflabels; j++ ) {
2079 if ( !strcmp(tokv[0], rf_label[j].label) ) {
2080 configp->rf_bursts[rf_label[j].subcode] = bursts;
2081 break;
2082 }
2083 }
2084 if ( j >= nrflabels ) {
2085 sprintf(errbuffer, "Unknown CM17A function '%s'", tokv[0]);
2086 store_error_message(errbuffer);
2087 errors++;
2088 }
2089 break;
2090 #endif
2091
2092 case LoopCount :
2093 configp->timer_loopcount = (unsigned long)strtol(tokv[0], &sp, 10);
2094 if ( !strchr(" \t\n", *sp) ) {
2095 store_error_message("Invalid TIMER_LOOPCOUNT");
2096 errors++;
2097 break;
2098 }
2099 break;
2100
2101 case RestrictDims :
2102 (void) strupper(tokv[0]);
2103 if ( !strcmp(tokv[0], "YES") )
2104 configp->restrict_dims = YES;
2105 else if ( !strcmp(tokv[0], "NO") )
2106 configp->restrict_dims = NO;
2107 else {
2108 store_error_message("RESTRICT_DIMS must be YES or NO");
2109 errors++;
2110 }
2111 break;
2112
2113 case StateFmt :
2114 (void) strupper(tokv[0]);
2115 if ( !strcmp(tokv[0], "NEW") )
2116 configp->state_format = NEW;
2117 else if ( !strcmp(tokv[0], "OLD") )
2118 configp->state_format = OLD;
2119 else {
2120 store_error_message("STATE_FORMAT must be NEW or OLD");
2121 errors++;
2122 }
2123 break;
2124
2125 case PfailScript :
2126 if ( !(configp->pfail_script = strdup(bufp)) ) {
2127 store_error_message("Memory allocation error - out of memory");
2128 errors++;
2129 }
2130 break;
2131
2132 case StartEngine :
2133 (void) strupper(tokv[0]);
2134 if ( !strncmp(tokv[0], "MANUAL", 3) )
2135 configp->start_engine = MANUAL;
2136 else if ( !strncmp(tokv[0], "AUTOMATIC", 4) )
2137 configp->start_engine = AUTOMATIC;
2138 else {
2139 store_error_message("START_ENGINE must be MANUAL or AUTO");
2140 errors++;
2141 }
2142 break;
2143
2144 case IgnoreSilent :
2145 break;
2146
2147 case NoSwitch :
2148 (void) strupper(tokv[0]);
2149 if ( !strcmp(tokv[0], "YES") )
2150 configp->rf_noswitch = YES;
2151 else if ( !strcmp(tokv[0], "NO") )
2152 configp->rf_noswitch = NO;
2153 else {
2154 store_error_message("RF_NOSWITCH must be YES or NO");
2155 errors++;
2156 }
2157 break;
2158
2159 case RespoolPerms :
2160 #ifndef RESPOOL
2161 store_error_message(
2162 "The RESPOOL_PERMISSIONS directive is invalid for this operating system");
2163 errors++;
2164 break;
2165 #endif
2166 perms = (int)strtol(tokv[0], &sp, 8);
2167 if ( !strchr(" \t\n", *sp) || perms < 0 || perms > 07777) {
2168 store_error_message("RESPOOL_PERMISSIONS - invalid octal number");
2169 errors++;
2170 }
2171 configp->respool_perms = (unsigned int)perms;
2172 break;
2173
2174 case SpoolMax :
2175 configp->spool_max = strtol(tokv[0], &sp, 10);
2176 if ( !strchr(" \t\n", *sp) ||
2177 configp->spool_max < SPOOLFILE_ABSMIN ||
2178 configp->spool_max > SPOOLFILE_ABSMAX ) {
2179 sprintf(errbuffer, "SPOOLFILE_MAX must be between %ul and %ul",
2180 SPOOLFILE_ABSMIN, SPOOLFILE_ABSMAX);
2181 store_error_message(errbuffer);
2182 errors++;
2183 }
2184 break;
2185
2186 case CheckRILine :
2187 (void) strupper(tokv[0]);
2188 if ( !strcmp(tokv[0], "YES") )
2189 configp->check_RI_line = YES;
2190 else if ( !strcmp(tokv[0], "NO") )
2191 configp->check_RI_line = NO;
2192 else {
2193 store_error_message("CHECK_RI_LINE must be YES or NO");
2194 errors++;
2195 }
2196 break;
2197
2198 case RIdisable :
2199 (void) strupper(tokv[0]);
2200 if ( !strcmp(tokv[0], "YES") )
2201 store_error_message("Obsolete - use RING_CTRL DISABLE");
2202 else if ( !strcmp(tokv[0], "NO") )
2203 store_error_message("Obsolete - use RING_CTRL ENABLE");
2204 else {
2205 store_error_message("Obsolete - Use RING_CTRL ENABLE or DISABLE");
2206 }
2207 errors++;
2208 break;
2209
2210 case RingCtrl :
2211 (void) strupper(tokv[0]);
2212 if ( !strcmp(tokv[0], "ENABLE") )
2213 configp->ring_ctrl = ENABLE;
2214 else if ( !strcmp(tokv[0], "DISABLE") )
2215 configp->ring_ctrl = DISABLE;
2216 else {
2217 store_error_message("RING_CTRL must be ENABLE or DISABLE");
2218 errors++;
2219 }
2220 break;
2221
2222 case SendRetries :
2223 configp->send_retries = (int)strtol(tokv[0], &sp, 10);
2224 if ( !strchr(" \t\n", *sp) ||
2225 configp->send_retries < 0 ) {
2226 store_error_message("SEND_RETRIES must be > 0");
2227 errors++;
2228 }
2229 break;
2230
2231 case ScriptCtrl :
2232 (void) strupper(tokv[0]);
2233 if ( !strcmp(tokv[0], "ENABLE") )
2234 configp->script_ctrl = ENABLE;
2235 else if ( !strcmp(tokv[0], "DISABLE") )
2236 configp->script_ctrl = DISABLE;
2237 else {
2238 store_error_message("SCRIPT_CTRL must be ENABLE or DISABLE");
2239 errors++;
2240 }
2241 break;
2242
2243 case StateCtrl :
2244 (void) strupper(tokv[0]);
2245 if ( !strcmp(tokv[0], "SINGLE") )
2246 configp->state_ctrl = SC_SINGLE;
2247 else if ( !strcmp(tokv[0], "BITMAP") )
2248 configp->state_ctrl = SC_BITMAP;
2249 else {
2250 store_error_message("STATE_CTRL must be SINGLE or BITMAP");
2251 errors++;
2252 }
2253 break;
2254
2255 case RFFuncMask :
2256 store_error_message("RF_FUNCMASK not yet implemented");
2257 errors++;
2258 break;
2259
2260 case HideUnchg :
2261 (void) strupper(tokv[0]);
2262 if ( !strcmp(tokv[0], "YES") )
2263 configp->hide_unchanged = YES;
2264 else if ( !strcmp(tokv[0], "NO") )
2265 configp->hide_unchanged = NO;
2266 else {
2267 store_error_message("HIDE_UNCHANGED must be YES or NO");
2268 errors++;
2269 }
2270 break;
2271
2272 case HideUnchgInactive :
2273 (void) strupper(tokv[0]);
2274 if ( !strcmp(tokv[0], "YES") )
2275 configp->hide_unchanged_inactive = YES;
2276 else if ( !strcmp(tokv[0], "NO") )
2277 configp->hide_unchanged_inactive = NO;
2278 else {
2279 store_error_message("HIDE_UNCHANGED_INACTIVE must be YES or NO");
2280 errors++;
2281 }
2282 break;
2283
2284 case ShowChange :
2285 (void) strupper(tokv[0]);
2286 if ( !strcmp(tokv[0], "YES") )
2287 configp->show_change = YES;
2288 else if ( !strcmp(tokv[0], "NO") )
2289 configp->show_change = NO;
2290 else {
2291 store_error_message("SHOW_CHANGE must be YES or NO");
2292 errors++;
2293 }
2294 break;
2295
2296 case AuxRepcounts :
2297 for ( j = 0; j < 3; j++ ) {
2298 value = (int)strtol(tokv[j], &sp, 10);
2299 if ( strchr(" \t\n", *sp) == NULL || value < 0 ) {
2300 store_error_message("Invalid AUX_REPCOUNTS");
2301 errors++;
2302 break;
2303 }
2304 configp->aux_repcounts[j] = value;
2305 }
2306 if ( configp->aux_repcounts[0] < 1 ) {
2307 store_error_message("AUX_REPCOUNTS <min count> value must be greater than zero");
2308 errors++;
2309 break;
2310 }
2311 break;
2312
2313 case AuxMincountRFX :
2314 value = (int)strtol(tokv[0], &sp, 10);
2315 if ( strchr(" \t\n", *sp) == NULL || value < 1 || value > 3 ) {
2316 store_error_message("AUX_MINCOUNT_RFX out of range 1-3");
2317 errors++;
2318 break;
2319 }
2320 configp->aux_mincount_rfx = value;
2321 break;
2322
2323 case DispRFNoise :
2324 (void) strupper(tokv[0]);
2325 if ( !strcmp(tokv[0], "YES") )
2326 configp->disp_rf_noise = YES;
2327 else if ( !strcmp(tokv[0], "NO") )
2328 configp->disp_rf_noise = NO;
2329 else {
2330 store_error_message("DISPLAY_RF_NOISE must be YES or NO");
2331 errors++;
2332 }
2333 break;
2334
2335 case ArmMaxDelay :
2336 if ( (longvalue = parse_hhmmss(tokv[0], 3)) >= 0 && longvalue < 43200 ) {
2337 configp->arm_max_delay = (int)longvalue;
2338 }
2339 else {
2340 store_error_message("Invalid ARM_MAX_DELAY");
2341 errors++;
2342 }
2343 break;
2344
2345 case ArmLogic :
2346 strupper(tokv[0]);
2347 configp->arm_logic =
2348 (strcmp(tokv[0], "STRICT") == 0) ? ArmLogicStrict :
2349 (strcmp(tokv[0], "MEDIUM") == 0) ? ArmLogicMedium :
2350 (strcmp(tokv[0], "LOOSE") == 0) ? ArmLogicLoose : 0;
2351
2352 if ( configp->arm_logic == 0 ) {
2353 store_error_message("ARM_LOGIC must be STRICT, MEDIUM or LOOSE");
2354 errors++;
2355 }
2356 break;
2357
2358 case InactiveTimeout :
2359 if ( (longvalue = parse_hhmmss(tokv[0], 3)) >= 0 && longvalue < 86400 ) {
2360 configp->inactive_timeout = longvalue;
2361 }
2362 else {
2363 store_error_message("Invalid INACTIVE_TIMEOUT");
2364 errors++;
2365 }
2366 break;
2367
2368 case InactiveTimeoutOre :
2369 if ( (longvalue = parse_hhmmss(tokv[0], 3)) >= 0 && longvalue < 86400 ) {
2370 configp->inactive_timeout_ore = longvalue;
2371 }
2372 else {
2373 store_error_message("Invalid INACTIVE_TIMEOUT_ORE");
2374 errors++;
2375 }
2376 break;
2377
2378 case DispRawRF :
2379 (void) strupper(tokv[0]);
2380
2381 if ( !strcmp(tokv[0], "NONE") )
2382 configp->disp_raw_rf = DISPMODE_RF_NONE;
2383 else if ( !strcmp(tokv[0], "NOISE") )
2384 configp->disp_raw_rf = DISPMODE_RF_NOISE;
2385 else if ( !strcmp(tokv[0], "ALL") )
2386 configp->disp_raw_rf = (DISPMODE_RF_NORMAL | DISPMODE_RF_NOISE);
2387 else {
2388 store_error_message("DISPLAY_RAW_RF must be NONE or NOISE or ALL");
2389 errors++;
2390 }
2391 break;
2392
2393 case HeyuUmask :
2394 if ( strcmp(strupper(tokv[0]), "OFF") == 0 ) {
2395 configp->heyu_umask = -1;
2396 }
2397 else {
2398 configp->heyu_umask = (int)strtol(tokv[0], &sp, 8);
2399 if ( !strchr(" \t\r\n", *sp) || configp->heyu_umask < 0 ) {
2400 store_error_message("Invalid HEYU_UMASK value.");
2401 errors++;
2402 }
2403 }
2404 break;
2405
2406 case AutoWait :
2407 configp->auto_wait = (int)strtol(tokv[0], &sp, 10);
2408 if ( !strchr(" \t\n\r", *sp) ||
2409 configp->auto_wait < 0 || configp->auto_wait > 300 ) {
2410 store_error_message("AUTO_WAIT timeout must be 0-300 seconds.");
2411 errors++;
2412 }
2413 break;
2414
2415 case FullBright :
2416 value = (int)strtol(tokv[0], &sp, 10);
2417 if ( !strchr(" \t\n\r", *sp) || value < 16 || value > 31 ) {
2418 store_error_message("FULL_BRIGHT level must be 16 though 31");
2419 errors++;
2420 }
2421 configp->full_bright = (unsigned char)value;
2422 break;
2423
2424 case EnginePoll :
2425 configp->engine_poll = strtol(tokv[0], &sp, 10);
2426 if ( !strchr(" \t\n\r", *sp) ||
2427 configp->engine_poll < 100L ||
2428 configp->engine_poll > 1000000L ) {
2429 store_error_message("ENGINE_POLL must be 100 though 1000000");
2430 errors++;
2431 }
2432 break;
2433
2434 case DmxTscale :
2435 strupper(tokv[0]);
2436 if ( strncmp(tokv[0], "FAHRENHEIT", 1) == 0 )
2437 configp->dmx_tscale = 'F';
2438 else if ( strncmp(tokv[0], "CELSIUS", 1) == 0 )
2439 configp->dmx_tscale = 'C';
2440 else if ( strncmp(tokv[0], "KELVIN", 1) == 0 )
2441 configp->dmx_tscale = 'K';
2442 else if ( strncmp(tokv[0], "RANKINE", 1) == 0 )
2443 configp->dmx_tscale = 'R';
2444 else {
2445 store_error_message("DMX_TSCALE must be C, F, K, or R");
2446 errors++;
2447 }
2448 if ( tokc > 1 ) {
2449 configp->dmx_toffset = strtod(tokv[1], &sp);
2450 if ( !strchr(" \t\n", *sp) ) {
2451 store_error_message("Invalid DMX_TSCALE offset.");
2452 errors++;
2453 }
2454 }
2455 break;
2456
2457 case OreLowBatt :
2458 value = (int)strtol(tokv[0], &sp, 10);
2459 if ( !strchr(" %\t\n\r", *sp) || value < 10 || value > 90 ) {
2460 store_error_message("ORE_LOWBATTERY level must be 10 though 90 percent");
2461 errors++;
2462 }
2463 configp->ore_lobat = (unsigned char)value;
2464 break;
2465
2466
2467 case OreTscale :
2468 strupper(tokv[0]);
2469 if ( strncmp(tokv[0], "FAHRENHEIT", 1) == 0 )
2470 configp->ore_tscale = 'F';
2471 else if ( strncmp(tokv[0], "CELSIUS", 1) == 0 )
2472 configp->ore_tscale = 'C';
2473 else if ( strncmp(tokv[0], "KELVIN", 1) == 0 )
2474 configp->ore_tscale = 'K';
2475 else if ( strncmp(tokv[0], "RANKINE", 1) == 0 )
2476 configp->ore_tscale = 'R';
2477 else {
2478 store_error_message("ORE_TSCALE must be C, F, K, or R");
2479 errors++;
2480 }
2481 if ( tokc > 1 ) {
2482 configp->ore_toffset = strtod(tokv[1], &sp);
2483 if ( !strchr(" \t\n", *sp) ) {
2484 store_error_message("Invalid ORE_TSCALE offset.");
2485 errors++;
2486 }
2487 }
2488 break;
2489
2490 case OreBPscale :
2491 strncpy2(configp->ore_bpunits, tokv[0], NAME_LEN - 1);
2492 configp->ore_bpscale = strtod(tokv[1], &sp);
2493 if ( !strchr(" \t\n", *sp) ) {
2494 store_error_message("Invalid ORE_BPSCALE scale factor.");
2495 errors++;
2496 break;
2497 }
2498 if ( tokc > 2 ) {
2499 configp->ore_bpoffset = strtod(tokv[2], &sp);
2500 if ( !strchr(" \t\n", *sp) ) {
2501 store_error_message("Invalid ORE_BPSCALE offset.");
2502 errors++;
2503 break;
2504 }
2505 }
2506 break;
2507
2508 case OreWgtscale :
2509 strncpy2(configp->ore_wgtunits, tokv[0], NAME_LEN - 1);
2510 configp->ore_wgtscale = strtod(tokv[1], &sp);
2511 if ( !strchr(" \t\n", *sp) ) {
2512 store_error_message("Invalid ORE_WGTSCALE scale factor.");
2513 errors++;
2514 }
2515 break;
2516
2517 case OreWindscale :
2518 strncpy2(configp->ore_windunits, tokv[0], NAME_LEN - 1);
2519 configp->ore_windscale = strtod(tokv[1], &sp);
2520 if ( !strchr(" \t\r\n", *sp) ) {
2521 store_error_message("Invalid ORE_WINDSCALE scale factor.");
2522 errors++;
2523 }
2524 break;
2525
2526 case OreWindSensorDir :
2527 dblvalue = strtod(tokv[0], &sp);
2528 if ( !strchr(" \t\r\n", *sp) || dblvalue < -359.6 || dblvalue > 359.9 ) {
2529 store_error_message("Invalid ORE_WINDSENSORDIR angle.");
2530 errors++;
2531 }
2532 /* Store as integer decidegrees */
2533 configp->ore_windsensordir = (int)(dblvalue * 10.0);
2534 break;
2535
2536 case OreWindDirMode :
2537 strupper(tokv[0]);
2538 if ( !strcmp(tokv[0], "POINTS") )
2539 configp->ore_winddir_mode = COMPASS_POINTS;
2540 else if ( !strcmp(tokv[0], "ANGLE") )
2541 configp->ore_winddir_mode = COMPASS_ANGLE;
2542 else if ( !strcmp(tokv[0], "BOTH") )
2543 configp->ore_winddir_mode = (COMPASS_POINTS|COMPASS_ANGLE);
2544 else {
2545 store_error_message("ORE_WINDDIR_MODE must be POINTS, ANGLE, or BOTH.");
2546 errors++;
2547 }
2548 break;
2549
2550 case OreRainRatescale :
2551 strncpy2(configp->ore_rainrateunits, tokv[0], NAME_LEN - 1);
2552 configp->ore_rainratescale = strtod(tokv[1], &sp);
2553 if ( !strchr(" \t\r\n", *sp) ) {
2554 store_error_message("Invalid ORE_RAINRATESCALE scale factor.");
2555 errors++;
2556 }
2557 break;
2558
2559 case OreRainTotscale :
2560 strncpy2(configp->ore_raintotunits, tokv[0], NAME_LEN - 1);
2561 configp->ore_raintotscale = strtod(tokv[1], &sp);
2562 if ( !strchr(" \t\r\n", *sp) ) {
2563 store_error_message("Invalid ORE_RAINTOTSCALE scale factor.");
2564 errors++;
2565 }
2566 break;
2567
2568 case RfxTscale :
2569 strupper(tokv[0]);
2570 if ( strncmp(tokv[0], "FAHRENHEIT", 1) == 0 )
2571 configp->rfx_tscale = 'F';
2572 else if ( strncmp(tokv[0], "CELSIUS", 1) == 0 )
2573 configp->rfx_tscale = 'C';
2574 else if ( strncmp(tokv[0], "KELVIN", 1) == 0 )
2575 configp->rfx_tscale = 'K';
2576 else if ( strncmp(tokv[0], "RANKINE", 1) == 0 )
2577 configp->rfx_tscale = 'R';
2578 else {
2579 store_error_message("RFX_TSCALE must be C, F, K, or R");
2580 errors++;
2581 }
2582 if ( tokc > 1 ) {
2583 configp->rfx_toffset = strtod(tokv[1], &sp);
2584 if ( !strchr(" \t\n", *sp) ) {
2585 store_error_message("Invalid RFX_TSCALE offset.");
2586 errors++;
2587 }
2588 }
2589 break;
2590
2591 case RfxVadscale :
2592 strncpy2(configp->rfx_vadunits, tokv[0], NAME_LEN - 1);
2593 configp->rfx_vadscale = strtod(tokv[1], &sp);
2594 if ( !strchr(" \t\n", *sp) ) {
2595 store_error_message("Invalid RFX_VADSCALE scale factor.");
2596 errors++;
2597 break;
2598 }
2599 if ( tokc > 2 ) {
2600 configp->rfx_vadoffset = strtod(tokv[2], &sp);
2601 if ( !strchr(" \t\n", *sp) ) {
2602 store_error_message("Invalid RFX_VADSCALE offset.");
2603 errors++;
2604 break;
2605 }
2606 }
2607 break;
2608
2609 case RfxBPscale :
2610 strncpy2(configp->rfx_bpunits, tokv[0], NAME_LEN - 1);
2611 configp->rfx_bpscale = strtod(tokv[1], &sp);
2612 if ( !strchr(" \t\n", *sp) ) {
2613 store_error_message("Invalid RFX_BPSCALE scale factor.");
2614 errors++;
2615 break;
2616 }
2617 if ( tokc > 2 ) {
2618 configp->rfx_bpoffset = strtod(tokv[2], &sp);
2619 if ( !strchr(" \t\n", *sp) ) {
2620 store_error_message("Invalid RFX_BPSCALE offset.");
2621 errors++;
2622 break;
2623 }
2624 }
2625 break;
2626
2627 case RfxComDtrRts :
2628 value = (int)strtol(tokv[0], &sp, 10);
2629 if ( !strchr(" \t\n\r", *sp) || value < 0 || value > 3 ) {
2630 store_error_message("RFXCOM_DTR_RTS must be 0 though 3");
2631 errors++;
2632 }
2633 configp->rfxcom_dtr_rts = (unsigned char)value;
2634 break;
2635
2636
2637 break;
2638
2639 case RfxHiBaud :
2640 (void) strupper(tokv[0]);
2641 if ( !strcmp(tokv[0], "YES") )
2642 configp->rfxcom_hibaud = YES;
2643 else if ( !strcmp(tokv[0], "NO") )
2644 configp->rfxcom_hibaud = NO;
2645 else {
2646 store_error_message("RFXCOM_HIBAUD must be YES or NO");
2647 errors++;
2648 }
2649 break;
2650
2651 case RfxPowerScale :
2652 strncpy2(configp->rfx_powerunits, tokv[0], NAME_LEN - 1);
2653 configp->rfx_powerscale = strtod(tokv[1], &sp);
2654 if ( !strchr(" \t\n", *sp) ) {
2655 store_error_message("Invalid RFX_POWERSCALE scale factor.");
2656 errors++;
2657 break;
2658 }
2659 break;
2660
2661 case RfxWaterScale :
2662 strncpy2(configp->rfx_waterunits, tokv[0], NAME_LEN - 1);
2663 configp->rfx_waterscale = strtod(tokv[1], &sp);
2664 if ( !strchr(" \t\n", *sp) ) {
2665 store_error_message("Invalid RFX_WATERSCALE scale factor.");
2666 errors++;
2667 break;
2668 }
2669 break;
2670
2671 case RfxGasScale :
2672 strncpy2(configp->rfx_gasunits, tokv[0], NAME_LEN - 1);
2673 configp->rfx_gasscale = strtod(tokv[1], &sp);
2674 if ( !strchr(" \t\n", *sp) ) {
2675 store_error_message("Invalid RFX_GASSCALE scale factor.");
2676 errors++;
2677 break;
2678 }
2679 break;
2680
2681 case RfxPulseScale :
2682 strncpy2(configp->rfx_pulseunits, tokv[0], NAME_LEN - 1);
2683 configp->rfx_pulsescale = strtod(tokv[1], &sp);
2684 if ( !strchr(" \t\n", *sp) ) {
2685 store_error_message("Invalid RFX_PULSESCALE scale factor.");
2686 errors++;
2687 break;
2688 }
2689 break;
2690
2691 case RfxComEnable :
2692 store_error_message("RFXCOM_ENABLE is obsolete; see RFXCOM_DISABLE");
2693 break;
2694
2695 #if 0
2696 case RfxComDisable :
2697 for ( j = 0; j < tokc; j++ ) {
2698 strupper(tokv[j]);
2699 if ( strncmp(tokv[j], "ARCTECH", 3) == 0 )
2700 configp->rfxcom_disable |= RFXCOM_ARCTECH;
2701 else if ( strncmp(tokv[j], "OREGON", 3) == 0 )
2702 configp->rfxcom_disable |= RFXCOM_OREGON;
2703 else if ( strncmp(tokv[j], "ATIWONDER", 3) == 0 )
2704 configp->rfxcom_disable |= RFXCOM_ATIWONDER;
2705 else if ( strncmp(tokv[j], "X10", 3) == 0 )
2706 configp->rfxcom_disable |= RFXCOM_X10;
2707 else if ( strncmp(tokv[j], "VISONIC", 3) == 0 )
2708 configp->rfxcom_disable |= RFXCOM_VISONIC;
2709 else if ( strncmp(tokv[j], "KOPPLA", 3) == 0 )
2710 configp->rfxcom_disable |= RFXCOM_KOPPLA;
2711 else if ( strcmp(tokv[j], "HE_UK") == 0 )
2712 configp->rfxcom_disable |= RFXCOM_HE_UK;
2713 else if ( strcmp(tokv[j], "HE_EU") == 0 )
2714 configp->rfxcom_disable |= RFXCOM_HE_EU;
2715 else {
2716 sprintf(errbuffer, "Invalid RFXCOM_DISABLE protocol %s", tokv[j]);
2717 store_error_message(errbuffer);
2718 errors++;
2719 break;
2720 }
2721 }
2722 break;
2723 #endif
2724
2725 case RfxComDisable :
2726 configp->rfxcom_disable = 0;
2727 for ( j = 0; j < tokc; j++ ) {
2728 strupper(tokv[j]);
2729 for ( k = 0; k < nrfxdisable; k++ ) {
2730 if ( strncmp(tokv[j], rfx_disable[k].label, rfx_disable[k].minlabel) == 0 ) {
2731 configp->rfxcom_disable |= rfx_disable[k].bitmap;
2732 *tokv[j] = '\0';
2733 break;
2734 }
2735 }
2736 if ( *tokv[j] ) {
2737 sprintf(errbuffer, "Invalid RFXCOM_DISABLE protocol %s", tokv[j]);
2738 store_error_message(errbuffer);
2739 errors++;
2740 break;
2741 }
2742 }
2743 break;
2744
2745 case LockupCheck :
2746 for ( j = 0; j < tokc; j++ ) {
2747 strupper(tokv[j]);
2748 if ( strcmp(tokv[j], "YES") == 0 )
2749 configp->lockup_check = (CHECK_PORT | CHECK_CM11);
2750 else if ( strcmp(tokv[j], "PORT") == 0 )
2751 configp->lockup_check = CHECK_PORT;
2752 else if ( strncmp(tokv[j], "CM11A", 4) == 0 )
2753 configp->lockup_check = CHECK_CM11;
2754 else if ( strcmp(tokv[j], "NO") == 0 )
2755 configp->lockup_check = 0;
2756 else {
2757 sprintf(errbuffer, "Invalid LOCKUP_CHECK parameter %s", tokv[j]);
2758 store_error_message(errbuffer);
2759 errors++;
2760 break;
2761 }
2762 }
2763 break;
2764
2765 case TailPath :
2766 strncpy2(configp->tailpath, tokv[0], sizeof(config.tailpath));
2767 break;
2768
2769 case RfxJam :
2770 (void) strupper(tokv[0]);
2771 if ( !strcmp(tokv[0], "YES") )
2772 configp->suppress_rfxjam = YES;
2773 else if ( !strcmp(tokv[0], "NO") )
2774 configp->suppress_rfxjam = NO;
2775 else {
2776 store_error_message("SUPPRESS_RFXJAM must be YES or NO");
2777 errors++;
2778 }
2779 break;
2780
2781 case DispDmxTemp :
2782 (void) strupper(tokv[0]);
2783 if ( !strcmp(tokv[0], "YES") )
2784 configp->display_dmxtemp = YES;
2785 else if ( !strcmp(tokv[0], "NO") )
2786 configp->display_dmxtemp = NO;
2787 else {
2788 store_error_message("DISPLAY_DMXTEMP must be YES or NO");
2789 errors++;
2790 }
2791 break;
2792
2793 case SecID16 :
2794 (void) strupper(tokv[0]);
2795 if ( !strcmp(tokv[0], "YES") )
2796 configp->securid_16 = YES;
2797 else if ( !strcmp(tokv[0], "NO") )
2798 configp->securid_16 = NO;
2799 else {
2800 store_error_message("SECURID_16 must be YES or NO");
2801 errors++;
2802 }
2803 break;
2804
2805 case SecIDPar :
2806 (void) strupper(tokv[0]);
2807 if ( !strcmp(tokv[0], "YES") )
2808 configp->securid_parity = YES;
2809 else if ( !strcmp(tokv[0], "NO") )
2810 configp->securid_parity = NO;
2811 else {
2812 store_error_message("SECURID_PARITY must be YES or NO");
2813 errors++;
2814 }
2815 break;
2816
2817 case LogDateYr :
2818 (void) strupper(tokv[0]);
2819 if ( !strcmp(tokv[0], "YES") )
2820 configp->logdate_year = YES;
2821 else if ( !strcmp(tokv[0], "NO") )
2822 configp->logdate_year = NO;
2823 else {
2824 store_error_message("LOGDATE_YEAR must be YES or NO");
2825 errors++;
2826 }
2827 break;
2828
2829 case LogDateUnix :
2830 (void) strupper(tokv[0]);
2831 if ( !strcmp(tokv[0], "YES") )
2832 configp->logdate_unix = YES;
2833 else if ( !strcmp(tokv[0], "NO") )
2834 configp->logdate_unix = NO;
2835 else {
2836 store_error_message("LOGDATE_UNIX must be YES or NO");
2837 errors++;
2838 }
2839 break;
2840
2841 case DispOreAll :
2842 (void) strupper(tokv[0]);
2843 if ( !strcmp(tokv[0], "YES") )
2844 configp->disp_ore_all = YES;
2845 else if ( !strcmp(tokv[0], "NO") )
2846 configp->disp_ore_all = NO;
2847 else {
2848 store_error_message("DISPLAY_ORE_ALL must be YES or NO");
2849 errors++;
2850 }
2851 break;
2852
2853 case OreDispFcast :
2854 (void) strupper(tokv[0]);
2855 if ( !strcmp(tokv[0], "YES") )
2856 configp->ore_display_fcast = YES;
2857 else if ( !strcmp(tokv[0], "NO") )
2858 configp->ore_display_fcast = NO;
2859 else {
2860 store_error_message("ORE_DISPLAY_FCAST must be YES or NO");
2861 errors++;
2862 }
2863 break;
2864
2865 case OreChgBitsT :
2866 value = (int)strtol(tokv[0], &sp, 10);
2867 if ( !strchr(" \t\n\r", *sp) || value < 1 || value > 255 ) {
2868 store_error_message("ORE_CHGBITS_T must be 1 though 255");
2869 errors++;
2870 }
2871 configp->ore_chgbits_t = (unsigned char)value;
2872 break;
2873
2874 case OreChgBitsRH :
2875 value = (int)strtol(tokv[0], &sp, 10);
2876 if ( !strchr(" \t\n\r", *sp) || value < 1 || value > 255 ) {
2877 store_error_message("ORE_CHGBITS_RH must be 1 though 255");
2878 errors++;
2879 }
2880 configp->ore_chgbits_rh = (unsigned char)value;
2881 break;
2882
2883 case OreChgBitsBP :
2884 value = (int)strtol(tokv[0], &sp, 10);
2885 if ( !strchr(" \t\n\r", *sp) || value < 1 || value > 255 ) {
2886 store_error_message("ORE_CHGBITS_BP must be 1 though 255");
2887 errors++;
2888 }
2889 configp->ore_chgbits_bp = (unsigned char)value;
2890 break;
2891
2892 case OreChgBitsWgt :
2893 value = (int)strtol(tokv[0], &sp, 10);
2894 if ( !strchr(" \t\n\r", *sp) || value < 1 || value > 255 ) {
2895 store_error_message("ORE_CHGBITS_WGT must be 1 though 255");
2896 errors++;
2897 }
2898 configp->ore_chgbits_wgt = (unsigned char)value;
2899 break;
2900
2901 case OreChgBitsWsp :
2902 longvalue = strtol(tokv[0], &sp, 10);
2903 if ( !strchr(" \t\n\r", *sp) || longvalue < 1 || longvalue > 65535 ) {
2904 store_error_message("ORE_CHGBITS_WINDSP must be 1 though 65535");
2905 errors++;
2906 }
2907 configp->ore_chgbits_wsp = (unsigned int)longvalue;
2908 break;
2909
2910 case OreChgBitsWavsp :
2911 longvalue = strtol(tokv[0], &sp, 10);
2912 if ( !strchr(" \t\n\r", *sp) || longvalue < 1 || longvalue > 65535 ) {
2913 store_error_message("ORE_CHGBITS_WINDAVSP must be 1 though 65535");
2914 errors++;
2915 }
2916 configp->ore_chgbits_wavsp = (unsigned int)longvalue;
2917 break;
2918
2919 case OreChgBitsWdir :
2920 longvalue = strtol(tokv[0], &sp, 10);
2921 if ( !strchr(" \t\n\r", *sp) || longvalue < 1 || longvalue > 720 ) {
2922 store_error_message("ORE_CHGBITS_WINDDIR must be 1 though 720");
2923 errors++;
2924 }
2925 configp->ore_chgbits_wdir = (unsigned int)longvalue;
2926 break;
2927
2928 case OreChgBitsRrate :
2929 longvalue = strtol(tokv[0], &sp, 10);
2930 if ( !strchr(" \t\n\r", *sp) || longvalue < 1 || longvalue > 65535 ) {
2931 store_error_message("ORE_CHGBITS_RAINRATE must be 1 though 65535");
2932 errors++;
2933 }
2934 configp->ore_chgbits_rrate = (unsigned int)longvalue;
2935 break;
2936
2937 case OreChgBitsRtot :
2938 longvalue = strtol(tokv[0], &sp, 10);
2939 if ( !strchr(" \t\n\r", *sp) || longvalue < 1 || longvalue > 65535 ) {
2940 store_error_message("ORE_CHGBITS_RAINTOT must be 1 though 65535");
2941 errors++;
2942 }
2943 configp->ore_chgbits_rtot = (unsigned int)longvalue;
2944 break;
2945
2946 case OreChgBitsUV :
2947 value = (int)strtol(tokv[0], &sp, 10);
2948 if ( !strchr(" \t\n\r", *sp) || value < 1 || value > 255 ) {
2949 store_error_message("ORE_CHGBITS_UV must be 1 though 255");
2950 errors++;
2951 }
2952 configp->ore_chgbits_uv = (unsigned char)value;
2953 break;
2954
2955 case OreDataEntry :
2956 (void) strupper(tokv[0]);
2957 if ( !strcmp(tokv[0], "NATIVE") )
2958 configp->ore_data_entry = NATIVE;
2959 else if ( !strcmp(tokv[0], "SCALED") )
2960 configp->ore_data_entry = SCALED;
2961 else {
2962 store_error_message("ORE_DATA_ENTRY must be NATIVE or SCALED");
2963 errors++;
2964 }
2965 break;
2966
2967 case OreDispChan :
2968 (void) strupper(tokv[0]);
2969 if ( !strcmp(tokv[0], "YES") )
2970 configp->ore_display_chan = YES;
2971 else if ( !strcmp(tokv[0], "NO") )
2972 configp->ore_display_chan = NO;
2973 else {
2974 store_error_message("ORE_DISPLAY_CHAN must be YES or NO");
2975 errors++;
2976 }
2977 break;
2978
2979 case OreDispBatLvl :
2980 (void) strupper(tokv[0]);
2981 if ( !strcmp(tokv[0], "YES") )
2982 configp->ore_display_batlvl = YES;
2983 else if ( !strcmp(tokv[0], "NO") )
2984 configp->ore_display_batlvl = NO;
2985 else {
2986 store_error_message("ORE_DISPLAY_BATLVL must be YES or NO");
2987 errors++;
2988 }
2989 break;
2990
2991 case OreDispCount :
2992 (void) strupper(tokv[0]);
2993 if ( !strcmp(tokv[0], "YES") )
2994 configp->ore_display_count = YES;
2995 else if ( !strcmp(tokv[0], "NO") )
2996 configp->ore_display_count = NO;
2997 else {
2998 store_error_message("ORE_DISPLAY_COUNT must be YES or NO");
2999 errors++;
3000 }
3001 break;
3002
3003 case OreDispBft :
3004 (void) strupper(tokv[0]);
3005 if ( !strcmp(tokv[0], "YES") )
3006 configp->ore_display_bft = YES;
3007 else if ( !strcmp(tokv[0], "NO") )
3008 configp->ore_display_bft = NO;
3009 else {
3010 store_error_message("ORE_DISPLAY_BEAUFORT must be YES or NO");
3011 errors++;
3012 }
3013 break;
3014
3015 case OreID16 :
3016 (void) strupper(tokv[0]);
3017 if ( !strcmp(tokv[0], "YES") )
3018 configp->oreid_16 = YES;
3019 else if ( !strcmp(tokv[0], "NO") )
3020 configp->oreid_16 = NO;
3021 else {
3022 store_error_message("ORE_ID_16 must be YES or NO");
3023 errors++;
3024 }
3025 break;
3026
3027 case DispSensorIntv :
3028 (void) strupper(tokv[0]);
3029 if ( !strcmp(tokv[0], "YES") )
3030 configp->display_sensor_intv = YES;
3031 else if ( !strcmp(tokv[0], "NO") )
3032 configp->display_sensor_intv = NO;
3033 else {
3034 store_error_message("DISPLAY_SENSOR_INTV must be YES or NO");
3035 errors++;
3036 }
3037 break;
3038
3039 case DateFormat :
3040 (void) strupper(tokv[0]);
3041 if ( !strcmp(tokv[0], "YMD") )
3042 configp->date_format = YMD_ORDER;
3043 else if ( !strcmp(tokv[0], "DMY") )
3044 configp->date_format = DMY_ORDER;
3045 else if ( !strcmp(tokv[0], "MDY") )
3046 configp->date_format = MDY_ORDER;
3047 else {
3048 store_error_message("DATE_FORMAT order must be YMD, DMY, or MDY");
3049 errors++;
3050 break;
3051 }
3052
3053 if ( tokc == 2 ) {
3054 if ( !strcmp(tokv[1], "'/'") || !strcmp(tokv[1], "\"/\"") || !strcmp(tokv[1], "/") )
3055 configp->date_separator = '/';
3056 else if ( !strcmp(tokv[1], "'-'") || !strcmp(tokv[1], "\"-\"") || !strcmp(tokv[1], "-") )
3057 configp->date_separator = '-';
3058 else if ( !strcmp(tokv[1], "'.'") || !strcmp(tokv[1], "\".\"") || !strcmp(tokv[1], ".") )
3059 configp->date_separator = '.';
3060 else {
3061 store_error_message("DATE_FORMAT separator must be '/', '-', or '.'");
3062 errors++;
3063 }
3064 }
3065 break;
3066
3067 case LockTimeout :
3068 value = (int)strtol(tokv[0], &sp, 10);
3069 if ( !strchr(" \t\n\r", *sp) || value < 5 || value > 60 ) {
3070 store_error_message("LOCK_TIMEOUT range is 5 through 60 seconds");
3071 errors++;
3072 }
3073 configp->lock_timeout = value;
3074 break;
3075
3076 case CM11QueryDelay :
3077 value = (int)strtol(tokv[0], &sp, 10);
3078 if ( !strchr(" \t\n\r", *sp) || value < 0 || value > 100 ) {
3079 store_error_message("CM11_QUERY_DELAY range is 0 through 100 milliseconds");
3080 errors++;
3081 }
3082 configp->cm11a_query_delay = value;
3083 break;
3084
3085 case ElsNumber :
3086 value = (int)strtol(tokv[0], &sp, 10);
3087 if ( !strchr(" \t\n\r", *sp) || value < 1 || value > 3 ) {
3088 store_error_message("ELS_NUMBER range is 1 through 3");
3089 errors++;
3090 }
3091 configp->els_number = value;
3092 break;
3093
3094 case ElsVoltage :
3095 dblvalue = strtod(tokv[0], &sp);
3096 if ( !strchr(" \t\n\r", *sp) || dblvalue < 0.0 ) {
3097 store_error_message("ELS_VOLTAGE is invalid or negative");
3098 errors++;
3099 }
3100 configp->els_voltage = dblvalue;
3101 break;
3102
3103 case ElsChgBitsCurr :
3104 value = (int)strtol(tokv[0], &sp, 10);
3105 if ( !strchr(" \t\n\r", *sp) || value < 1 || value > 1000 ) {
3106 store_error_message("ELS_CHGBITS_CURR is 1 through 1000");
3107 errors++;
3108 }
3109 configp->els_chgbits_curr = value;
3110 break;
3111
3112 case ScanMode :
3113 (void) strupper(tokv[0]);
3114 if ( !strcmp(tokv[0], "CONTINUE") )
3115 configp->scanmode = FM_CONTINUE;
3116 else if ( !strcmp(tokv[0], "BREAK") )
3117 configp->scanmode = FM_BREAK;
3118 else {
3119 store_error_message("LAUNCHER_SCANMODE must be CONTINUE or BREAK");
3120 errors++;
3121 }
3122 break;
3123
3124 case RfxInline :
3125 (void) strupper(tokv[0]);
3126 if ( !strcmp(tokv[0], "YES") )
3127 configp->rfx_inline = YES;
3128 else if ( !strcmp(tokv[0], "NO") )
3129 configp->rfx_inline = NO;
3130 else {
3131 store_error_message("RFXMETER_SETUP_INLINE must be YES or NO");
3132 errors++;
3133 }
3134 break;
3135
3136 case OwlVoltage :
3137 dblvalue = strtod(tokv[0], &sp);
3138 if ( !strchr(" \t\n\r", *sp) || dblvalue < 0.0 ) {
3139 store_error_message("OWL_VOLTAGE is invalid or negative");
3140 errors++;
3141 }
3142 configp->owl_voltage = dblvalue;
3143 break;
3144
3145 case OwlCalibPower :
3146 dblvalue = strtod(tokv[0], &sp);
3147 if ( !strchr(" \t\n\r", *sp) || dblvalue < 0.0 ) {
3148 store_error_message("OWL_CALIB_POWER is invalid or negative");
3149 errors++;
3150 }
3151 configp->owl_calib_power = dblvalue;
3152 break;
3153
3154 case OwlCalibEnergy :
3155 dblvalue = strtod(tokv[0], &sp);
3156 if ( !strchr(" \t\n\r", *sp) || dblvalue < 0.0 ) {
3157 store_error_message("OWL_CALIB_ENERGY is invalid or negative");
3158 errors++;
3159 }
3160 configp->owl_calib_energy = dblvalue;
3161 break;
3162
3163 case OwlChgBitsPower :
3164 longvalue = strtol(tokv[0], &sp, 10);
3165 if ( !strchr(" \t\n\r", *sp) || longvalue < 1L || longvalue > 10000L ) {
3166 store_error_message("OWL_CHGBITS_POWER is 1 through 10000");
3167 errors++;
3168 }
3169 configp->owl_chgbits_power = longvalue;
3170 break;
3171
3172 case OwlChgBitsEnergy :
3173 longvalue = strtol(tokv[0], &sp, 10);
3174 if ( !strchr(" \t\n\r", *sp) || longvalue < 1L || longvalue > 100000L ) {
3175 store_error_message("OWL_CHGBITS_ENERGY is 1 through 100000");
3176 errors++;
3177 }
3178 configp->owl_chgbits_energy = longvalue;
3179 break;
3180
3181 case OwlDispCount :
3182 (void) strupper(tokv[0]);
3183 if ( !strcmp(tokv[0], "YES") )
3184 configp->owl_display_count = YES;
3185 else if ( !strcmp(tokv[0], "NO") )
3186 configp->owl_display_count = NO;
3187 else {
3188 store_error_message("OWL_DISPLAY_COUNT must be YES or NO");
3189 errors++;
3190 }
3191 break;
3192
3193 case ArmRemote :
3194 (void) strupper(tokv[0]);
3195 if ( !strncmp(tokv[0], "MANUAL", 3) )
3196 configp->arm_remote = MANUAL;
3197 else if ( !strncmp(tokv[0], "AUTOMATIC", 4) )
3198 configp->arm_remote = AUTOMATIC;
3199 else {
3200 store_error_message("ARM_REMOTE must be MANUAL or AUTO");
3201 errors++;
3202 }
3203 break;
3204
3205 case ActiveChange :
3206 (void) strupper(tokv[0]);
3207 if ( !strcmp(tokv[0], "YES") )
3208 configp->active_change = YES;
3209 else if ( !strcmp(tokv[0], "NO") )
3210 configp->active_change = NO;
3211 else {
3212 store_error_message("ACTIVE_CHANGE must be YES or NO");
3213 errors++;
3214 }
3215 break;
3216
3217 case InactiveHandling :
3218 (void) strupper(tokv[0]);
3219 if ( !strcmp(tokv[0], "NEW") )
3220 configp->inactive_handling = NEW;
3221 else if ( !strcmp(tokv[0], "OLD") )
3222 configp->inactive_handling = OLD;
3223 else {
3224 store_error_message("INACTIVE_HANDLING must be NEW or OLD");
3225 errors++;
3226 }
3227 break;
3228
3229 case ProcessXmit :
3230 (void) strupper(tokv[0]);
3231 if ( !strcmp(tokv[0], "YES") )
3232 configp->process_xmit = YES;
3233 else if ( !strcmp(tokv[0], "NO") )
3234 configp->process_xmit = NO;
3235 else {
3236 store_error_message("PROCESS_XMIT must be YES or NO");
3237 errors++;
3238 }
3239 break;
3240
3241 case ShowFlagsMode :
3242 (void) strupper(tokv[0]);
3243 if ( !strcmp(tokv[0], "NEW") )
3244 configp->show_flags_mode = NEW;
3245 else if ( !strcmp(tokv[0], "OLD") )
3246 configp->show_flags_mode = OLD;
3247 else {
3248 store_error_message("SHOW_FLAGS_MODE must be NEW or OLD");
3249 errors++;
3250 }
3251 break;
3252
3253 case LaunchPathAppend :
3254 strtrim(tokv[0]);
3255 if ( strlen(tokv[0]) > PATH_LEN ) {
3256 store_error_message("LAUNCHPATH_APPEND too long");
3257 errors++;
3258 }
3259 else {
3260 strcpy(configp->launchpath_append, tokv[0]);
3261 }
3262 break;
3263
3264 case LaunchPathPrefix :
3265 strtrim(tokv[0]);
3266 if ( strlen(tokv[0]) > PATH_LEN ) {
3267 store_error_message("LAUNCHPATH_PREFIX too long");
3268 errors++;
3269 }
3270 else {
3271 strcpy(configp->launchpath_prefix, tokv[0]);
3272 }
3273 break;
3274
3275 case FixStopStartError :
3276 (void) strupper(tokv[0]);
3277 if ( !strcmp(tokv[0], "YES") )
3278 configp->fix_stopstart_error = YES;
3279 else if ( !strcmp(tokv[0], "NO") )
3280 configp->fix_stopstart_error = NO;
3281 else {
3282 store_error_message("FIX_STOPSTART_ERROR must be YES or NO");
3283 errors++;
3284 }
3285 break;
3286
3287 case ChkSumTimeout :
3288 longvalue = strtol(tokv[0], &sp, 10);
3289 if ( !strchr(" \t\n\r", *sp) || longvalue < 1L || longvalue > 20L ) {
3290 store_error_message("CHKSUM_TIMEOUT must be 1 through 20 seconds");
3291 errors++;
3292 break;
3293 }
3294 configp->chksum_timeout = longvalue;
3295 break;
3296
3297 default :
3298 store_error_message("Unsupported config directive");
3299 errors++;
3300 break;
3301
3302 }
3303 free( tokv );
3304
3305 return errors;
3306 }
3307
3308 /*---------------------------------------------------------------------+
3309 | Get certain configuration items from environment. |
3310 +---------------------------------------------------------------------*/
environment_config(void)3311 int environment_config ( void )
3312 {
3313 int j, retcode, errors = 0;
3314 char *sp;
3315 char buffer[32];
3316
3317 static char *envars[] = {
3318 "LATITUDE",
3319 "LONGITUDE",
3320 "ASIF_DATE",
3321 "ASIF_TIME",
3322 };
3323
3324 reset_isparsed_flags();
3325
3326 for ( j = 0; j < (int)(sizeof(envars)/sizeof(char *)); j++ ) {
3327 if ( (sp = getenv(envars[j])) != NULL ) {
3328 sprintf(buffer, "%s %s", envars[j], sp);
3329 retcode = parse_config_tail(buffer, SRC_ENVIRON);
3330 errors += retcode;
3331 if ( retcode != 0 || *error_message() != '\0' ) {
3332 fprintf(stderr, "Environment variable %s.\n", error_message());
3333 clear_error_message();
3334 }
3335 }
3336 }
3337 return errors;
3338 }
3339
3340
3341 /*---------------------------------------------------------------------+
3342 | Display configuration file directives that have been overridden, |
3343 | either by an environment variable or by a 'config' command in the |
3344 | schedule file, as indicated by the isparsed flag. |
3345 +---------------------------------------------------------------------*/
display_config_overrides(FILE * fd)3346 void display_config_overrides ( FILE *fd )
3347 {
3348 int j, count = 0;
3349 char delim = ' ';
3350
3351 fprintf(fd, "Configuration overrides:");
3352
3353 for ( j = 0; j < ncommands; j++ ) {
3354 if ( command[j].isparsed & (SRC_ENVIRON | SRC_SCHED)) {
3355 count++;
3356 fprintf(fd, "%c %s", delim, command[j].name);
3357 delim = ',';
3358 }
3359 }
3360 if ( !count )
3361 fprintf(fd, " -- None --");
3362
3363 fprintf(fd, "\n\n");
3364
3365 return;
3366 }
3367
3368 /*---------------------------------------------------------------------+
3369 | Open the user's X10 configuration file and read only the minimal |
3370 | directives for specific commands, like 'heyu stop'. |
3371 +---------------------------------------------------------------------*/
read_minimal_config(unsigned char mode,unsigned int source)3372 void read_minimal_config ( unsigned char mode, unsigned int source )
3373 {
3374
3375 FILE *fd ;
3376 int error_count;
3377 char confp[PATH_LEN + 1];
3378 extern char heyu_config[PATH_LEN + 1];
3379 extern int verbose;
3380
3381 find_heyu_path();
3382
3383 strncpy2(confp, pathspec(heyu_config), sizeof(confp) - 1);
3384
3385 if ( verbose )
3386 (void) fprintf(stdout, "Opening Heyu configuration file '%s'\n", confp);
3387
3388 if ( !(fd = fopen(confp, "r")) ) {
3389 if ( !i_am_relay )
3390 fprintf(stderr, "Unable to find (or open) Heyu configuration file '%s'\n", confp);
3391 else
3392 syslog(LOG_ERR, "Unable to find (or open) Heyu configuration file '%s'\n", confp);
3393
3394 return;
3395 }
3396
3397 error_count = parse_minimal_config( fd, mode, source );
3398
3399 if ( error_count != 0 ) {
3400 if ( !i_am_relay )
3401 fprintf(stderr, "Quitting due to errors in configuration file '%s'\n", confp);
3402 else
3403 syslog(LOG_ERR, "Quitting due to errors in configuration file '%s'\n", confp);
3404 exit(1);
3405 }
3406
3407 (void) fclose( fd );
3408
3409 return;
3410 }
3411
3412
3413 /*---------------------------------------------------------------------+
3414 | Return the index in the array of SCRIPT structures for the SCRIPT |
3415 | having the argument 'label', or -1 if not found. |
3416 +---------------------------------------------------------------------*/
lookup_script(SCRIPT * scriptp,char * label)3417 int lookup_script ( SCRIPT *scriptp, char *label )
3418 {
3419 int j = 0;
3420
3421 while ( scriptp && scriptp[j].line_no > 0 ) {
3422 if ( strcmp(label, scriptp[j].label) == 0 )
3423 return j;
3424 j++;
3425 }
3426 return -1;
3427 }
3428
3429 /*---------------------------------------------------------------------+
3430 | Return the index in the array of LAUNCHER structures for the first |
3431 | LAUNCHER having the argument 'label', or -1 if not found. |
3432 +---------------------------------------------------------------------*/
lookup_launcher(LAUNCHER * launcherp,char * label)3433 int lookup_launcher ( LAUNCHER *launcherp, char *label )
3434 {
3435 int j = 0;
3436
3437 while ( launcherp && launcherp[j].line_no > 0 ) {
3438 if ( strcmp(label, launcherp[j].label) == 0 )
3439 return j;
3440 j++;
3441 }
3442 return -1;
3443 }
3444
3445
3446 /*---------------------------------------------------------------------+
3447 | Create list of Oregon sensor IDs to be ignored and classified as |
3448 | noise. |
3449 +---------------------------------------------------------------------*/
create_oregon_ignore_list(void)3450 int create_oregon_ignore_list ( void )
3451 {
3452 #ifdef HASORE
3453 ALIAS *aliasp;
3454 int j, k;
3455
3456 if ( (aliasp = configp->aliasp) == NULL )
3457 return 0;
3458
3459 ore_ignore_size = 0;
3460 j = 0;
3461 while ( aliasp[j].line_no > 0 ) {
3462 if ( aliasp[j].vtype == RF_OREGON && (aliasp[j].optflags & MOPT_RFIGNORE) ) {
3463 k = 0;
3464 while ( k < aliasp[j].nident && ore_ignore_size < (sizeof(ore_ignore)/sizeof(unsigned int)) ) {
3465 ore_ignore[ore_ignore_size++] = aliasp[j].ident[k];
3466 k++;
3467 }
3468 }
3469 j++;
3470 }
3471 #endif /* HASORE */
3472 return 0;
3473 }
3474
3475 /*---------------------------------------------------------------------+
3476 | Create list of Security sensor IDs to be ignored and classified as |
3477 | noise. |
3478 +---------------------------------------------------------------------*/
create_security_ignore_list(void)3479 int create_security_ignore_list ( void )
3480 {
3481 ALIAS *aliasp;
3482 int j, k;
3483
3484 if ( (aliasp = configp->aliasp) == NULL )
3485 return 0;
3486
3487 sec_ignore_size = 0;
3488 j = 0;
3489 while ( aliasp[j].line_no > 0 ) {
3490 if ( aliasp[j].vtype == RF_SEC && (aliasp[j].optflags & MOPT_RFIGNORE) ) {
3491 k = 0;
3492 while ( k < aliasp[j].nident && sec_ignore_size < (sizeof(sec_ignore)/sizeof(unsigned short)) ) {
3493 sec_ignore[sec_ignore_size++] = aliasp[j].ident[k];
3494 k++;
3495 }
3496 }
3497 j++;
3498 }
3499 return 0;
3500 }
3501
is_sec_ignored(unsigned int saddr)3502 int is_sec_ignored ( unsigned int saddr )
3503 {
3504 int j = 0;
3505
3506 while ( j < sec_ignore_size ) {
3507 if ( saddr == sec_ignore[j] ) {
3508 return 1;
3509 }
3510 j++;
3511 }
3512 return 0;
3513 }
3514
3515 /*---------------------------------------------------------------------+
3516 | Resolve interrelated configuration items. |
3517 +---------------------------------------------------------------------*/
finalize_config(unsigned char mode)3518 int finalize_config ( unsigned char mode )
3519 {
3520 int finalize_launchers(void);
3521 int create_file_paths(void);
3522 mode_t heyu_umask;
3523 int verify_unique_ids(unsigned char);
3524 int assign_data_storage ( void );
3525 int set_elec1_nvar ( int );
3526
3527 ALIAS *aliasp;
3528
3529 char errmsg[80];
3530 char *sp;
3531 int j;
3532
3533
3534 /* Count and configure aliases */
3535 aliasp = configp->aliasp;
3536 j = 0;
3537 while ( aliasp && aliasp[j].line_no > 0 ) {
3538 if ( (aliasp[j].optflags & MOPT_HEARTBEAT) && !(aliasp[j].optflags2 & MOPT2_IATO) ) {
3539 aliasp[j].hb_timeout = configp->inactive_timeout;
3540 }
3541 j++;
3542 }
3543 configp->alias_size = j;
3544
3545 if ( configp->heyu_umask >= 0 )
3546 umask((mode_t)configp->heyu_umask);
3547
3548 heyu_umask = umask(0);
3549 umask(heyu_umask);
3550
3551 if ( configp->log_umask < 0 )
3552 configp->log_umask = (int)heyu_umask;
3553
3554 if ( configp->mode == COMPATIBLE ) {
3555 configp->program_days = 366;
3556 }
3557 else {
3558 configp->program_days = configp->program_days_in;
3559 }
3560
3561 if ( configp->min_dusk != OFF && configp->max_dusk != OFF &&
3562 configp->min_dusk >= configp->max_dusk ) {
3563 store_error_message("MIN_DUSK must be less than MAX_DUSK");
3564 return 1;
3565 }
3566
3567 if ( configp->min_dawn != OFF && configp->max_dawn != OFF &&
3568 configp->min_dawn >= configp->max_dawn ) {
3569 store_error_message("MIN_DAWN must be less than MAX_DAWN");
3570 return 1;
3571 }
3572
3573 if ( configp->rfxcom_enable && configp->rfxcom_disable ) {
3574 store_error_message("RFXCOM_ENABLE (Deprecated) and RFXCOM_DISABLE are incompatible.");
3575 return 1;
3576 }
3577 if ( configp->rfxcom_disable )
3578 configp->rfxcom_enable = 0xFFFF;
3579 else if ( configp->rfxcom_enable )
3580 store_error_message("Directive RFXCOM_ENABLE is deprecated; see RFXCOM_DISABLE");
3581
3582 if ( configp->securid_16 == NO || configp->auxdev != DEV_RFXCOMVL ) {
3583 configp->securid_mask = 0x00ffu;
3584 }
3585 else {
3586 configp->securid_mask = 0xffffu;
3587 }
3588
3589 if ( configp->oreid_16 == NO || configp->auxdev != DEV_RFXCOMVL ) {
3590 configp->oreid_mask = 0x00ffu;
3591 }
3592 else {
3593 configp->oreid_mask = 0xffffu;
3594 }
3595
3596 if ( verify_unique_ids(RF_ENT) != 0 ||
3597 verify_unique_ids(RF_SEC) != 0 ||
3598 verify_unique_ids(RF_XSENSOR) != 0 ||
3599 verify_unique_ids(RF_XMETER) != 0 ||
3600 verify_unique_ids(RF_DIGIMAX) != 0 ||
3601 verify_unique_ids(RF_OREGON) != 0 ) {
3602 return 1;
3603 }
3604
3605 if ( strcmp(configp->tty, "dummy") == 0 ) {
3606 configp->device_type |= DEV_DUMMY;
3607 }
3608
3609 /* Create suffix for lock files, e.g., ".ttyS0" */
3610
3611 if ( (sp = strrchr(configp->tty, '/')) != NULL ) {
3612 strncpy2(configp->suffix, sp, sizeof(config.suffix) - 1);
3613 *(configp->suffix) = '.';
3614 }
3615 else {
3616 strncpy2(configp->suffix, ".", sizeof(config.suffix) - 1);
3617 strncat(configp->suffix, configp->tty,
3618 sizeof(config.suffix) - 1 - strlen(configp->suffix));
3619 }
3620
3621 if ( configp->auxdev ) {
3622 if ( (sp = strrchr(configp->ttyaux, '/')) != NULL ) {
3623 strncpy2(configp->suffixaux, sp, sizeof(config.suffixaux) - 1);
3624 *(configp->suffixaux) = '.';
3625 }
3626 else {
3627 strncpy2(configp->suffixaux, ".", sizeof(config.suffixaux) - 1);
3628 strncat(configp->suffixaux, configp->ttyaux,
3629 sizeof(config.suffixaux) - 1 - strlen(configp->suffixaux));
3630 }
3631 }
3632
3633 if ( configp->aux_repcounts[0] == 0 ) {
3634 configp->aux_repcounts[0] =
3635 (configp->auxdev == DEV_RFXCOM32 ||
3636 configp->auxdev == DEV_RFXCOMVL ) ?
3637 DEF_AUX_MINCOUNT_RFXCOM :
3638 (configp->auxdev == DEV_MR26A) ? DEF_AUX_MINCOUNT_MR26 : DEF_AUX_MINCOUNT_W800;
3639 }
3640
3641 if ( configp->aux_mincount_rfx == 0 ) {
3642 if (configp->auxdev == DEV_RFXCOM32 ||
3643 configp->auxdev == DEV_RFXCOMVL ) {
3644 configp->aux_mincount_rfx = max(DEF_AUX_MINCOUNT_RFX, configp->aux_repcounts[0]);
3645 }
3646 else {
3647 configp->aux_mincount_rfx = configp->aux_repcounts[0];
3648 }
3649 }
3650
3651 if ( *configp->logfile == '\0' ) {
3652 strncpy2(configp->logfile, DEF_LOGFILE, sizeof(config.logfile) - 1);
3653 }
3654 else if ( configp->logcommon == YES ) {
3655 strncat(configp->logfile, ".common",
3656 sizeof(config.logfile) - 1 - strlen(configp->logfile));
3657 if ( configp->disp_subdir == NO_ANSWER )
3658 configp->disp_subdir = YES;
3659 }
3660 else {
3661 strncat(configp->logfile, configp->suffix,
3662 sizeof(config.logfile) - 1 - strlen(configp->logfile));
3663 }
3664
3665 /* If not set above */
3666 if ( configp->disp_subdir == NO_ANSWER )
3667 configp->disp_subdir = NO;
3668
3669 if ( configp->hide_unchanged_inactive == NO_ANSWER )
3670 configp->hide_unchanged_inactive = configp->hide_unchanged;
3671
3672 create_file_paths();
3673
3674 if ( access(configp->logfile, F_OK) == 0 &&
3675 access(configp->logfile, W_OK) != 0 ) {
3676 sprintf(errmsg, "Log file '%s' is not writable - check permissions.",
3677 configp->logfile);
3678 store_error_message(errmsg);
3679 return 1;
3680 }
3681
3682 if ( access(statefile, F_OK) == 0 &&
3683 access(statefile, W_OK) != 0 ) {
3684 sprintf(errmsg, "State file '%s' is not writable - check permissions.",
3685 statefile);
3686 store_error_message(errmsg);
3687 return 1;
3688 }
3689
3690 for ( j = 0; j < nrflabels; j++ ) {
3691 if ( configp->rf_bursts[j] > configp->def_rf_bursts ) {
3692 sprintf(errmsg, "RF_BURSTS exceeds %d\n", configp->def_rf_bursts);
3693 store_error_message(errmsg);
3694 return 1;
3695 }
3696 }
3697
3698
3699 if ( configp->transceive & configp->rfforward ) {
3700 store_error_message("Housecode conflict in TRANSCEIVE and RFFORWARD");
3701 return 1;
3702 }
3703
3704 if ( configp->device_type == DEV_DUMMY )
3705 configp->lockup_check = 0;
3706
3707 assign_data_storage();
3708
3709 create_oregon_ignore_list();
3710 create_security_ignore_list();
3711
3712 set_elec1_nvar(configp->els_number);
3713
3714
3715 #ifdef HASRFXM
3716 create_rfxpower_panels();
3717 #endif
3718
3719 if ( finalize_launchers() > 0 )
3720 return 1;
3721
3722 return 0;
3723 }
3724
3725
3726 /*---------------------------------------------------------------------+
3727 | Add an alias to the array of ALIAS structures and return the index |
3728 | of the new member. |
3729 +---------------------------------------------------------------------*/
add_alias(ALIAS ** aliaspp,char * label,int line_no,char housecode,char * units,int modtype)3730 int add_alias ( ALIAS **aliaspp, char *label, int line_no,
3731 char housecode, char *units, int modtype )
3732 {
3733 static int size, max_size;
3734 static int strucsize = sizeof(ALIAS);
3735 int j, k, maxlevel;
3736 int blksize = 10;
3737 char hc;
3738 unsigned int bmap;
3739 unsigned long vflags, flags, xflags, kflags;
3740 char errmsg[128];
3741 int (*module_xlate_func(int index))();
3742
3743 clear_error_message();
3744
3745 /* Allocate initial block of memory */
3746 if ( *aliaspp == NULL ) {
3747 *aliaspp = (ALIAS *) calloc(blksize, strucsize );
3748 if ( *aliaspp == NULL ) {
3749 (void) fprintf(stderr, "Unable to allocate memory for Alias.\n");
3750 exit(1);
3751 }
3752 max_size = blksize;
3753 size = 0;
3754 /* Initialize it where necessary */
3755 for ( j = 0; j < max_size; j++ ) {
3756 (*aliaspp)[j].label[0] = '\0';
3757 (*aliaspp)[j].modtype = -1;
3758 (*aliaspp)[j].line_no = 0;
3759 (*aliaspp)[j].vflags = 0;
3760 (*aliaspp)[j].flags = 0;
3761 (*aliaspp)[j].xflags = 0;
3762 (*aliaspp)[j].kflags = 0;
3763 (*aliaspp)[j].optflags = 0;
3764 (*aliaspp)[j].optflags2 = 0;
3765 (*aliaspp)[j].tmin = 0;
3766 (*aliaspp)[j].tmax = 0;
3767 (*aliaspp)[j].rhmin = 0;
3768 (*aliaspp)[j].rhmax = 0;
3769 for ( k = 0; k < NOFFSET; k++ )
3770 (*aliaspp)[j].offset[k] = 0.0;
3771 (*aliaspp)[j].vtype = 0;
3772 (*aliaspp)[j].subtype = 0;
3773 (*aliaspp)[j].nident = 0;
3774 for ( k = 0; k < NIDENT; k++ ) {
3775 (*aliaspp)[j].ident[k] = 0;
3776 (*aliaspp)[j].kaku_keymap[k] = 0;
3777 (*aliaspp)[j].kaku_grpmap[k] = 0;
3778 }
3779 (*aliaspp)[j].xlate_func = NULL;
3780 // (*aliaspp)[j].timeout = 0;
3781 (*aliaspp)[j].hb_timeout = -1L;
3782 (*aliaspp)[j].hb_index = -1;
3783 (*aliaspp)[j].nvar = 0;
3784 (*aliaspp)[j].storage_index = -1;
3785 (*aliaspp)[j].storage_units = 0;
3786 for ( k = 0; k < NFUNCLIST; k++ ) {
3787 (*aliaspp)[j].funclist[k] = 0xff;
3788 (*aliaspp)[j].statusoffset[k] = k;
3789 }
3790 (*aliaspp)[j].ext0links = 0;
3791 }
3792 }
3793
3794 /* Check for a valid label length */
3795 if ( (int)strlen(label) > NAME_LEN ) {
3796 sprintf(errmsg,
3797 "Alias label '%s' too long - maximum %d characters", label, NAME_LEN);
3798 store_error_message(errmsg);
3799 return -1;
3800 }
3801
3802 /* See if the alias label is already in the list. */
3803 /* If so, it's an error. */
3804 if ( (j = get_alias(*aliaspp, label, &hc, &bmap)) >= 0 ) {
3805 (void) sprintf(errmsg, "Duplicate alias label '%s'", label);
3806 store_error_message(errmsg);
3807 return -1;
3808 }
3809
3810 /* Verify that the label is not 'macro' */
3811 if ( strcmp(label, "macro") == 0 ) {
3812 store_error_message("An alias may not have the label 'macro'\n");
3813 return -1;
3814 }
3815
3816 /* Check the housecode */
3817 if ( housecode == '_' ) {
3818 (void) sprintf(errmsg,
3819 "Alias '%s': Default housecode symbol ('_') is invalid in an alias",
3820 label);
3821 store_error_message(errmsg);
3822 return -1;
3823 }
3824 if ( (hc = toupper((int)housecode)) < 'A' || hc > 'P' ) {
3825 (void) sprintf(errmsg, "Alias '%s': Housecode '%c' outside range A-P",
3826 label, hc);
3827 store_error_message(errmsg);
3828 return -1;
3829 }
3830
3831 /* Check the units list */
3832 if ( parse_units( units, &bmap ) != 0 ) {
3833 (void) sprintf(errmsg, "Alias '%s': ", label);
3834 add_error_prefix(errmsg);
3835 return -1;
3836 }
3837
3838 /* Check to see that the module type (if any) specified for */
3839 /* this housecode|unit address doesn't conflict with that */
3840 /* in a previously defined alias. */
3841
3842 if ( modtype >= 0 ) {
3843 j = 0;
3844 while ( (*aliaspp)[j].line_no > 0 ) {
3845 if ( (*aliaspp)[j].housecode == hc && (*aliaspp)[j].unitbmap & bmap &&
3846 (*aliaspp)[j].modtype >= 0 ) {
3847 if ( (*aliaspp)[j].modtype != modtype ) {
3848 sprintf(errmsg,
3849 "Module type conflicts with that defined for %c%s on Line %d",
3850 hc, bmap2units((*aliaspp)[j].unitbmap & bmap),
3851 (*aliaspp)[j].line_no);
3852 store_error_message(errmsg);
3853 return -1;
3854 }
3855 }
3856 j++;
3857 }
3858 }
3859
3860 #if 0
3861 if ( modtype >= 0 ) {
3862 j = 0;
3863 while ( (*aliaspp)[j].line_no > 0 ) {
3864 if ( (*aliaspp)[j].housecode == hc && (*aliaspp)[j].unitbmap & bmap &&
3865 (*aliaspp)[j].modtype >= 0 && (*aliaspp)[j].modtype != modtype ) {
3866 sprintf(errmsg,
3867 "Module type conflicts with that defined for %c%s on Line %d",
3868 hc, bmap2units((*aliaspp)[j].unitbmap & bmap),
3869 (*aliaspp)[j].line_no);
3870 store_error_message(errmsg);
3871 return -1;
3872 }
3873 j++;
3874 }
3875 }
3876 #endif
3877
3878 /* Check to see if there's an available location */
3879 /* If not, increase the size of the memory allocation. */
3880 /* (Always leave room for a final termination indicator.) */
3881 if ( size == (max_size - 1)) {
3882 max_size += blksize ;
3883 *aliaspp = (ALIAS *) realloc(*aliaspp, max_size * strucsize );
3884 if ( *aliaspp == NULL ) {
3885 (void) fprintf(stderr, "Unable to increase size of Alias list.\n");
3886 exit(1);
3887 }
3888
3889 /* Initialize the new memory allocation */
3890 for ( j = size; j < max_size; j++ ) {
3891 (*aliaspp)[j].label[0] = '\0';
3892 (*aliaspp)[j].modtype = -1;
3893 (*aliaspp)[j].line_no = 0;
3894 (*aliaspp)[j].vflags = 0;
3895 (*aliaspp)[j].flags = 0;
3896 (*aliaspp)[j].xflags = 0;
3897 (*aliaspp)[j].kflags = 0;
3898 (*aliaspp)[j].optflags = 0;
3899 (*aliaspp)[j].optflags2 = 0;
3900 (*aliaspp)[j].tmin = 0;
3901 (*aliaspp)[j].tmax = 0;
3902 (*aliaspp)[j].rhmin = 0;
3903 (*aliaspp)[j].rhmax = 0;
3904 for ( k = 0; k < NOFFSET; k++ )
3905 (*aliaspp)[j].offset[k] = 0.0;
3906 (*aliaspp)[j].vtype = 0;
3907 (*aliaspp)[j].subtype = 0;
3908 (*aliaspp)[j].nident = 0;
3909 for ( k = 0; k < NIDENT; k++ ) {
3910 (*aliaspp)[j].ident[k] = 0;
3911 (*aliaspp)[j].kaku_keymap[k] = 0;
3912 (*aliaspp)[j].kaku_grpmap[k] = 0;
3913 }
3914 (*aliaspp)[j].xlate_func = NULL;
3915 // (*aliaspp)[j].timeout = 0;
3916 (*aliaspp)[j].hb_timeout = -1L;
3917 (*aliaspp)[j].hb_index = -1;
3918 (*aliaspp)[j].nvar = 0;
3919 (*aliaspp)[j].storage_index = -1;
3920 (*aliaspp)[j].storage_units = 0;
3921 for ( k = 0; k < NFUNCLIST; k++ ) {
3922 (*aliaspp)[j].funclist[k] = 0xff;
3923 (*aliaspp)[j].statusoffset[k] = k;
3924 }
3925 (*aliaspp)[j].ext0links = 0;
3926 }
3927 }
3928
3929 j = size;
3930 size += 1;
3931
3932 (void) strncpy2((*aliaspp)[j].label, label, NAME_LEN);
3933 (*aliaspp)[j].line_no = line_no;
3934 (*aliaspp)[j].housecode = toupper((int)housecode);
3935 (*aliaspp)[j].hcode = hc2code(housecode);
3936 (*aliaspp)[j].unitbmap = bmap;
3937 (*aliaspp)[j].modtype = modtype;
3938 module_attributes(modtype, &vflags, &flags, &xflags, &kflags, &maxlevel);
3939 (*aliaspp)[j].vflags = vflags;
3940 (*aliaspp)[j].flags = flags;
3941 (*aliaspp)[j].xflags = xflags;
3942 (*aliaspp)[j].kflags = kflags;
3943 (*aliaspp)[j].maxlevel = maxlevel;
3944 (*aliaspp)[j].onlevel = maxlevel;
3945 (*aliaspp)[j].xlate_func = module_xlate_func(modtype);
3946
3947 return j;
3948 }
3949
3950 /*---------------------------------------------------------------------+
3951 | Add a scene or usersyn to the array of SCENE structures and return |
3952 | the index of the new member. |
3953 | Argument 'type' may be 1 for a scene or 2 for a usersyn |
3954 +---------------------------------------------------------------------*/
add_scene(SCENE ** scenepp,char * label,int line_no,char * body,unsigned int type)3955 int add_scene ( SCENE **scenepp, char *label,
3956 int line_no, char *body, unsigned int type )
3957 {
3958 static int size, max_size ;
3959 static int strucsize = sizeof(SCENE);
3960 int j;
3961 char *sp;
3962 int cmdc, nparms;
3963 char **cmdv;
3964 int blksize = 10;
3965 char errmsg[128];
3966 extern char *typename[];
3967
3968 /* Allocate initial block of memory */
3969 if ( *scenepp == NULL ) {
3970 *scenepp = calloc(blksize, strucsize );
3971 if ( *scenepp == NULL ) {
3972 fprintf(stderr, "Unable to allocate memory for Scene/Usersyn.\n");
3973 exit(1);
3974 }
3975 max_size = blksize;
3976 size = 0;
3977 /* Initialize it */
3978 for ( j = 0; j < max_size; j++ ) {
3979 (*scenepp)[j].label[0] = '\0';
3980 (*scenepp)[j].line_no = -1;
3981 (*scenepp)[j].nparms = 0;
3982 (*scenepp)[j].type = 0;
3983 (*scenepp)[j].body = NULL;
3984 }
3985 }
3986
3987 /* Check for a valid scene label */
3988 if ( (int)strlen(label) > SCENE_LEN ) {
3989 sprintf(errmsg,
3990 "%s label too long - maximum %d characters", typename[type], SCENE_LEN);
3991 store_error_message(errmsg);
3992 return -1;
3993 }
3994 if ( strchr("+_-", *label) != NULL ) {
3995 sprintf(errmsg, "%s label may not may not begin with '+', '-' or '_'", typename[type]);
3996 store_error_message(errmsg);
3997 return -1;
3998 }
3999 if ( strchr(label, '$') != NULL ) {
4000 sprintf(errmsg, "%s label may not contain the '$' character", typename[type]);
4001 store_error_message(errmsg);
4002 return -1;
4003 }
4004 if ( strchr(label, ';') != NULL ) {
4005 sprintf(errmsg, "%s label may not contain the ';' character", typename[type]);
4006 store_error_message(errmsg);
4007 return -1;
4008 }
4009
4010 /* See if the scene label is already in the list. */
4011 /* If so, it's an error. */
4012 if ( (j = lookup_scene(*scenepp, label)) >= 0 ) {
4013 sprintf(errmsg,
4014 "%s label '%s' previously defined as a %s on line %d",
4015 typename[type], label, typename[(*scenepp)[j].type], (*scenepp)[j].line_no);
4016 store_error_message(errmsg);
4017 return -1;
4018 }
4019
4020 if ( is_admin_cmd(label) || is_direct_cmd(label) ) {
4021 sprintf(errmsg, "%s label '%s' conflicts with heyu command", typename[type], label);
4022 store_error_message(errmsg);
4023 return -1;
4024 }
4025
4026 /* Check to see if there's an available location */
4027 /* If not, increase the size of the memory allocation. */
4028 /* (Always leave room for a final termination indicator.) */
4029 if ( size == (max_size - 1)) {
4030 max_size += blksize ;
4031 *scenepp = realloc(*scenepp, max_size * strucsize );
4032 if ( *scenepp == NULL ) {
4033 fprintf(stderr, "Unable to increase size of Scene/Usersyn list.\n");
4034 exit(1);
4035 }
4036
4037 /* Initialize the new memory allocation */
4038 for ( j = size; j < max_size; j++ ) {
4039 (*scenepp)[j].label[0] = '\0';
4040 (*scenepp)[j].line_no = -1;
4041 (*scenepp)[j].nparms = 0;
4042 (*scenepp)[j].type = 0;
4043 (*scenepp)[j].body = NULL;
4044 }
4045 }
4046
4047 j = size;
4048 size += 1;
4049
4050 /* Determine the number of replaceable parameters */
4051 sp = strdup(body);
4052 tokenize(sp, " \t;", &cmdc, &cmdv);
4053 nparms = max_parms(cmdc, cmdv);
4054 free(sp);
4055 free(cmdv);
4056 if ( *error_message() != '\0' ) {
4057 sprintf(errmsg, "%s '%s': ", typename[type], label);
4058 add_error_prefix(errmsg);
4059 }
4060 if ( nparms < 0 )
4061 return -1;
4062
4063 sp = strdup(body);
4064 if ( sp == NULL ) {
4065 fprintf(stderr,
4066 "Unable to allocate memory for body of Scene/Usersyn '%s'.\n", label);
4067 exit(1);
4068 }
4069 strtrim(sp);
4070
4071 (void) strncpy2((*scenepp)[j].label, label, SCENE_LEN);
4072 (*scenepp)[j].line_no = line_no;
4073 (*scenepp)[j].nparms = nparms;
4074 (*scenepp)[j].type = type;
4075 (*scenepp)[j].body = sp;
4076
4077 return j;
4078 }
4079
4080 /*---------------------------------------------------------------------+
4081 | Parse Latitude string [NS+-]ddd:mm and store in struct config. |
4082 | line_no <= 0 indicates string from environment, otherwise line in |
4083 | configuration file. |
4084 +---------------------------------------------------------------------*/
parse_latitude(char * string)4085 int parse_latitude ( char *string )
4086 {
4087 char tmpbuff[128];
4088 char *sp1, *sp2;
4089 int sign;
4090
4091 if ( string == NULL )
4092 return 0;
4093
4094 (void)strncpy2(tmpbuff, string, sizeof(tmpbuff) - 1);
4095 sp1 = tmpbuff;
4096
4097 /* For compatibility with Heyu 1 */
4098 if ( isdigit((int)(*sp1)) ) {
4099 (void)strcpy(tmpbuff, "N");
4100 (void)strncpy2(tmpbuff + 1, string, sizeof(tmpbuff) - 2);
4101 }
4102 else if ( *sp1 == '+' ) {
4103 *sp1 = 'N';
4104 }
4105 else if ( *sp1 == '-' ) {
4106 *sp1 = 'S';
4107 }
4108
4109 switch ( toupper((int)(*sp1)) ) {
4110 case 'N' :
4111 sign = 1;
4112 break;
4113 case 'S' :
4114 sign = -1;
4115 break;
4116 default :
4117 sign = -2;
4118 break;
4119 }
4120 sp1++;
4121
4122 if ( sign < -1 || !(sp2 = strchr(sp1, ':')) ) {
4123 store_error_message("LATITUDE invalid - must be [NS+-]dd:mm");
4124 configp->loc_flag &= ~(LATITUDE) ;
4125 return 1;
4126 }
4127
4128 configp->lat_m = (int)strtol(sp2 + 1, NULL, 10);
4129 *sp2 = '\0';
4130 configp->lat_d = (int)strtol(sp1, NULL, 10);
4131 if ( configp->lat_d == 0 )
4132 configp->lat_m *= sign ;
4133 else
4134 configp->lat_d *= sign ;
4135
4136 configp->latitude = ( configp->lat_d < 0 ) ?
4137 (double)configp->lat_d - (double)configp->lat_m/60. :
4138 (double)configp->lat_d + (double)configp->lat_m/60.;
4139
4140 if ( configp->latitude < -89. || configp->latitude > 89. ) {
4141 store_error_message("LATITUDE outside range -89 to +89 degrees");
4142 configp->loc_flag &= ~(LATITUDE);
4143 return 1;
4144 }
4145
4146 configp->loc_flag |= LATITUDE ;
4147
4148 return 0;
4149 }
4150
4151 /*---------------------------------------------------------------------+
4152 | Parse Longitude string [EW+-]ddd:mm and store in struct config. |
4153 | line_no <= 0 indicates string from environment, otherwise line in |
4154 | configuration file. |
4155 +---------------------------------------------------------------------*/
parse_longitude(char * string)4156 int parse_longitude ( char *string )
4157 {
4158 char tmpbuff[128];
4159 char *sp1, *sp2;
4160 int sign;
4161
4162 if ( string == NULL )
4163 return 0;
4164
4165 (void)strncpy2(tmpbuff, string, sizeof(tmpbuff) - 1);
4166 sp1 = tmpbuff;
4167
4168 /* For compatibility with Heyu 1, where positive longitude assumed West */
4169 if ( isdigit((int)(*sp1)) ) {
4170 (void)strcpy(tmpbuff, "W");
4171 (void)strncpy2(tmpbuff + 1, string, sizeof(tmpbuff) - 2);
4172 }
4173 else if ( *sp1 == '+' ) {
4174 *sp1 = 'W';
4175 }
4176 else if ( *sp1 == '-' ) {
4177 *sp1 = 'E';
4178 }
4179
4180 switch ( toupper((int)(*sp1)) ) {
4181 case 'E' :
4182 sign = 1;
4183 break;
4184 case 'W' :
4185 sign = -1;
4186 break;
4187 default :
4188 sign = -2;
4189 break;
4190 }
4191 sp1++;
4192
4193 if ( sign < -1 || !(sp2 = strchr(sp1, ':')) ) {
4194 store_error_message("LONGITUDE invalid - must be [EW+-]dd:mm");
4195 configp->loc_flag &= ~(LONGITUDE) ;
4196 return 1;
4197 }
4198
4199 configp->lon_m = (int)strtol(sp2 + 1, NULL, 10);
4200 *sp2 = '\0';
4201 configp->lon_d = (int)strtol(sp1, NULL, 10);
4202 if ( configp->lon_d == 0 )
4203 configp->lon_m *= sign ;
4204 else
4205 configp->lon_d *= sign ;
4206
4207 configp->longitude = ( configp->lon_d < 0 ) ?
4208 (double)configp->lon_d - (double)configp->lon_m/60. :
4209 (double)configp->lon_d + (double)configp->lon_m/60.;
4210
4211 if ( configp->longitude < -180. || configp->longitude > 180. ) {
4212 store_error_message("LONGITUDE outside range -180 to +180 degrees");
4213 configp->loc_flag &= ~(LONGITUDE);
4214 return 1;
4215 }
4216
4217 configp->loc_flag |= LONGITUDE ;
4218
4219 return 0;
4220 }
4221
4222 /*---------------------------------------------------------------------+
4223 | Check executability of a file on user's PATH |
4224 +---------------------------------------------------------------------*/
is_executable(char * pathname)4225 int is_executable ( char *pathname )
4226 {
4227 char pathbuffer[1024];
4228 char buffer[1024];
4229 char *sp;
4230 int j, tokc;
4231 char **tokv;
4232
4233 if ( access(pathname, X_OK) == 0 )
4234 return 1;
4235
4236 if ( (sp = getenv("PATH")) == NULL )
4237 return 0;
4238
4239 strncpy2(pathbuffer, sp, sizeof(pathbuffer) - 1);
4240
4241 tokenize(buffer, ":", &tokc, &tokv);
4242
4243 for ( j = 0; j < tokc; j++ ) {
4244 strncpy2(buffer, tokv[j], sizeof(buffer) - 1);
4245 strncat(buffer, "/", sizeof(buffer) - 1 - strlen(buffer));
4246 strncat(buffer, pathname, sizeof(buffer) - 1 - strlen(buffer));
4247 if ( access(buffer, X_OK) == 0 ) {
4248 free(tokv);
4249 return 1;
4250 }
4251 }
4252 free(tokv);
4253 return 0;
4254 }
4255
4256 /*---------------------------------------------------------------------+
4257 | Free memory allocated for SCRIPT structure and contents. |
4258 +---------------------------------------------------------------------*/
free_scripts(SCRIPT ** scriptpp)4259 void free_scripts ( SCRIPT **scriptpp )
4260 {
4261 int j = 0;
4262
4263 if ( *scriptpp == NULL )
4264 return;
4265
4266 while ( (*scriptpp)[j].line_no > 0 ) {
4267 if ( (*scriptpp)[j].cmdline ) {
4268 free((*scriptpp)[j].cmdline);
4269 }
4270 j++;
4271 }
4272 free(*scriptpp);
4273 *scriptpp = NULL;
4274
4275 return;
4276 }
4277
4278 /*---------------------------------------------------------------------+
4279 | Free the array of SCENEs and the scene bodies therein. |
4280 +---------------------------------------------------------------------*/
free_scenes(SCENE ** scenepp)4281 void free_scenes ( SCENE **scenepp )
4282 {
4283 int j = 0;
4284
4285 if ( *scenepp == NULL )
4286 return;
4287
4288 while ( (*scenepp)[j].line_no > 0 ) {
4289 if ( (*scenepp)[j].body != NULL ) {
4290 free((*scenepp)[j].body);
4291 }
4292 j++;
4293 }
4294
4295 free((*scenepp));
4296 *scenepp = NULL;
4297 return;
4298 }
4299
4300 /*---------------------------------------------------------------------+
4301 | Free the array of ALIASES. |
4302 +---------------------------------------------------------------------*/
free_aliases(ALIAS ** aliaspp)4303 void free_aliases ( ALIAS **aliaspp )
4304 {
4305 if ( *aliaspp == NULL )
4306 return;
4307
4308 free((*aliaspp));
4309 *aliaspp = NULL;
4310 return;
4311 }
4312
4313 /*---------------------------------------------------------------------+
4314 | Free the array of LAUNCHERS. |
4315 +---------------------------------------------------------------------*/
free_launchers(LAUNCHER ** launcherpp)4316 void free_launchers ( LAUNCHER **launcherpp )
4317 {
4318 if ( *launcherpp == NULL )
4319 return;
4320
4321 free((*launcherpp));
4322 *launcherpp = NULL;
4323 return;
4324 }
4325
4326 /*---------------------------------------------------------------------+
4327 | Free the relay powerfail script. |
4328 +---------------------------------------------------------------------*/
free_relay_powerfail_script(char ** pfail_script)4329 void free_relay_powerfail_script ( char **pfail_script )
4330 {
4331 if ( *pfail_script == NULL )
4332 return;
4333
4334 free(*pfail_script);
4335 *pfail_script = NULL;
4336 return;
4337 }
4338
4339 /*---------------------------------------------------------------------+
4340 | Free arrays of ALIASes, SCENEs, SCRIPTs, and LAUNCHERs |
4341 +---------------------------------------------------------------------*/
free_all_arrays(CONFIG * configp)4342 void free_all_arrays ( CONFIG *configp )
4343 {
4344 free_aliases(&configp->aliasp);
4345 free_scenes(&configp->scenep);
4346 free_scripts(&configp->scriptp);
4347 free_launchers(&configp->launcherp);
4348 free_relay_powerfail_script(&configp->pfail_script);
4349
4350 return;
4351 }
4352
4353 /*---------------------------------------------------------------------+
4354 | Create the file pathspecs for many files. |
4355 +---------------------------------------------------------------------*/
create_file_paths(void)4356 int create_file_paths ( void )
4357 {
4358 sprintf(statefile, "%s", pathspec(STATE_FILE));
4359 sprintf(enginelockfile, "%s/LCK..%s%s", LOCKDIR, STATE_LOCKFILE, configp->suffix);
4360
4361 #if 0 /* future */
4362 sprintf(spoolfile, "%s/%s%s", SPOOLDIR, SPOOLFILE, configp->suffix);
4363 sprintf(relaylockfile, "%s/LCK..%s%s", LOCKDIR, RELAYFILE, configp->suffix);
4364 sprintf(writelockfile, "%s/LCK..%s%s", LOCKDIR, WRITEFILE, configp->suffix);
4365 sprintf(ttylockfile, "%s/LCK.%s", LOCKDIR, configp->suffix);
4366 #endif /* future */
4367
4368 return 0;
4369 }
4370
4371 /*---------------------------------------------------------------------+
4372 | Open the user's X10 configuration file and call parse_config() to |
4373 | parse it and fill in global structure config. exit(1) is called |
4374 | if the file cannot be found or read, or if it contains errors. |
4375 +---------------------------------------------------------------------*/
get_configuration(unsigned char mode)4376 int get_configuration ( unsigned char mode )
4377 {
4378
4379 FILE *fd ;
4380 int error_count;
4381 char confp[PATH_LEN + 1];
4382 CONFIG configtmp;
4383
4384 /* Return if the configuration file has already been read into memory */
4385 if ( config.read_flag != 0 ) {
4386 return 0;
4387 }
4388
4389 configp = &configtmp;
4390
4391 find_heyu_path();
4392
4393 strncpy2(confp, pathspec(heyu_config), sizeof(confp) - 1);
4394
4395 if ( verbose )
4396 (void) fprintf(stdout,
4397 "Reading Heyu configuration file '%s'\n", confp);
4398
4399 if ( !(fd = fopen(confp, "r")) ) {
4400 if ( !i_am_relay )
4401 fprintf(stderr, "Unable to find (or open) Heyu configuration file '%s'\n", confp);
4402 else
4403 syslog(LOG_ERR, "Unable to find (or open) Heyu configuration file '%s'\n", confp);
4404
4405 exit(1);
4406 }
4407
4408 setup_countdown_timers();
4409
4410 error_count = parse_config( fd, mode );
4411
4412 (void) fclose( fd );
4413
4414 if ( error_count != 0 ) {
4415 if ( mode == CONFIG_RESTART && (i_am_aux || i_am_relay) ) {
4416 return error_count;
4417 }
4418 else {
4419 (void)fprintf(stderr,
4420 "Quitting due to errors in configuration file '%s'\n", confp);
4421 exit(1);
4422 }
4423 }
4424
4425 return 0;
4426 }
4427
4428 /*---------------------------------------------------------------------+
4429 | Parse a time string X:Y:Z and return the total time represented by |
4430 | 3600*X + 60*Y + Z, or -1 if error. With X:Y:Z = hh:mm:ss the value |
4431 | returned will typically represent seconds. With just Y:Z the value |
4432 | returned can be interpreted as either hh:mm or mm:ss depending on |
4433 | the context. A null field or empty field, i.e., "::" or ": :" is |
4434 | flagged as an error, as is a trailing ':'. |
4435 +---------------------------------------------------------------------*/
parse_hhmmss(char * hhmmss,int maxfields)4436 long parse_hhmmss ( char *hhmmss, int maxfields )
4437 {
4438 int j, tokc;
4439 long value, seconds = 0;
4440 char **tokv;
4441 char *sp;
4442 char buf[32];
4443
4444 if ( strstr(hhmmss, "::") != NULL ||
4445 *(hhmmss + strlen(hhmmss) - 1) == ':' ||
4446 strlen(hhmmss) > (sizeof(buf) - 1) ) {
4447 return -1;
4448 }
4449
4450 strcpy(buf, hhmmss);
4451
4452 tokenize(buf, ":", &tokc, &tokv );
4453
4454 if ( tokc > maxfields ) {
4455 free(tokv);
4456 return -1;
4457 }
4458
4459 for ( j = 0; j < tokc; j++ ) {
4460 if ( *strtrim(tokv[j]) == '\0' ) {
4461 free(tokv);
4462 return -1;
4463 }
4464 else {
4465 value = strtol(tokv[j], &sp, 10);
4466 if ( strchr(" \t\n", *sp) == NULL ) {
4467 free(tokv);
4468 return -1;
4469 }
4470 }
4471 seconds = 60 * seconds + value;
4472 }
4473 free(tokv);
4474 return seconds;
4475 }
4476
4477 /*---------------------------------------------------------------------+
4478 | Verify unique IDs for Sec, Ent or RFXSensor modules |
4479 +---------------------------------------------------------------------*/
verify_unique_ids(unsigned char vtype)4480 int verify_unique_ids ( unsigned char vtype )
4481 {
4482 ALIAS *aliasp;
4483 unsigned short ident, mask;
4484 int j, k;
4485 char errmsg[160];
4486 int ntable, dupes;
4487
4488 struct idtable_st {
4489 unsigned short ident;
4490 int index;
4491 } idtable[512];
4492
4493 if ( !(aliasp = configp->aliasp) )
4494 return 0;
4495
4496 mask = (vtype == RF_SEC) ? configp->securid_mask :
4497 (vtype == RF_OREGON) ? configp->oreid_mask : 0xffffu;
4498
4499 strcpy(errmsg, "The same ID appears in ALIASes:");
4500
4501 ntable = 0;
4502 j = 0;
4503 while ( aliasp[j].line_no > 0 ) {
4504 if ( aliasp[j].vtype == vtype ) {
4505 for ( k = 0; k < aliasp[j].nident; k++ ) {
4506 idtable[ntable].ident = aliasp[j].ident[k] & mask;
4507 idtable[ntable++].index = j;
4508 }
4509 }
4510 j++;
4511 }
4512
4513 dupes = 0;
4514 for ( j = 0; j < ntable; j++ ) {
4515 ident = idtable[j].ident;
4516 for ( k = j + 1; k < ntable; k++ ) {
4517 if ( idtable[k].ident == ident ) {
4518 dupes++;
4519 snprintf(errmsg + strlen(errmsg), sizeof(errmsg) - 1, " (%s %s)",
4520 aliasp[idtable[j].index].label, aliasp[idtable[k].index].label);
4521 }
4522 }
4523 }
4524
4525 if ( dupes > 0 ) {
4526 store_error_message(errmsg);
4527 return 1;
4528 }
4529
4530 return 0;
4531 }
4532
4533 /*---------------------------------------------------------------------+
4534 | Display configuration file stripped of comments and blank lines. |
4535 +---------------------------------------------------------------------*/
show_configuration(void)4536 void show_configuration ( void )
4537 {
4538 FILE *fd ;
4539 char confp[PATH_LEN + 1];
4540 char buffer[LINE_LEN];
4541 char *sp;
4542
4543 get_configuration(CONFIG_INIT);
4544
4545 find_heyu_path();
4546
4547 strncpy2(confp, pathspec(heyu_config), sizeof(confp) - 1);
4548
4549 if ( !(fd = fopen(confp, "r")) ) {
4550 exit(1);
4551 }
4552
4553 while ( fgets(buffer, sizeof(buffer), fd) != NULL ) {
4554 if ( (sp = strchr(buffer, '#')) != NULL )
4555 *sp = '\0';
4556 strtrim(buffer);
4557 if ( *buffer )
4558 printf("%s\n", buffer);
4559 }
4560
4561 (void) fclose( fd );
4562 return;
4563 }
4564
display_webhook_usage(void)4565 void display_webhook_usage ( void )
4566 {
4567 printf("Usage: heyu webhook <option> -L[fmt] -d|D[fmt] -m|M[fmt] -b[fmt] -ce<list> -nb<repl> [category]\n");
4568 printf("options:\n");
4569 printf(" fileinfo Deprecated - use pathinfo\n");
4570 printf(" menuinfo Deprecated - use helpinfo\n");
4571 printf(" pathinfo Display pathspecs for Heyu config and log files.\n");
4572 printf(" flaginfo Display flags, czflags, or tzflags as long ASCII bitmap.\n");
4573 printf(" flagbankinfo Display flags, czflags, or tzflags as multiple banks of 32.\n");
4574 printf(" helpinfo Display available help menu commands\n");
4575 printf(" config_dump Display display configuration file directives.\n");
4576 printf(" maskinfo Display masks for environment variable $X10_Hu\n");
4577 printf(" flagmaskinfo Display masks for environment variable $X10_Hu_vFlags\n");
4578 printf("switches:\n");
4579 printf(" -L Prefix with formatted line number in configuration file.\n");
4580 printf(" -d |-D Display formatted directive label in lower | upper case.\n");
4581 printf(" -m |-M Format multiple directive label numbering beginning with 0 | 1\n");
4582 printf(" -b Format body of directive.\n");
4583 printf(" -ce Characters in <list> are escaped in script command lines.\n");
4584 printf(" -nb Null body is replaced by <repl>.\n");
4585 printf("The format specification %%V must appear in each format string ([fmt]) where\n");
4586 printf("it is replaced as appropriate by the line number, directive label, label number,\n");
4587 printf("or directive body.\n");
4588 printf("\n");
4589 printf("categories for config_dump:\n");
4590 printf(" alias\n");
4591 printf(" usersyn\n");
4592 printf(" scene\n");
4593 printf(" script\n");
4594 printf(" other (Everything other than the above directives.)\n");
4595 printf(" <blank> (Everything.)\n");
4596 printf("categories for pathinfo:\n");
4597 printf(" conf Configuration file pathspec.\n");
4598 printf(" log Logfile pathspec.\n");
4599 printf(" <blank> Both the above.\n");
4600 printf("categories for flaginfo and flagbankinfo:\n");
4601 printf(" flags Common flags.\n");
4602 printf(" czflags Counter-zero flags.\n");
4603 printf(" tzflags Timer-zero flags.\n");
4604 printf("Example:\n");
4605 printf(" heyu webhook config_dump -L\"%%V: \" -dheyu_%%V -m\\(%%V\\) -b=\\\"%%V\\\" alias\n");
4606 printf("yields:\n");
4607 printf(" 13: heyu_alias(2)=\"porch_light A7 StdWS\"\n");
4608 printf("\n");
4609 return;
4610 }
4611
flags2asciimap(char * asciimap,unsigned long flags)4612 int flags2asciimap ( char *asciimap, unsigned long flags )
4613 {
4614 int j;
4615
4616 for ( j = 0; j < 32; j++ ) {
4617 asciimap[j] = (flags & (1 << j)) ? '1' : '0';
4618 }
4619 asciimap[32] = '\0';
4620
4621 return 0;
4622 }
4623
allflags2asciimap(char * asciimap,unsigned long * flags,int num_banks)4624 int allflags2asciimap ( char *asciimap, unsigned long *flags, int num_banks )
4625 {
4626 int j, k, bank;
4627
4628 k = 0;
4629 for ( bank = 0; bank < num_banks; bank++ ) {
4630 for ( j = 0; j < 32; j++ ) {
4631 asciimap[k++] = (flags[bank] & (1 << j)) ? '1' : '0';
4632 }
4633 }
4634 asciimap[k++] = '\0';
4635
4636 return 0;
4637 }
4638
4639
4640 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++
4641 | START WEBHOOK SECTION |
4642 +++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
4643
4644 #define WF_LINE 0x00000001
4645 #define WF_UPPER 0x00000002
4646 #define WF_MULT 0x00000004
4647 #define WF_ESC 0x00000008
4648 #define WF_ALIAS 0x00000010
4649 #define WF_USYN 0x00000020
4650 #define WF_SCENE 0x00000040
4651 #define WF_SCRIPT 0x00000080
4652 #define WF_OTHER 0x00000100
4653 #define WF_CONF 0x00000200
4654 #define WF_LOG 0x00000400
4655 #define WF_NULLBODY 0x00000800
4656 #define WF_FLAGS 0x00001000
4657 #define WF_CZFLAGS 0x00002000
4658 #define WF_TZFLAGS 0x00004000
4659 #define WF_MASKS 0x00008000
4660
4661 #define WF_ALLCAT (WF_ALIAS | WF_USYN | WF_SCENE | WF_SCRIPT | WF_OTHER)
4662
4663 typedef struct {
4664 char label[NAME_LEN + 1];
4665 int index;
4666 } MULTI;
4667
4668 typedef struct {
4669 char label[NAME_LEN + 1];
4670 } IGNLIST;
4671
4672 static struct cat_st {
4673 char *label;
4674 unsigned int flag;
4675 } catlist[] = {
4676 {"ALIAS", WF_ALIAS },
4677 {"USERSYN", WF_USYN },
4678 {"SCENE", WF_SCENE },
4679 {"SCRIPT", WF_SCRIPT},
4680 {"OTHER", WF_OTHER },
4681 };
4682 #define NCATEGORY (sizeof(catlist)/sizeof(struct cat_st))
4683
4684 struct webhook_st {
4685 char line_format[NAME_LEN + 1];
4686 char label_format[NAME_LEN + 1];
4687 char mult_format[NAME_LEN + 1];
4688 char body_format[NAME_LEN + 1];
4689 char escape_list[NAME_LEN + 1];
4690 char null_body[PATH_LEN + 1];
4691 unsigned long flags;
4692 int index_start;
4693 int nmult;
4694 int nignore;
4695 MULTI mtable[sizeof(command)/sizeof(struct conf)];
4696 IGNLIST igntable[sizeof(command)/sizeof(struct conf)];
4697 };
4698
category_flag(char * category)4699 unsigned int category_flag ( char *category )
4700 {
4701 int j;
4702
4703 for ( j = 0; j < NCATEGORY; j++ ) {
4704 if ( strcmp(category, catlist[j].label) == 0 ) {
4705 return catlist[j].flag;
4706 }
4707 }
4708 return 0;
4709 }
4710
directive_flag(char * directive)4711 unsigned int directive_flag ( char *directive )
4712 {
4713 int j;
4714
4715 for ( j = 0; j < NCATEGORY; j++ ) {
4716 if ( strcmp(directive, catlist[j].label) == 0 ) {
4717 return catlist[j].flag;
4718 }
4719 }
4720 return WF_OTHER;
4721 }
4722
init_hooks(struct webhook_st * hookp)4723 void init_hooks ( struct webhook_st *hookp )
4724 {
4725
4726 strcpy(hookp->line_format, "%d: ");
4727 strcpy(hookp->label_format, "%s");
4728 strcpy(hookp->mult_format, "[%d]");
4729 strcpy(hookp->body_format, " %s");
4730 strcpy(hookp->escape_list, "");
4731 strcpy(hookp->null_body, "");
4732 hookp->flags = 0;
4733 hookp->index_start = 0;
4734 hookp->nmult = 0;
4735 hookp->nignore = 0;
4736
4737 return;
4738 }
4739
set_format(char * fmt_str,char * fmt)4740 int set_format ( char *fmt_str, char *fmt )
4741 {
4742 char *sp;
4743
4744 if ( strlen(fmt_str) > NAME_LEN ) {
4745 fprintf(stderr, "Format too long.\n");
4746 return 1;
4747 }
4748
4749 if ( (sp = strstr(fmt_str, "%V")) == NULL ) {
4750 fprintf(stderr, "No '%%V' in format string.\n");
4751 return 1;
4752 }
4753 strncpy(sp, "..", 2);
4754
4755 if ( strchr(fmt_str, '%') != NULL ) {
4756 fprintf(stderr, "Only '%%V' may appear in format string.\n");
4757 return 1;
4758 }
4759 strncpy(sp, fmt, 2);
4760
4761 return 0;
4762 }
4763
create_mult_ign_tables(struct webhook_st * hookp)4764 int create_mult_ign_tables ( struct webhook_st *hookp )
4765 {
4766 int i, j, m;
4767 MULTI *mtable;
4768 IGNLIST *igntable;
4769
4770 mtable = hookp->mtable;
4771 igntable = hookp->igntable;
4772
4773 i = m = 0;
4774 for ( j = 1; j < ncommands; j++ ) {
4775 if ( command[j].flags & CMLT ) {
4776 strcpy(mtable[m].label, command[j].name);
4777 mtable[m].index = hookp->index_start;
4778 m++;
4779 }
4780 else if ( command[j].flags & CIGN ) {
4781 strcpy(igntable[i].label, command[j].name);
4782 i++;
4783 }
4784 }
4785 hookp->nmult = m;
4786 *(mtable[m].label) = '\0';
4787 hookp->nignore = i;
4788 *(igntable[i].label) = '\0';
4789
4790 return m;
4791 }
4792
if_ignore(char * directive,struct webhook_st * hookp)4793 int if_ignore ( char *directive, struct webhook_st *hookp )
4794 {
4795 int j;
4796 IGNLIST *igntable;
4797
4798 igntable = hookp->igntable;
4799
4800 for ( j = 0; j < hookp->nignore; j++ ) {
4801 if ( strcmp(directive, igntable[j].label) == 0 )
4802 return 1;
4803 }
4804 return 0;
4805 }
4806
init_mult_table(struct webhook_st * hookp)4807 void init_mult_table ( struct webhook_st *hookp )
4808 {
4809 int k = 0;
4810 MULTI *mtable;
4811
4812 mtable = hookp->mtable;
4813
4814 for ( k = 0; k < hookp->nmult; k++ )
4815 mtable[k].index = hookp->index_start;
4816
4817 return;
4818 }
4819
4820
mult_index(MULTI * multp,char * label)4821 int mult_index( MULTI *multp, char *label )
4822 {
4823 int index, k = 0;
4824
4825 while ( *multp[k].label ) {
4826 if ( strcmp(multp[k].label, label) == 0 ) {
4827 index = multp[k].index;
4828 multp[k].index += 1;
4829 return index;
4830 }
4831 k++;
4832 }
4833 return -1;
4834 }
4835
4836
parse_switches(int argc,char * argv[],struct webhook_st * hookp)4837 int parse_switches ( int argc, char *argv[], struct webhook_st *hookp )
4838 {
4839 int j;
4840
4841 if ( argc < 4 )
4842 return 0;
4843
4844 for ( j = 3; j < argc; j++ ) {
4845 if ( *argv[j] == '-' ) {
4846 switch ( *(argv[j] + 1) ) {
4847 case 'L' :
4848 hookp->flags |= WF_LINE;
4849 if ( *(argv[j] + 2) != '\0' ) {
4850 if ( set_format(argv[j] + 2, "%d") != 0 )
4851 return 1;
4852 strcpy(hookp->line_format, (argv[j] + 2));
4853 }
4854 break;
4855 case 'D' :
4856 hookp->flags |= WF_UPPER;
4857 case 'd' :
4858 if ( *(argv[j] + 2) != '\0' ) {
4859 if ( set_format(argv[j] + 2, "%s") != 0 )
4860 return 1;
4861 strcpy(hookp->label_format, (argv[j] + 2));
4862 }
4863 break;
4864 case 'M' :
4865 hookp->index_start = 1;
4866 case 'm' :
4867 hookp->flags |= WF_MULT;
4868 if ( *(argv[j] + 2) != '\0' ) {
4869 if ( set_format(argv[j] + 2, "%d") != 0 )
4870 return 1;
4871 strcpy(hookp->mult_format, (argv[j] + 2));
4872 }
4873 break;
4874 case 'b' :
4875 if ( *(argv[j] + 2) != '\0' ) {
4876 if ( set_format(argv[j] + 2, "%s") != 0 )
4877 return 1;
4878 strcpy(hookp->body_format, (argv[j] + 2));
4879 }
4880 break;
4881 case 'c' :
4882 if ( *(argv[j] + 2) == 'e' ) {
4883 hookp->flags |= WF_ESC;
4884 if ( *(argv[j] + 3) ) {
4885 strcpy(hookp->escape_list, (argv[j] + 3));
4886 }
4887 }
4888 else {
4889 fprintf(stderr, "Switch '%s' invalid.\n", argv[j]);
4890 return 1;
4891 }
4892 break;
4893 case 'n' :
4894 if ( *(argv[j] + 2) == 'b' ) {
4895 hookp->flags |= WF_NULLBODY;
4896 if ( *(argv[j] + 3) ) {
4897 strcpy(hookp->null_body, (argv[j] + 3));
4898 }
4899 }
4900 else {
4901 fprintf(stderr, "Switch '%s' invalid.\n", argv[j]);
4902 return 1;
4903 }
4904 break;
4905
4906 default :
4907 fprintf(stderr, "Switch '%s' not recognized.\n", argv[j]);
4908 return 1;
4909 break;
4910 }
4911 }
4912 }
4913 return 0;
4914 }
4915
webhook_script_cmdline(char * cmdptr,struct webhook_st * hookp)4916 int webhook_script_cmdline ( char *cmdptr, struct webhook_st *hookp )
4917 {
4918 char buffer[LINE_LEN];
4919 char *sp, *dp;
4920
4921 if ( !(hookp->flags & WF_ESC) )
4922 return 0;
4923
4924 strcpy(buffer, cmdptr);
4925 sp = buffer;
4926 dp = cmdptr;
4927 while ( *sp ) {
4928 if ( strchr(hookp->escape_list, *sp) )
4929 *dp++ = '\\';
4930 *dp++ = *sp++;
4931 }
4932 *dp = '\0';
4933
4934 return 0;
4935 }
4936
config_dump_category(FILE * fd,unsigned int wf_flag,struct webhook_st * hookp)4937 void config_dump_category ( FILE *fd, unsigned int wf_flag, struct webhook_st *hookp )
4938 {
4939 char buffer[LINE_LEN];
4940 char outbuf[LINE_LEN];
4941 char directive[NAME_LEN + 1];
4942 char *sp, *cmdptr;
4943 int j, tokc, line_no, index;
4944 unsigned int flags, dflag;
4945 char **tokv = NULL;
4946 MULTI *mtable;
4947 IGNLIST *igntable;
4948
4949 rewind(fd);
4950
4951 flags = hookp->flags;
4952 mtable = hookp->mtable;
4953 igntable = hookp->igntable;
4954
4955 line_no = 0;
4956 while ( fgets(buffer, sizeof(buffer), fd) != NULL ) {
4957 line_no++;
4958 if ( (sp = strchr(buffer, '#')) != NULL )
4959 *sp = '\0';
4960 strtrim(buffer);
4961 if ( *buffer == '\0' )
4962 continue;
4963 sp = buffer;
4964 get_token(directive, &sp, " \t\r\n", NAME_LEN + 1);
4965 strupper(directive);
4966
4967 if ( if_ignore(directive, hookp) )
4968 continue;
4969
4970 dflag = directive_flag(directive);
4971 if ( !(dflag & wf_flag) )
4972 continue;
4973
4974 index = mult_index(mtable, directive);
4975 if ( !(flags & WF_UPPER) )
4976 strlower(directive);
4977 if ( flags & WF_LINE )
4978 printf(hookp->line_format, line_no);
4979 printf(hookp->label_format, directive);
4980 if ( (flags & WF_MULT) && (index >= 0) )
4981 printf(hookp->mult_format, index);
4982
4983 *outbuf = '\0';
4984 if ( dflag & WF_SCRIPT ) {
4985 cmdptr = strstr(sp, "::");
4986 *cmdptr = '\0';
4987 tokenize(sp, " \t\r\n", &tokc, &tokv);
4988 for ( j = 0; j < tokc; j++ ) {
4989 strcat(outbuf, tokv[j]);
4990 strcat(outbuf, " ");
4991 }
4992 *cmdptr = ':';
4993 webhook_script_cmdline(cmdptr + 2, hookp);
4994 strcat(outbuf, cmdptr);
4995 }
4996 else {
4997 tokenize(sp, " \t\r\n", &tokc, &tokv);
4998 for ( j = 0; j < tokc; j++ ) {
4999 strcat(outbuf, tokv[j]);
5000 strcat(outbuf, " ");
5001 }
5002 *(outbuf + strlen(outbuf) - 1) = '\0';
5003 }
5004
5005 printf(hookp->body_format, outbuf);
5006 printf("\n");
5007 free(tokv);
5008 }
5009
5010 return;
5011 }
5012
webhook_config_dump(int argc,char * argv[])5013 int webhook_config_dump ( int argc, char *argv[] )
5014 {
5015 char category[NAME_LEN + 1];
5016 struct webhook_st hooks;
5017 MULTI *mtable;
5018 FILE *fp;
5019 char confp[PATH_LEN + 1];
5020 int j;
5021
5022 init_hooks(&hooks);
5023
5024 if ( argc > 3 && *argv[argc - 1] != '-' ) {
5025 strncpy2(category, argv[argc - 1], NAME_LEN);
5026 strupper(category);
5027
5028 if ( (hooks.flags = category_flag(category)) == 0 ) {
5029 fprintf(stderr, "Unsupported category '%s'\n", argv[argc - 1]);
5030 return 1;
5031 }
5032 }
5033 else {
5034 hooks.flags = 0;
5035 for ( j = 0; j < NCATEGORY; j++ ) {
5036 hooks.flags |= catlist[j].flag;
5037 }
5038 }
5039
5040 if ( parse_switches(argc, argv, &hooks) != 0 )
5041 return 1;
5042
5043 create_mult_ign_tables(&hooks);
5044 init_mult_table(&hooks);
5045
5046 mtable = hooks.mtable;
5047
5048 get_configuration(CONFIG_INIT);
5049
5050 find_heyu_path();
5051
5052 strncpy2(confp, pathspec(heyu_config), sizeof(confp) - 1);
5053
5054 if ( !(fp = fopen(confp, "r")) ) {
5055 exit(1);
5056 }
5057
5058 config_dump_category(fp, hooks.flags, &hooks);
5059
5060 fclose( fp );
5061
5062 return 0;
5063 }
5064
webhook_pathinfo(int argc,char * argv[])5065 int webhook_pathinfo ( int argc, char *argv[] )
5066 {
5067 char *configlabel[] = {"conf", "CONF"};
5068 char *loglabel[] = {"log", "LOG"};
5069 char category[NAME_LEN + 1];
5070 char *label;
5071 struct webhook_st hooks;
5072
5073 init_hooks(&hooks);
5074
5075 if ( argc > 3 && *argv[argc - 1] != '-' ) {
5076 strncpy2(category, argv[argc - 1], NAME_LEN);
5077 strupper(category);
5078
5079 if ( strcmp(category, "CONF") == 0 )
5080 hooks.flags |= WF_CONF;
5081 else if ( strcmp(category, "LOG") == 0 )
5082 hooks.flags |= WF_LOG;
5083 else {
5084 fprintf(stderr, "Unsupported category '%s'\n", argv[argc - 1]);
5085 return 1;
5086 }
5087 }
5088 else {
5089 hooks.flags |= (WF_CONF | WF_LOG);
5090 }
5091
5092 if ( parse_switches(argc, argv, &hooks) != 0 )
5093 return 1;
5094
5095 get_configuration(CONFIG_INIT);
5096
5097 if ( hooks.flags & WF_CONF ) {
5098 find_heyu_path();
5099 label = (hooks.flags & WF_UPPER) ? configlabel[1] : configlabel[0];
5100 printf(hooks.label_format, label);
5101 printf(hooks.body_format, pathspec(heyu_config));
5102 printf("\n");
5103 }
5104
5105 if ( hooks.flags & WF_LOG ) {
5106 label = (hooks.flags & WF_UPPER) ? loglabel[1] : loglabel[0];
5107 printf(hooks.label_format, label);
5108 if ( strcmp(configp->logfile, "/dev/null") == 0 && (hooks.flags & WF_NULLBODY) )
5109 printf(hooks.body_format, hooks.null_body);
5110 else
5111 printf(hooks.body_format, configp->logfile);
5112 printf("\n");
5113 }
5114
5115 return 0;
5116 }
5117
get_help_topics(char ** topic,int * ntopic)5118 void get_help_topics ( char **topic, int *ntopic )
5119 {
5120
5121 *ntopic = 0;
5122
5123 topic[(*ntopic)++] = "admin";
5124 topic[(*ntopic)++] = "direct";
5125 topic[(*ntopic)++] = "state";
5126 topic[(*ntopic)++] = "internal";
5127 #ifdef HASCM17A
5128 topic[(*ntopic)++] = "cm17a";
5129 #endif
5130 #ifdef HASEXT0
5131 topic[(*ntopic)++] = "shutter";
5132 #endif
5133 #ifdef HASRFXS
5134 topic[(*ntopic)++] = "rfxsensor";
5135 #endif
5136 #ifdef HASRFXM
5137 topic[(*ntopic)++] = "rfxmeter";
5138 #endif
5139 #ifdef HASDMX
5140 topic[(*ntopic)++] = "digimax";
5141 #endif
5142 #ifdef HASORE
5143 topic[(*ntopic)++] = "oregon";
5144 #endif
5145
5146 return;
5147
5148 }
5149
webhook_menuinfo(int argc,char * argv[])5150 int webhook_menuinfo ( int argc, char *argv[] )
5151 {
5152 char *topic[32];
5153 int j, ntopic;
5154
5155 get_help_topics (topic, &ntopic);
5156
5157 for ( j = 0; j < ntopic; j++ )
5158 printf("$help_menu[%d]=\"/heyu/help %s\";\n", j, topic[j]);
5159 return 0;
5160 }
5161
5162
webhook_fileinfo(int argc,char * argv[])5163 int webhook_fileinfo ( int argc, char *argv[] )
5164 {
5165
5166 get_configuration(CONFIG_INIT);
5167 find_heyu_path();
5168 printf("$heyu_conf=\"%s\";\n", pathspec(heyu_config));
5169 if ( strcmp(configp->logfile, "/dev/null") == 0 )
5170 printf("$heyu_log=\"/tmp/\";\n");
5171 else
5172 printf("$heyu_log=\"%s\";\n", configp->logfile);
5173 return 0;
5174
5175 }
5176
webhook_helpinfo(int argc,char * argv[])5177 int webhook_helpinfo ( int argc, char *argv[] )
5178 {
5179 char *label;
5180 struct webhook_st hooks;
5181 int j, k, ntopic;
5182 char outformat[80];
5183 char *topic[32];
5184
5185 init_hooks(&hooks);
5186
5187 if ( parse_switches(argc, argv, &hooks) != 0 )
5188 return 1;
5189
5190 label = (hooks.flags & WF_UPPER) ? "HELP" : "help" ;
5191
5192 /* Get list of available help topics */
5193 get_help_topics(topic, &ntopic);
5194
5195 if ( hooks.flags & WF_MULT ) {
5196 sprintf(outformat, "%s%s%s\n", hooks.label_format, hooks.mult_format, hooks.body_format);
5197 j = hooks.index_start;
5198 for ( k = 0; k < ntopic; k++ )
5199 printf(outformat, label, j++, topic[k]);
5200 }
5201 else {
5202 sprintf(outformat, "%s%s\n", hooks.label_format, hooks.body_format);
5203 for ( k = 0; k < ntopic; k++ )
5204 printf(outformat, label, topic[k]);
5205 }
5206
5207 return 0;
5208 }
5209
5210
webhook_flaginfo(int argc,char * argv[])5211 int webhook_flaginfo ( int argc, char *argv[] )
5212 {
5213 char *flaglabel[] = {"flags", "FLAGS"};
5214 char *czflaglabel[] = {"czflags", "CZFLAGS"};
5215 char *tzflaglabel[] = {"tzflags", "TZFLAGS"};
5216
5217 char category[NAME_LEN + 1];
5218 char *label;
5219 struct webhook_st hooks;
5220 int read_x10state_file ( void );
5221
5222 char asciimap[1030];
5223
5224 get_configuration(CONFIG_INIT);
5225
5226 init_hooks(&hooks);
5227
5228 if ( argc > 3 && *argv[argc - 1] != '-' ) {
5229 strncpy2(category, argv[argc - 1], NAME_LEN);
5230 strupper(category);
5231
5232 if ( strcmp(category, "FLAGS") == 0 )
5233 hooks.flags |= WF_FLAGS;
5234 else if ( strcmp(category, "CZFLAGS") == 0 )
5235 hooks.flags |= WF_CZFLAGS;
5236 else if ( strcmp(category, "TZFLAGS") == 0 )
5237 hooks.flags |= WF_TZFLAGS;
5238 else {
5239 fprintf(stderr, "Unsupported flaginfo category '%s'\n", argv[argc - 1]);
5240 return 1;
5241 }
5242 }
5243 else {
5244 fprintf(stderr, "Missing category. It must be FLAGS, CZFLAGS, or TZFLAGS\n");
5245 return 1;
5246 }
5247
5248 if ( check_for_engine() != 0 ) {
5249 fprintf(stderr, "State engine is not running.\n");
5250 return 1;
5251 }
5252
5253 if ( fetch_x10state() != 0 ) {
5254 fprintf(stderr, "Webhook unable to read state file.\n");
5255 return 1;
5256 }
5257
5258 if ( parse_switches(argc, argv, &hooks) != 0 )
5259 return 1;
5260
5261 if ( hooks.flags & WF_FLAGS ) {
5262 allflags2asciimap(asciimap, x10global.flags, NUM_FLAG_BANKS);
5263 label = (hooks.flags & WF_UPPER) ? flaglabel[1] : flaglabel[0];
5264 }
5265 else if ( hooks.flags & WF_CZFLAGS ) {
5266 allflags2asciimap(asciimap, x10global.czflags, NUM_COUNTER_BANKS);
5267 label = (hooks.flags & WF_UPPER) ? czflaglabel[1] : czflaglabel[0];
5268 }
5269 else if ( hooks.flags & WF_TZFLAGS ) {
5270 allflags2asciimap(asciimap, x10global.tzflags, NUM_TIMER_BANKS);
5271 label = (hooks.flags & WF_UPPER) ? tzflaglabel[1] : tzflaglabel[0];
5272 }
5273 else {
5274 return 1;
5275 }
5276
5277 printf(hooks.label_format, label);
5278 printf(hooks.body_format, asciimap);
5279 printf("\n");
5280
5281 return 0;
5282 }
5283
webhook_flagbankinfo(int argc,char * argv[])5284 int webhook_flagbankinfo ( int argc, char *argv[] )
5285 {
5286
5287 char *flaglabel[] = {"flagbank", "FLAGBANK"};
5288 char *czflaglabel[] = {"czflagbank", "CZFLAGBANK"};
5289 char *tzflaglabel[] = {"tzflagbank", "TZFLAGBANK"};
5290
5291 char category[NAME_LEN + 1];
5292 char *label;
5293 struct webhook_st hooks;
5294 int read_x10state_file ( void );
5295
5296 char asciimap[34];
5297 int j;
5298
5299 get_configuration(CONFIG_INIT);
5300
5301 init_hooks(&hooks);
5302
5303 if ( argc > 3 && *argv[argc - 1] != '-' ) {
5304 strncpy2(category, argv[argc - 1], NAME_LEN);
5305 strupper(category);
5306
5307 if ( strcmp(category, "FLAGS") == 0 )
5308 hooks.flags |= WF_FLAGS;
5309 else if ( strcmp(category, "CZFLAGS") == 0 )
5310 hooks.flags |= WF_CZFLAGS;
5311 else if ( strcmp(category, "TZFLAGS") == 0 )
5312 hooks.flags |= WF_TZFLAGS;
5313 else {
5314 fprintf(stderr, "Unsupported flagbankinfo category '%s'\n", argv[argc - 1]);
5315 return 1;
5316 }
5317 }
5318 else {
5319 fprintf(stderr, "Missing category. It must be FLAGS, CZFLAGS, or TZFLAGS\n");
5320 return 1;
5321 }
5322
5323 if ( check_for_engine() != 0 ) {
5324 fprintf(stderr, "State engine is not running.\n");
5325 return 1;
5326 }
5327
5328 if ( fetch_x10state() != 0 ) {
5329 fprintf(stderr, "Webhook unable to read x10state file.\n");
5330 return 1;
5331 }
5332
5333 if ( parse_switches(argc, argv, &hooks) != 0 )
5334 return 1;
5335
5336 if ( hooks.flags & WF_FLAGS ) {
5337 label = (hooks.flags & WF_UPPER) ? flaglabel[1] : flaglabel[0];
5338 for ( j = 0; j < NUM_FLAG_BANKS; j++ ) {
5339 flags2asciimap(asciimap, x10global.flags[j]);
5340 printf(hooks.label_format, label);
5341 printf(hooks.mult_format, hooks.index_start + j);
5342 printf(hooks.body_format, asciimap);
5343 printf("\n");
5344 }
5345 }
5346 else if ( hooks.flags & WF_CZFLAGS ) {
5347 label = (hooks.flags & WF_UPPER) ? czflaglabel[1] : czflaglabel[0];
5348 for ( j = 0; j < NUM_COUNTER_BANKS; j++ ) {
5349 flags2asciimap(asciimap, x10global.czflags[j]);
5350 printf(hooks.label_format, label);
5351 printf(hooks.mult_format, hooks.index_start + j);
5352 printf(hooks.body_format, asciimap);
5353 printf("\n");
5354 }
5355 }
5356 else if ( hooks.flags & WF_TZFLAGS ) {
5357 label = (hooks.flags & WF_UPPER) ? tzflaglabel[1] : tzflaglabel[0];
5358 for ( j = 0; j < NUM_TIMER_BANKS; j++ ) {
5359 flags2asciimap(asciimap, x10global.tzflags[j]);
5360 printf(hooks.label_format, label);
5361 printf(hooks.mult_format, hooks.index_start + j);
5362 printf(hooks.body_format, asciimap);
5363 printf("\n");
5364 }
5365 }
5366 else {
5367 return 1;
5368 }
5369
5370 return 0;
5371 }
5372
webhook_maskinfo(int argc,char * argv[])5373 int webhook_maskinfo ( int argc, char *argv[] )
5374 {
5375 char *label;
5376 int j;
5377 char minibuf[32];
5378 unsigned int mask;
5379 struct webhook_st hooks;
5380 extern int get_env_funcmask ( int, char **, unsigned int * );
5381 extern int get_env_flagmask ( int, char **, unsigned int * );
5382
5383 init_hooks(&hooks);
5384
5385 hooks.flags |= WF_MASKS;
5386
5387 if ( parse_switches(argc, argv, &hooks) != 0 )
5388 return 1;
5389
5390 j = 0;
5391 while ( get_env_funcmask(j, &label, &mask) == 0 ) {
5392 printf(hooks.label_format, label);
5393 sprintf(minibuf, "%d", mask);
5394 printf(hooks.body_format, minibuf);
5395 printf("\n");
5396 j++;
5397 }
5398
5399 return 0;
5400 }
5401
webhook_flagmaskinfo(int argc,char * argv[])5402 int webhook_flagmaskinfo ( int argc, char *argv[] )
5403 {
5404 char *label;
5405 int j;
5406 char minibuf[32];
5407 unsigned int mask;
5408 struct webhook_st hooks;
5409 extern int get_env_funcmask ( int, char **, unsigned int * );
5410 extern int get_env_flagmask ( int, char **, unsigned int * );
5411
5412 init_hooks(&hooks);
5413
5414 hooks.flags |= WF_MASKS;
5415
5416 if ( parse_switches(argc, argv, &hooks) != 0 )
5417 return 1;
5418
5419 j = 0;
5420 while ( get_env_flagmask(j, &label, &mask) == 0 ) {
5421 printf(hooks.label_format, label);
5422 sprintf(minibuf, "%d", mask);
5423 printf(hooks.body_format, minibuf);
5424 printf("\n");
5425 j++;
5426 }
5427
5428 return 0;
5429 }
5430
5431
c_webhook(int argc,char * argv[])5432 int c_webhook ( int argc, char *argv[] )
5433 {
5434 if ( argc < 3 ) {
5435 display_webhook_usage();
5436 return 0;
5437 }
5438
5439 if ( strcmp(argv[2], "config_dump") == 0 )
5440 return webhook_config_dump(argc, argv);
5441 else if ( strcmp(argv[2], "pathinfo") == 0 )
5442 return webhook_pathinfo(argc, argv);
5443 else if ( strcmp(argv[2], "helpinfo") == 0 )
5444 return webhook_helpinfo(argc, argv);
5445 else if ( strcmp(argv[2], "flaginfo") == 0 )
5446 return webhook_flaginfo(argc, argv);
5447 else if ( strcmp(argv[2], "flagbankinfo") == 0 )
5448 return webhook_flagbankinfo(argc, argv);
5449 else if ( strcmp(argv[2], "maskinfo") == 0 )
5450 return webhook_maskinfo(argc, argv);
5451 else if ( strcmp(argv[2], "flagmaskinfo") == 0 )
5452 return webhook_flagmaskinfo(argc, argv);
5453 else if ( strcmp(argv[2], "fileinfo") == 0 )
5454 return webhook_fileinfo(argc, argv); /* deprecated */
5455 else if ( strcmp(argv[2], "menuinfo") == 0 )
5456 return webhook_menuinfo(argc, argv); /* deprecated */
5457 else {
5458 fprintf(stderr, "Invalid webhook command '%s'\n", argv[2]);
5459 return 1;
5460 }
5461 return 0;
5462 }
5463
5464 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++
5465 | END WEBHOOK SECTION |
5466 +++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
5467
5468
5469
cmp_directives(const void * m1,const void * m2)5470 int cmp_directives ( const void *m1, const void *m2 )
5471 {
5472 struct conf *one, *two;
5473
5474 one = (struct conf *)m1; two = (struct conf *)m2;
5475
5476 return strcmp(one->name, two->name);
5477 }
5478
c_conflist(int argc,char * argv[])5479 int c_conflist ( int argc, char *argv[] )
5480 {
5481 int j;
5482 qsort(command + 1, ncommands - 1, sizeof(struct conf), cmp_directives);
5483
5484 for ( j = 1; j < ncommands - 1; j++ )
5485 if ( !(command[j].flags & (CIGN | CHID)) )
5486 printf("%s\n", command[j].name);
5487 printf("\n");
5488
5489 return 0;
5490 }
5491
5492 /*---------------------------------------------------------------------+
5493 | Compare arrays of ALIAS structures to see if any have been changed. |
5494 | Return 1 if changed or 0 if unchanged. |
5495 +---------------------------------------------------------------------*/
is_alias_changed(ALIAS * aliasp1,int size1,ALIAS * aliasp2,int size2)5496 int is_alias_changed ( ALIAS *aliasp1, int size1, ALIAS *aliasp2, int size2 )
5497 {
5498 ALIAS *aliaspp1, *aliaspp2;
5499 int j, k, dif;
5500
5501 if ( size1 != size2 || size1 == 0 )
5502 return 1;
5503
5504 for ( j = 0; j < size1; j++ ) {
5505 aliaspp1 = &aliasp1[j]; aliaspp2 = &aliasp2[j];
5506 dif = (strcmp(aliaspp1->label, aliaspp2->label)) ? 1 :
5507 (aliaspp1->housecode != aliaspp2->housecode) ? 1 :
5508 (aliaspp1->hcode != aliaspp2->hcode) ? 1 :
5509 (aliaspp1->unitbmap != aliaspp2->unitbmap) ? 1 :
5510 (aliaspp1->ext0links != aliaspp2->ext0links) ? 1 :
5511 (aliaspp1->modtype != aliaspp2->modtype) ? 1 :
5512 (aliaspp1->vflags != aliaspp2->vflags) ? 1 :
5513 (aliaspp1->flags != aliaspp2->flags) ? 1 :
5514 (aliaspp1->xflags != aliaspp2->xflags) ? 1 :
5515 (aliaspp1->optflags != aliaspp2->optflags) ? 1 :
5516 (aliaspp1->optflags2 != aliaspp2->optflags2) ? 1 :
5517 (aliaspp1->tmin != aliaspp2->tmin) ? 1 :
5518 (aliaspp1->tmax != aliaspp2->tmax) ? 1 :
5519 (aliaspp1->rhmin != aliaspp2->rhmin) ? 1 :
5520 (aliaspp1->rhmax != aliaspp2->rhmax) ? 1 :
5521 (aliaspp1->onlevel != aliaspp2->onlevel) ? 1 :
5522 (aliaspp1->maxlevel != aliaspp2->maxlevel) ? 1 :
5523 (aliaspp1->vtype != aliaspp2->vtype) ? 1 :
5524 (aliaspp1->subtype != aliaspp2->subtype) ? 1 :
5525 (aliaspp1->nident != aliaspp2->nident) ? 1 :
5526 // (aliaspp1->timeout != aliaspp2->timeout) ? 1 :
5527 (aliaspp1->hb_timeout != aliaspp2->hb_timeout) ? 1 :
5528 (aliaspp1->storage_index != aliaspp2->storage_index) ? 1 :
5529 (aliaspp1->storage_units != aliaspp2->storage_units) ? 1 : 0;
5530
5531 if ( dif )
5532 return 1;
5533
5534 for ( k = 0; k < aliaspp1->nident; k++ ) {
5535 if ( aliaspp1->ident[k] != aliaspp2->ident[k] )
5536 return 1;
5537 }
5538 for ( k = 0; k < NFUNCLIST; k++ ) {
5539 if ( aliaspp1->funclist[k] != aliaspp2->funclist[k] )
5540 return 1;
5541 }
5542 for ( k = 0; k < NOFFSET; k++ ) {
5543 if ( aliaspp1->offset[k] != aliaspp2->offset[k] )
5544 return 1;
5545 }
5546 }
5547
5548 return 0;
5549 }
5550
5551
5552
5553