1 /* mge-xml.c	Model specific routines for Eaton / MGE XML protocol UPSes
2 
3    Copyright (C)
4 	2008-2009	Arjen de Korte <adkorte-guest@alioth.debian.org>
5 	2009-2021	Eaton (author: Arnaud Quette <ArnaudQuette@Eaton.com>)
6 	2017		Eaton (author: Jim Klimov <EvgenyKlimov@Eaton.com>)
7 
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12 
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include <ne_xml.h>
28 
29 #include "common.h"
30 #include "dstate.h"
31 
32 #include "netxml-ups.h"
33 #include "mge-xml.h"
34 #include "main.h" /* for testvar() */
35 
36 #define MGE_XML_VERSION		"MGEXML/0.31"
37 
38 #define MGE_XML_INITUPS		"/"
39 #define MGE_XML_INITINFO	"/mgeups/product.xml /product.xml /ws/product.xml"
40 
41 #define ST_FLAG_RW		0x0001
42 #define ST_FLAG_STATIC		0x0002
43 
44 static int	mge_ambient_value = 0;
45 
46 /* The number of phases is not present in XML data as a separate node,
47  * but we can infer it from presence of non-zero data on several
48  * per-line nodes. */
49 static int
50 	inited_phaseinfo_in = 0,
51 	inited_phaseinfo_bypass = 0,
52 	inited_phaseinfo_out = 0,
53 	num_inphases = -1,
54 	num_bypassphases = -1,
55 	num_outphases = -1;
56 
57 static char	mge_scratch_buf[256];
58 
59 static char	var[128];
60 static char	val[128];
61 
62 static int	mge_shutdown_pending = 0;
63 
64 /* This flag flips to 0 when/if we post the detailed deprecation message */
65 static int	mge_report_deprecation__convert_deci = 1;
66 
67 typedef enum {
68 	ROOTPARENT = NE_XML_STATEROOT,
69 
70 	_UNEXPECTED,
71 	_PARSEERROR,
72 
73 	PRODUCT_INFO = 100,	/* "/mgeups/product.xml" */
74 
75 		PI_SUMMARY = 110,
76 			PI_HTML_PROPERTIES_PAGE,
77 			PI_XML_SUMMARY_PAGE,
78 			PI_CENTRAL_CFG,
79 			PI_CSV_LOGS,
80 		/* /PI_SUMMARY */
81 
82 		PI_ALARMS = 120,
83 			PI_SUBSCRIPTION,
84 			PI_POLLING,
85 		/* /ALARMS */
86 
87 		PI_MANAGEMENT = 130,
88 			PI_MANAGEMENT_PAGE,
89 			PI_XML_MANAGEMENT_PAGE,
90 		/* /MANAGEMENT */
91 
92 		PI_UPS_DATA = 140,
93 			PI_GET_OBJECT,
94 			PI_SET_OBJECT,
95 		/* /UPS_DATA */
96 
97 	/* /PRODUCT_INFO */
98 
99 	SUMMARY = 200,		/* "/upsprop.xml" */
100 		SU_OBJECT,
101 	/* /SUMMARY */
102 
103 	GET_OBJECT = 300,	/* "/getvalue.cgi" */
104 		GO_OBJECT,
105 	/* /GET_OBJECT */
106 
107 	SET_OBJECT = 400,	/* "/setvalue.cgi" */
108 		SO_OBJECT,
109 	/* /SET_OBJECT */
110 
111 	ALARM = 500,
112 
113 	XML_CLIENT = 600,
114 		XC_GENERAL = 610,
115 			XC_STARTUP,
116 			XC_SHUTDOWN,
117 			XC_BROADCAST
118 
119 } mge_xml_state_t;
120 
121 typedef struct {
122 	const char	*nutname;	/* NUT variable name */
123 	uint32_t nutflags;	/* NUT flags (to set in addinfo) */
124 	size_t	nutlen;		/* length of the NUT string */
125 	const char	*xmlname;	/* XML variable name */
126 	uint32_t xmlflags;	/* XML flags (to be used to determine what kind of variable this is */
127 	size_t	xmllen;		/* length of the XML string */
128 	const char	*(*convert)(const char *value);	/* conversion function from XML<->NUT value (returns
129 						   NULL if no further processing is required) */
130 } xml_info_t;
131 
online_info(const char * arg_val)132 static const char *online_info(const char *arg_val)
133 {
134 	if (arg_val[0] == '1') {
135 		STATUS_SET(ONLINE);
136 	} else {
137 		STATUS_CLR(ONLINE);
138 	}
139 
140 	return NULL;
141 }
142 
discharging_info(const char * arg_val)143 static const char *discharging_info(const char *arg_val)
144 {
145 	if (arg_val[0] == '1') {
146 		STATUS_SET(DISCHRG);
147 		/* Workaround NMC bug: both charging and discharging set to 1 */
148 		if(STATUS_BIT(CHRG)) {
149 			STATUS_CLR(CHRG);
150 		}
151 	} else {
152 		STATUS_CLR(DISCHRG);
153 	}
154 
155 	return NULL;
156 }
157 
charging_info(const char * arg_val)158 static const char *charging_info(const char *arg_val)
159 {
160 	if (arg_val[0] == '1') {
161 		STATUS_SET(CHRG);
162 	} else {
163 		STATUS_CLR(CHRG);
164 	}
165 
166 	return NULL;
167 }
168 
lowbatt_info(const char * arg_val)169 static const char *lowbatt_info(const char *arg_val)
170 {
171 	if (arg_val[0] == '1') {
172 		STATUS_SET(LOWBATT);
173 	} else {
174 		STATUS_CLR(LOWBATT);
175 	}
176 
177 	return NULL;
178 }
179 
overload_info(const char * arg_val)180 static const char *overload_info(const char *arg_val)
181 {
182 	if (arg_val[0] == '1') {
183 		STATUS_SET(OVERLOAD);
184 	} else {
185 		STATUS_CLR(OVERLOAD);
186 	}
187 
188 	return NULL;
189 }
190 
replacebatt_info(const char * arg_val)191 static const char *replacebatt_info(const char *arg_val)
192 {
193 	if (arg_val[0] == '1') {
194 		STATUS_SET(REPLACEBATT);
195 	} else {
196 		STATUS_CLR(REPLACEBATT);
197 	}
198 
199 	return NULL;
200 }
201 
trim_info(const char * arg_val)202 static const char *trim_info(const char *arg_val)
203 {
204 	if (arg_val[0] == '1') {
205 		STATUS_SET(TRIM);
206 	} else {
207 		STATUS_CLR(TRIM);
208 	}
209 
210 	return NULL;
211 }
212 
boost_info(const char * arg_val)213 static const char *boost_info(const char *arg_val)
214 {
215 	if (arg_val[0] == '1') {
216 		STATUS_SET(BOOST);
217 	} else {
218 		STATUS_CLR(BOOST);
219 	}
220 
221 	return NULL;
222 }
223 
bypass_aut_info(const char * arg_val)224 static const char *bypass_aut_info(const char *arg_val)
225 {
226 	if (arg_val[0] == '1') {
227 		STATUS_SET(BYPASSAUTO);
228 	} else {
229 		STATUS_CLR(BYPASSAUTO);
230 	}
231 
232 	return NULL;
233 }
234 
bypass_man_info(const char * arg_val)235 static const char *bypass_man_info(const char *arg_val)
236 {
237 	if (arg_val[0] == '1') {
238 		STATUS_SET(BYPASSMAN);
239 	} else {
240 		STATUS_CLR(BYPASSMAN);
241 	}
242 
243 	return NULL;
244 }
245 
off_info(const char * arg_val)246 static const char *off_info(const char *arg_val)
247 {
248 	if (arg_val[0] == '0') {
249 		STATUS_SET(OFF);
250 	} else {
251 		STATUS_CLR(OFF);
252 	}
253 
254 	return NULL;
255 }
256 
257 /* note: this value is reverted (0=set, 1=not set). We report "battery
258    not installed" rather than "battery installed", so that devices
259    that don't implement this variable have a battery by default */
nobattery_info(const char * arg_val)260 static const char *nobattery_info(const char *arg_val)
261 {
262 	if (arg_val[0] == '0') {
263 		STATUS_SET(NOBATTERY);
264 	} else {
265 		STATUS_CLR(NOBATTERY);
266 	}
267 
268 	return NULL;
269 }
270 
fanfail_info(const char * arg_val)271 static const char *fanfail_info(const char *arg_val)
272 {
273 	if (arg_val[0] == '1') {
274 		STATUS_SET(FANFAIL);
275 	} else {
276 		STATUS_CLR(FANFAIL);
277 	}
278 
279 	return NULL;
280 }
281 
282 #if 0
283 static const char *shutdownimm_info(const char *arg_val)
284 {
285 	if (arg_val[0] == '1') {
286 		STATUS_SET(SHUTDOWNIMM);
287 	} else {
288 		STATUS_CLR(SHUTDOWNIMM);
289 	}
290 
291 	return NULL;
292 }
293 #endif
294 
overheat_info(const char * arg_val)295 static const char *overheat_info(const char *arg_val)
296 {
297 	if (arg_val[0] == '1') {
298 		STATUS_SET(OVERHEAT);
299 	} else {
300 		STATUS_CLR(OVERHEAT);
301 	}
302 
303 	return NULL;
304 }
305 
commfault_info(const char * arg_val)306 static const char *commfault_info(const char *arg_val)
307 {
308 	if (arg_val[0] == '1') {
309 		STATUS_SET(COMMFAULT);
310 	} else {
311 		STATUS_CLR(COMMFAULT);
312 	}
313 
314 	return NULL;
315 }
316 
internalfailure_info(const char * arg_val)317 static const char *internalfailure_info(const char *arg_val)
318 {
319 	if (arg_val[0] == '1') {
320 		STATUS_SET(INTERNALFAULT);
321 	} else {
322 		STATUS_CLR(INTERNALFAULT);
323 	}
324 
325 	return NULL;
326 }
327 
battvoltlo_info(const char * arg_val)328 static const char *battvoltlo_info(const char *arg_val)
329 {
330 	if (arg_val[0] == '1') {
331 		STATUS_SET(BATTVOLTLO);
332 	} else {
333 		STATUS_CLR(BATTVOLTLO);
334 	}
335 
336 	return NULL;
337 }
338 
battvolthi_info(const char * arg_val)339 static const char *battvolthi_info(const char *arg_val)
340 {
341 	if (arg_val[0] == '1') {
342 		STATUS_SET(BATTVOLTHI);
343 	} else {
344 		STATUS_CLR(BATTVOLTHI);
345 	}
346 
347 	return NULL;
348 }
349 
chargerfail_info(const char * arg_val)350 static const char *chargerfail_info(const char *arg_val)
351 {
352 	if ((arg_val[0] == '1') || !strncasecmp(arg_val, "Yes", 3)) {
353 		STATUS_SET(CHARGERFAIL);
354 	} else {
355 		STATUS_CLR(CHARGERFAIL);
356 	}
357 
358 	return NULL;
359 }
360 
vrange_info(const char * arg_val)361 static const char *vrange_info(const char *arg_val)
362 {
363 	if ((arg_val[0] == '1') || !strncasecmp(arg_val, "Yes", 3)) {
364 		STATUS_SET(VRANGE);
365 	} else {
366 		STATUS_CLR(VRANGE);
367 	}
368 
369 	return NULL;
370 }
371 
frange_info(const char * arg_val)372 static const char *frange_info(const char *arg_val)
373 {
374 	if ((arg_val[0] == '1') || !strncasecmp(arg_val, "Yes", 3)) {
375 		STATUS_SET(FRANGE);
376 	} else {
377 		STATUS_CLR(FRANGE);
378 	}
379 
380 	return NULL;
381 }
382 
fuse_fault_info(const char * arg_val)383 static const char *fuse_fault_info(const char *arg_val)
384 {
385 	if (arg_val[0] == '1') {
386 		STATUS_SET(FUSEFAULT);
387 	} else {
388 		STATUS_CLR(FUSEFAULT);
389 	}
390 
391 	return NULL;
392 }
393 
yes_no_info(const char * arg_val)394 static const char *yes_no_info(const char *arg_val)
395 {
396 	switch(arg_val[0])
397 	{
398 	case '1':
399 		return "yes";
400 	case '0':
401 		return "no";
402 	default:
403 		upsdebugx(2, "%s: unexpected value [%s]", __func__, arg_val);
404 		return "<unknown>";
405 	}
406 }
407 
on_off_info(const char * arg_val)408 static const char *on_off_info(const char *arg_val)
409 {
410 	switch(arg_val[0])
411 	{
412 	case '1':
413 		return "on";
414 	case '0':
415 		return "off";
416 	default:
417 		upsdebugx(2, "%s: unexpected value [%s]", __func__, arg_val);
418 		return "<unknown>";
419 	}
420 }
421 
convert_deci(const char * arg_val)422 static const char *convert_deci(const char *arg_val)
423 {
424 	/* Note: this routine was needed for original MGE devices, before the company
425 	 * was bought out and split in 2007 between Eaton (1ph devices) and Schneider
426 	 * (3ph devices). Those firmwares back when the driver was written apparently
427 	 * served 10x the measured values. Not sure if any such units are in service
428 	 * now (with same FW, and with no upgrade path). Reign of XML/PDC is waning.
429 	 * For currently known NetXML servers, the value served is good without more
430 	 * conversions. If older devices pop up in the field, we can add an estimation
431 	 * by e.g. reported voltage and amps (to be an order of magnitude for power).
432 	 * Alternately we can look at model names and/or firmware versions or release
433 	 * dates, if we get those and if we know enough to map them to either logic. */
434 
435 	if (testvar("do_convert_deci")) {
436 		/* Old code for old devices: */
437 		if (mge_report_deprecation__convert_deci) {
438 			upslogx(LOG_NOTICE, "%s() is now deprecated, so values from XML are normally not decimated. This driver instance has however configured do_convert_deci in your ups.conf, so this behavior for old MGE NetXML-capable devices is preserved.", __func__);
439 			mge_report_deprecation__convert_deci = 0;
440 		}
441 		snprintf(mge_scratch_buf, sizeof(mge_scratch_buf), "%.1f", 0.1 * (float)(atoi(arg_val)));
442 		return mge_scratch_buf;
443 	}
444 
445 	if (mge_report_deprecation__convert_deci) {
446 		upslogx(LOG_NOTICE, "%s() is now deprecated, so values from XML are not decimated. If you happen to have an old MGE NetXML-capable device that now shows measurements 10x too big, and a firmware update does not solve this, please inform NUT devs via the issue tracker at %s with details about your hardware and firmware versions. Also try to enable do_convert_deci in your ups.conf", __func__, PACKAGE_BUGREPORT );
447 		mge_report_deprecation__convert_deci = 0;
448 	}
449 	upsdebugx(5, "%s() is now deprecated, so value '%s' is not decimated. If this change broke your setup, please see details logged above.", __func__, arg_val);
450 	return arg_val;
451 }
452 
453 /* Ignore a zero value if the UPS is not switched off */
ignore_if_zero(const char * arg_val)454 static const char *ignore_if_zero(const char *arg_val)
455 {
456 	if (atoi(arg_val) == 0) {
457 		return NULL;
458 	}
459 
460 	return convert_deci(arg_val);
461 }
462 
463 /* Set the 'ups.date' from the combined value
464  * (ex. 2008/03/01 15:23:26) and return the time */
split_date_time(const char * arg_val)465 static const char *split_date_time(const char *arg_val)
466 {
467 	char	*last = NULL;
468 
469 	snprintf(mge_scratch_buf, sizeof(mge_scratch_buf), "%s", arg_val);
470 	dstate_setinfo("ups.date", "%s", strtok_r(mge_scratch_buf, " -", &last));
471 
472 	return strtok_r(NULL, " ", &last);
473 }
474 
url_convert(const char * arg_val)475 static const char *url_convert(const char *arg_val)
476 {
477 	char	buf[256], *last = NULL;
478 
479 	snprintf(buf, sizeof(buf), "%s", arg_val);
480 	snprintf(mge_scratch_buf, sizeof(mge_scratch_buf), "/%s", strtok_r(buf, " \r\n\t", &last));
481 
482 	return mge_scratch_buf;
483 }
484 
mge_battery_capacity(const char * arg_val)485 static const char *mge_battery_capacity(const char *arg_val)
486 {
487 	snprintf(mge_scratch_buf, sizeof(mge_scratch_buf), "%.2f", (float)(atoi(arg_val)) / 3600.0);
488 	return mge_scratch_buf;
489 }
490 
mge_powerfactor_conversion(const char * arg_val)491 static const char *mge_powerfactor_conversion(const char *arg_val)
492 {
493 	snprintf(mge_scratch_buf, sizeof(mge_scratch_buf), "%.2f", (float)(atoi(arg_val)) / 100.0);
494 	return mge_scratch_buf;
495 }
496 
mge_beeper_info(const char * arg_val)497 static const char *mge_beeper_info(const char *arg_val)
498 {
499 	switch (atoi(arg_val))
500 	{
501 	case 1:
502 		return "disabled";
503 	case 2:
504 		return "enabled";
505 	case 3:
506 		return "muted";
507 	}
508 	return NULL;
509 }
510 
mge_upstype_conversion(const char * arg_val)511 static const char *mge_upstype_conversion(const char *arg_val)
512 {
513 	switch (atoi(arg_val))
514 	{
515 	case 1:
516 		return "offline / line interactive";
517 	case 2:
518 		return "online";
519 	case 3:
520 		return "online - unitary/parallel";
521 	case 4:
522 		return "online - parallel with hot standy";
523 	case 5:
524 		return "online - hot standby redundancy";
525 	}
526 	return NULL;
527 }
528 
mge_sensitivity_info(const char * arg_val)529 static const char *mge_sensitivity_info(const char *arg_val)
530 {
531 	switch (atoi(arg_val))
532 	{
533 	case 0:
534 		return "normal";
535 	case 1:
536 		return "high";
537 	case 2:
538 		return "low";
539 	}
540 	return NULL;
541 }
542 
mge_test_result_info(const char * arg_val)543 static const char *mge_test_result_info(const char *arg_val)
544 {
545 	STATUS_CLR(CAL);
546 	switch (atoi(arg_val))
547 	{
548 	case 1:
549 		return "done and passed";
550 	case 2:
551 		return "done and warning";
552 	case 3:
553 		return "done and error";
554 	case 4:
555 		return "aborted";
556 	case 5:
557 		STATUS_SET(CAL);
558 		return "in progress";
559 	case 6:
560 		return "no test initiated";
561 	case 7:
562 		return "test scheduled";
563 	}
564 	return NULL;
565 }
566 
mge_ambient_info(const char * arg_val)567 static const char *mge_ambient_info(const char *arg_val)
568 {
569 	switch (mge_ambient_value)
570 	{
571 	case 1:
572 		return arg_val;
573 	default:
574 		return NULL;
575 	}
576 }
577 
mge_timer_shutdown(const char * delay_before_shutoff)578 static const char *mge_timer_shutdown(const char *delay_before_shutoff)
579 {
580 	if (atoi(delay_before_shutoff) > -1 ) {
581 		STATUS_SET(SHUTDOWNIMM);
582 		mge_shutdown_pending = 1;
583 
584 		if( atoi(delay_before_shutoff) > shutdown_duration ) {
585 			STATUS_CLR(SHUTDOWNIMM);
586 			mge_shutdown_pending = 0;
587 		}
588 	} else {
589 		STATUS_CLR(SHUTDOWNIMM);
590 		mge_shutdown_pending = 0;
591 	}
592 
593 	return val;
594 }
595 
mge_shutdown_imminent(const char * arg_val)596 static const char *mge_shutdown_imminent(const char *arg_val)
597 {
598 	const int shutdown_delay = atoi(arg_val);
599 
600 	/* shutdown is already managed by mge_timer_shutdown, give up */
601 	if(mge_shutdown_pending) {
602 		return NULL;
603 	}
604 
605 	/* We may have "NONE" or "-1" or ?? as value
606 	 * We also double check both the string and numeric values to be zero!*/
607 	if ((arg_val) && (arg_val[0] == '0') && (shutdown_delay == 0)) {
608 		STATUS_SET(SHUTDOWNIMM);
609 	} else {
610 		STATUS_CLR(SHUTDOWNIMM);
611 	}
612 
613 	return NULL;
614 }
615 
616 static xml_info_t mge_xml2nut[] = {
617 	/* NMC configuration (mapped 1:1 for now) */
618 	{ "device.contact", ST_FLAG_RW, 0, "System.Contact", 0, 0, NULL },
619 	{ "device.location", ST_FLAG_RW, 0, "System.Location", 0, 0, NULL },
620 	/* Not used for now; might however be used in future for history & stats collection
621 	{ "System.History.Log.Interval", ST_FLAG_RW, 0, "System.History.Log.Interval", 0, 0, NULL },
622 	*/
623 #if (0)  /* not interresting for NUT */
624 	{ "System.Environment.Log.Interval", ST_FLAG_RW, 0, "System.Environment.Log.Interval", 0, 0, NULL },
625 	{ "System.Outlet[1].iName", ST_FLAG_RW, 0, "System.Outlet[1].iName", 0, 0, NULL },
626 	/* Mapped as ups.delay.shutdown
627 	{ "System.ShutdownDuration", ST_FLAG_RW, 0, "System.ShutdownDuration", 0, 0, NULL },
628 	*/
629 	{ "System.ShutdownTimerSelected", ST_FLAG_RW, 0, "System.ShutdownTimerSelected", 0, 0, NULL },
630 	{ "System.ShutdownTimer", ST_FLAG_RW, 0, "System.ShutdownTimer", 0, 0, NULL },
631 	/* Mapped as battery.runtime.low
632 	{ "System.RunTimeToEmptyLimit", ST_FLAG_RW, 0, "System.RunTimeToEmptyLimit", 0, 0, NULL },
633 	*/
634 	{ "System.RemainingCapacityLimit", ST_FLAG_RW, 0, "System.RemainingCapacityLimit", 0, 0, NULL },
635 	{ "System.RestartLevel", ST_FLAG_RW, 0, "System.RestartLevel", 0, 0, NULL },
636 	{ "System.Outlet[2].iName", ST_FLAG_RW, 0, "System.Outlet[2].iName", 0, 0, NULL },
637 	/* Mapped as outlet.1.delay.shutdown
638 	{ "System.Outlet[2].ShutdownDuration", ST_FLAG_RW, 0, "System.Outlet[2].ShutdownDuration", 0, 0, NULL },
639 	*/
640 	{ "System.Outlet[2].ShutdownTimer", ST_FLAG_RW, 0, "System.Outlet[2].ShutdownTimer", 0, 0, NULL },
641 	{ "System.Outlet[2].StartupTimer", ST_FLAG_RW, 0, "System.Outlet[2].StartupTimer", 0, 0, NULL },
642 	{ "System.Outlet[2].RemainingCapacityLimit", ST_FLAG_RW, 0, "System.Outlet[2].RemainingCapacityLimit", 0, 0, NULL },
643 	/* For future extension, and support of shutdown on load segment
644 	 * { "System.Outlet[2].RunTimeToShutdown", ST_FLAG_RW, 0, "System.Outlet[2].RunTimeToShutdown", 0, 0, NULL }, */
645 	{ "System.Outlet[3].iName", ST_FLAG_RW, 0, "System.Outlet[3].iName", 0, 0, NULL },
646 	/* Mapped as outlet.2.delay.shutdown
647 	{ "System.Outlet[3].ShutdownDuration", ST_FLAG_RW, 0, "System.Outlet[3].ShutdownDuration", 0, 0, NULL },
648 	*/
649 	{ "System.Outlet[3].ShutdownTimer", ST_FLAG_RW, 0, "System.Outlet[3].ShutdownTimer", 0, 0, NULL },
650 	{ "System.Outlet[3].StartupTimer", ST_FLAG_RW, 0, "System.Outlet[3].StartupTimer", 0, 0, NULL },
651 	{ "System.Outlet[3].RemainingCapacityLimit", ST_FLAG_RW, 0, "System.Outlet[3].RemainingCapacityLimit", 0, 0, NULL },
652 	/* For future extension, and support of shutdown on load segment
653 	 * { "System.Outlet[3].RunTimeToShutdown", ST_FLAG_RW, 0, "System.Outlet[3].RunTimeToShutdown", 0, 0, NULL }, */
654 	{ "System.Outlet[1].OffDelay", ST_FLAG_RW, 0, "System.Outlet[1].OffDelay", 0, 0, NULL },
655 	{ "System.Outlet[1].Toggle", ST_FLAG_RW, 0, "System.Outlet[1].Toggle", 0, 0, NULL },
656 	{ "System.Outlet[1].OnDelay", ST_FLAG_RW, 0, "System.Outlet[1].OnDelay", 0, 0, NULL },
657 	{ "System.Outlet[2].OffDelay", ST_FLAG_RW, 0, "System.Outlet[2].OffDelay", 0, 0, NULL },
658 	{ "System.Outlet[2].Toggle", ST_FLAG_RW, 0, "System.Outlet[2].Toggle", 0, 0, NULL },
659 	{ "System.Outlet[2].OnDelay", ST_FLAG_RW, 0, "System.Outlet[2].OnDelay", 0, 0, NULL },
660 	{ "System.Outlet[3].OffDelay", ST_FLAG_RW, 0, "System.Outlet[3].OffDelay", 0, 0, NULL },
661 	{ "System.Outlet[3].Toggle", ST_FLAG_RW, 0, "System.Outlet[3].Toggle", 0, 0, NULL },
662 	{ "System.Outlet[3].OnDelay", ST_FLAG_RW, 0, "System.Outlet[3].OnDelay", 0, 0, NULL },
663 	{ "System.Login", ST_FLAG_RW, 0, "System.Login", 0, 0, NULL },
664 	{ "System.Password", ST_FLAG_RW, 0, "System.Password", 0, 0, NULL },
665 	{ "System.Security", ST_FLAG_RW, 0, "System.Security", 0, 0, NULL },
666 	{ "System.FirmwareUpgrade", ST_FLAG_RW, 0, "System.FirmwareUpgrade", 0, 0, NULL },
667 	{ "System.Network.SNMP.ReadCommunity", ST_FLAG_RW, 0, "System.Network.SNMP.ReadCommunity", 0, 0, NULL },
668 	{ "System.Network.SNMP.ReadCommunityName", 0, 0, "System.Network.SNMP.ReadCommunityName", 0, 0, NULL },
669 	{ "System.Network.SNMP.ReadCommunitySecurityLevel", 0, 0, "System.Network.SNMP.ReadCommunitySecurityLevel", 0, 0, NULL },
670 	{ "System.Network.SNMP.ReadCommunitySecurityRight", 0, 0, "System.Network.SNMP.ReadCommunitySecurityRight", 0, 0, NULL },
671 	{ "System.Network.SNMP.WriteCommunity", ST_FLAG_RW, 0, "System.Network.SNMP.WriteCommunity", 0, 0, NULL },
672 	{ "System.Network.SNMP.WriteCommunityName", 0, 0, "System.Network.SNMP.WriteCommunityName", 0, 0, NULL },
673 	{ "System.Network.SNMP.WriteCommunitySecurityLevel", 0, 0, "System.Network.SNMP.WriteCommunitySecurityLevel", 0, 0, NULL },
674 	{ "System.Network.SNMP.WriteCommunitySecurityRight", ST_FLAG_RW, 0, "System.Network.SNMP.WriteCommunitySecurityRight", 0, 0, NULL },
675 	{ "System.Network.SNMP.Admin", ST_FLAG_RW, 0, "System.Network.SNMP.Admin", 0, 0, NULL },
676 	{ "System.Network.SNMP.AdminPassword", ST_FLAG_RW, 0, "System.Network.SNMP.AdminPassword", 0, 0, NULL },
677 	{ "System.Network.SNMP.AdminSecurityLevel", ST_FLAG_RW, 0, "System.Network.SNMP.AdminSecurityLevel", 0, 0, NULL },
678 	{ "System.Network.SNMP.AdminSecurityRight", 0, 0, "System.Network.SNMP.AdminSecurityRight", 0, 0, NULL },
679 	{ "System.Network.SNMP.User", ST_FLAG_RW, 0, "System.Network.SNMP.User", 0, 0, NULL },
680 	{ "System.Network.SNMP.UserPassword", ST_FLAG_RW, 0, "System.Network.SNMP.UserPassword", 0, 0, NULL },
681 	{ "System.Network.SNMP.UserSecurityLevel", ST_FLAG_RW, 0, "System.Network.SNMP.UserSecurityLevel", 0, 0, NULL },
682 	{ "System.Network.SNMP.UserSecurityRight", 0, 0, "System.Network.SNMP.UserSecurityRight", 0, 0, NULL },
683 	{ "System.Network.SNMP.NotificationUserName", ST_FLAG_RW, 0, "System.Network.SNMP.NotificationUserName", 0, 0, NULL },
684 	{ "System.Network.SNMP.snmpVersion", ST_FLAG_RW, 0, "System.Network.SNMP.snmpVersion", 0, 0, NULL },
685 	{ "System.Network.SNMP.engineBoots", 0, 0, "System.Network.SNMP.engineBoots", 0, 0, NULL },
686 	{ "System.Network.Telnet.Access", ST_FLAG_RW, 0, "System.Network.Telnet.Access", 0, 0, NULL },
687 	{ "System.Network.Telnet.Security", ST_FLAG_RW, 0, "System.Network.Telnet.Security", 0, 0, NULL },
688 	{ "System.Network.Telnet.Console", ST_FLAG_RW, 0, "System.Network.Telnet.Console", 0, 0, NULL },
689 	{ "System.Email.Sender", ST_FLAG_RW, 0, "System.Email.Sender", 0, 0, NULL },
690 	{ "System.Email.Subject", ST_FLAG_RW, 0, "System.Email.Subject", 0, 0, NULL },
691 	{ "System.Email.UPSName", ST_FLAG_RW, 0, "System.Email.UPSName", 0, 0, NULL },
692 	{ "System.Email.Message", ST_FLAG_RW, 0, "System.Email.Message", 0, 0, NULL },
693 	{ "System.Email.Localization", ST_FLAG_RW, 0, "System.Email.Localization", 0, 0, NULL },
694 	{ "System.Email.EventName", ST_FLAG_RW, 0, "System.Email.EventName", 0, 0, NULL },
695 	{ "System.Email[0].Recipient", ST_FLAG_RW, 0, "System.Email[0].Recipient", 0, 0, NULL },
696 	{ "System.Email[0].Selected", ST_FLAG_RW, 0, "System.Email[0].Selected", 0, 0, NULL },
697 	{ "System.Email[0].Enotify", ST_FLAG_RW, 0, "System.Email[0].Enotify", 0, 0, NULL },
698 	{ "System.Email[0].Measures.Log", ST_FLAG_RW, 0, "System.Email[0].Measures.Log", 0, 0, NULL },
699 	{ "System.Email[0].Events.Log", ST_FLAG_RW, 0, "System.Email[0].Events.Log", 0, 0, NULL },
700 	{ "System.Email[0].SystemEvents.Log", ST_FLAG_RW, 0, "System.Email[0].SystemEvents.Log", 0, 0, NULL },
701 	{ "System.Email[0].Environment.Log", ST_FLAG_RW, 0, "System.Email[0].Environment.Log", 0, 0, NULL },
702 	{ "System.Email[0].Report.Periodicity", ST_FLAG_RW, 0, "System.Email[0].Report.Periodicity", 0, 0, NULL },
703 	{ "System.Email[0].Report.Hour", ST_FLAG_RW, 0, "System.Email[0].Report.Hour", 0, 0, NULL },
704 	{ "System.Email[0].Report.Next", ST_FLAG_RW, 0, "System.Email[0].Report.Next", 0, 0, NULL },
705 	{ "System.Email[0].EventList.Discharging", ST_FLAG_RW, 0, "System.Email[0].EventList.Discharging", 0, 0, NULL },
706 	{ "System.Email[0].EventList.ACPresent", ST_FLAG_RW, 0, "System.Email[0].EventList.ACPresent", 0, 0, NULL },
707 	{ "System.Email[0].EventList.RunTimeToShutdown", ST_FLAG_RW, 0, "System.Email[0].EventList.RunTimeToShutdown", 0, 0, NULL },
708 	{ "System.Email[0].EventList.BelowRemainingCapacityLimit", ST_FLAG_RW, 0, "System.Email[0].EventList.BelowRemainingCapacityLimit", 0, 0, NULL },
709 	{ "System.Email[0].EventList.NeedReplacement.1", ST_FLAG_RW, 0, "System.Email[0].EventList.NeedReplacement.1", 0, 0, NULL },
710 	{ "System.Email[0].EventList.NeedReplacement.0", ST_FLAG_RW, 0, "System.Email[0].EventList.NeedReplacement.0", 0, 0, NULL },
711 	{ "System.Email[0].EventList.Overload.1", ST_FLAG_RW, 0, "System.Email[0].EventList.Overload.1", 0, 0, NULL },
712 	{ "System.Email[0].EventList.Overload.0", ST_FLAG_RW, 0, "System.Email[0].EventList.Overload.0", 0, 0, NULL },
713 	{ "System.Email[0].EventList.InternalFailure.1", ST_FLAG_RW, 0, "System.Email[0].EventList.InternalFailure.1", 0, 0, NULL },
714 	{ "System.Email[0].EventList.InternalFailure.0", ST_FLAG_RW, 0, "System.Email[0].EventList.InternalFailure.0", 0, 0, NULL },
715 	{ "System.Email[0].EventList.CommunicationLost.1", ST_FLAG_RW, 0, "System.Email[0].EventList.CommunicationLost.1", 0, 0, NULL },
716 	{ "System.Email[0].EventList.CommunicationLost.0", ST_FLAG_RW, 0, "System.Email[0].EventList.CommunicationLost.0", 0, 0, NULL },
717 	{ "System.Email[0].EventList.Charger.InternalFailure", ST_FLAG_RW, 0, "System.Email[0].EventList.Charger.InternalFailure", 0, 0, NULL },
718 	{ "System.Email[0].EventList.Input[2].Used.1", ST_FLAG_RW, 0, "System.Email[0].EventList.Input[2].Used.1", 0, 0, NULL },
719 	{ "System.Email[0].EventList.Input[2].Used.0", ST_FLAG_RW, 0, "System.Email[0].EventList.Input[2].Used.0", 0, 0, NULL },
720 	{ "System.Email[0].EventList.PowerModule.RedundancyLost.1", ST_FLAG_RW, 0, "System.Email[0].EventList.PowerModule.RedundancyLost.1", 0, 0, NULL },
721 	{ "System.Email[0].EventList.PowerModule.RedundancyLost.0", ST_FLAG_RW, 0, "System.Email[0].EventList.PowerModule.RedundancyLost.0", 0, 0, NULL },
722 	{ "System.Email[0].EventList.PowerModule.ProtectionLost.1", ST_FLAG_RW, 0, "System.Email[0].EventList.PowerModule.ProtectionLost.1", 0, 0, NULL },
723 	{ "System.Email[0].EventList.PowerModule.ProtectionLost.0", ST_FLAG_RW, 0, "System.Email[0].EventList.PowerModule.ProtectionLost.0", 0, 0, NULL },
724 	{ "System.Email[0].EventList.FirmwareUpgrade", ST_FLAG_RW, 0, "System.Email[0].EventList.FirmwareUpgrade", 0, 0, NULL },
725 	{ "System.Email[0].EventList.Environment.CommunicationLost", ST_FLAG_RW, 0, "System.Email[0].EventList.Environment.CommunicationLost", 0, 0, NULL },
726 	{ "System.Email[0].EventList.Environment.Notify", ST_FLAG_RW, 0, "System.Email[0].EventList.Environment.Notify", 0, 0, NULL },
727 	{ "System.Email[1].Recipient", ST_FLAG_RW, 0, "System.Email[1].Recipient", 0, 0, NULL },
728 	{ "System.Email[1].Selected", ST_FLAG_RW, 0, "System.Email[1].Selected", 0, 0, NULL },
729 	{ "System.Email[1].Enotify", ST_FLAG_RW, 0, "System.Email[1].Enotify", 0, 0, NULL },
730 	{ "System.Email[1].Measures.Log", ST_FLAG_RW, 0, "System.Email[1].Measures.Log", 0, 0, NULL },
731 	{ "System.Email[1].Events.Log", ST_FLAG_RW, 0, "System.Email[1].Events.Log", 0, 0, NULL },
732 	{ "System.Email[1].SystemEvents.Log", ST_FLAG_RW, 0, "System.Email[1].SystemEvents.Log", 0, 0, NULL },
733 	{ "System.Email[1].Environment.Log", ST_FLAG_RW, 0, "System.Email[1].Environment.Log", 0, 0, NULL },
734 	{ "System.Email[1].Report.Periodicity", ST_FLAG_RW, 0, "System.Email[1].Report.Periodicity", 0, 0, NULL },
735 	{ "System.Email[1].Report.Hour", ST_FLAG_RW, 0, "System.Email[1].Report.Hour", 0, 0, NULL },
736 	{ "System.Email[1].Report.Next", ST_FLAG_RW, 0, "System.Email[1].Report.Next", 0, 0, NULL },
737 	{ "System.Email[1].EventList.Discharging", ST_FLAG_RW, 0, "System.Email[1].EventList.Discharging", 0, 0, NULL },
738 	{ "System.Email[1].EventList.ACPresent", ST_FLAG_RW, 0, "System.Email[1].EventList.ACPresent", 0, 0, NULL },
739 	{ "System.Email[1].EventList.RunTimeToShutdown", ST_FLAG_RW, 0, "System.Email[1].EventList.RunTimeToShutdown", 0, 0, NULL },
740 	{ "System.Email[1].EventList.BelowRemainingCapacityLimit", ST_FLAG_RW, 0, "System.Email[1].EventList.BelowRemainingCapacityLimit", 0, 0, NULL },
741 	{ "System.Email[1].EventList.NeedReplacement.1", ST_FLAG_RW, 0, "System.Email[1].EventList.NeedReplacement.1", 0, 0, NULL },
742 	{ "System.Email[1].EventList.NeedReplacement.0", ST_FLAG_RW, 0, "System.Email[1].EventList.NeedReplacement.0", 0, 0, NULL },
743 	{ "System.Email[1].EventList.Overload.1", ST_FLAG_RW, 0, "System.Email[1].EventList.Overload.1", 0, 0, NULL },
744 	{ "System.Email[1].EventList.Overload.0", ST_FLAG_RW, 0, "System.Email[1].EventList.Overload.0", 0, 0, NULL },
745 	{ "System.Email[1].EventList.InternalFailure.1", ST_FLAG_RW, 0, "System.Email[1].EventList.InternalFailure.1", 0, 0, NULL },
746 	{ "System.Email[1].EventList.InternalFailure.0", ST_FLAG_RW, 0, "System.Email[1].EventList.InternalFailure.0", 0, 0, NULL },
747 	{ "System.Email[1].EventList.CommunicationLost.1", ST_FLAG_RW, 0, "System.Email[1].EventList.CommunicationLost.1", 0, 0, NULL },
748 	{ "System.Email[1].EventList.CommunicationLost.0", ST_FLAG_RW, 0, "System.Email[1].EventList.CommunicationLost.0", 0, 0, NULL },
749 	{ "System.Email[1].EventList.Charger.InternalFailure", ST_FLAG_RW, 0, "System.Email[1].EventList.Charger.InternalFailure", 0, 0, NULL },
750 	{ "System.Email[1].EventList.Input[2].Used.1", ST_FLAG_RW, 0, "System.Email[1].EventList.Input[2].Used.1", 0, 0, NULL },
751 	{ "System.Email[1].EventList.Input[2].Used.0", ST_FLAG_RW, 0, "System.Email[1].EventList.Input[2].Used.0", 0, 0, NULL },
752 	{ "System.Email[1].EventList.PowerModule.RedundancyLost.1", ST_FLAG_RW, 0, "System.Email[1].EventList.PowerModule.RedundancyLost.1", 0, 0, NULL },
753 	{ "System.Email[1].EventList.PowerModule.RedundancyLost.0", ST_FLAG_RW, 0, "System.Email[1].EventList.PowerModule.RedundancyLost.0", 0, 0, NULL },
754 	{ "System.Email[1].EventList.PowerModule.ProtectionLost.1", ST_FLAG_RW, 0, "System.Email[1].EventList.PowerModule.ProtectionLost.1", 0, 0, NULL },
755 	{ "System.Email[1].EventList.PowerModule.ProtectionLost.0", ST_FLAG_RW, 0, "System.Email[1].EventList.PowerModule.ProtectionLost.0", 0, 0, NULL },
756 	{ "System.Email[1].EventList.FirmwareUpgrade", ST_FLAG_RW, 0, "System.Email[1].EventList.FirmwareUpgrade", 0, 0, NULL },
757 	{ "System.Email[1].EventList.Environment.CommunicationLost", ST_FLAG_RW, 0, "System.Email[1].EventList.Environment.CommunicationLost", 0, 0, NULL },
758 	{ "System.Email[1].EventList.Environment.Notify", ST_FLAG_RW, 0, "System.Email[1].EventList.Environment.Notify", 0, 0, NULL },
759 	{ "System.Email[2].Recipient", ST_FLAG_RW, 0, "System.Email[2].Recipient", 0, 0, NULL },
760 	{ "System.Email[2].Selected", ST_FLAG_RW, 0, "System.Email[2].Selected", 0, 0, NULL },
761 	{ "System.Email[2].Enotify", ST_FLAG_RW, 0, "System.Email[2].Enotify", 0, 0, NULL },
762 	{ "System.Email[2].Measures.Log", ST_FLAG_RW, 0, "System.Email[2].Measures.Log", 0, 0, NULL },
763 	{ "System.Email[2].Events.Log", ST_FLAG_RW, 0, "System.Email[2].Events.Log", 0, 0, NULL },
764 	{ "System.Email[2].SystemEvents.Log", ST_FLAG_RW, 0, "System.Email[2].SystemEvents.Log", 0, 0, NULL },
765 	{ "System.Email[2].Environment.Log", ST_FLAG_RW, 0, "System.Email[2].Environment.Log", 0, 0, NULL },
766 	{ "System.Email[2].Report.Periodicity", ST_FLAG_RW, 0, "System.Email[2].Report.Periodicity", 0, 0, NULL },
767 	{ "System.Email[2].Report.Hour", ST_FLAG_RW, 0, "System.Email[2].Report.Hour", 0, 0, NULL },
768 	{ "System.Email[2].Report.Next", ST_FLAG_RW, 0, "System.Email[2].Report.Next", 0, 0, NULL },
769 	{ "System.Email[2].EventList.Discharging", ST_FLAG_RW, 0, "System.Email[2].EventList.Discharging", 0, 0, NULL },
770 	{ "System.Email[2].EventList.ACPresent", ST_FLAG_RW, 0, "System.Email[2].EventList.ACPresent", 0, 0, NULL },
771 	{ "System.Email[2].EventList.RunTimeToShutdown", ST_FLAG_RW, 0, "System.Email[2].EventList.RunTimeToShutdown", 0, 0, NULL },
772 	{ "System.Email[2].EventList.BelowRemainingCapacityLimit", ST_FLAG_RW, 0, "System.Email[2].EventList.BelowRemainingCapacityLimit", 0, 0, NULL },
773 	{ "System.Email[2].EventList.NeedReplacement.1", ST_FLAG_RW, 0, "System.Email[2].EventList.NeedReplacement.1", 0, 0, NULL },
774 	{ "System.Email[2].EventList.NeedReplacement.0", ST_FLAG_RW, 0, "System.Email[2].EventList.NeedReplacement.0", 0, 0, NULL },
775 	{ "System.Email[2].EventList.Overload.1", ST_FLAG_RW, 0, "System.Email[2].EventList.Overload.1", 0, 0, NULL },
776 	{ "System.Email[2].EventList.Overload.0", ST_FLAG_RW, 0, "System.Email[2].EventList.Overload.0", 0, 0, NULL },
777 	{ "System.Email[2].EventList.InternalFailure.1", ST_FLAG_RW, 0, "System.Email[2].EventList.InternalFailure.1", 0, 0, NULL },
778 	{ "System.Email[2].EventList.InternalFailure.0", ST_FLAG_RW, 0, "System.Email[2].EventList.InternalFailure.0", 0, 0, NULL },
779 	{ "System.Email[2].EventList.CommunicationLost.1", ST_FLAG_RW, 0, "System.Email[2].EventList.CommunicationLost.1", 0, 0, NULL },
780 	{ "System.Email[2].EventList.CommunicationLost.0", ST_FLAG_RW, 0, "System.Email[2].EventList.CommunicationLost.0", 0, 0, NULL },
781 	{ "System.Email[2].EventList.Charger.InternalFailure", ST_FLAG_RW, 0, "System.Email[2].EventList.Charger.InternalFailure", 0, 0, NULL },
782 	{ "System.Email[2].EventList.Input[2].Used.1", ST_FLAG_RW, 0, "System.Email[2].EventList.Input[2].Used.1", 0, 0, NULL },
783 	{ "System.Email[2].EventList.Input[2].Used.0", ST_FLAG_RW, 0, "System.Email[2].EventList.Input[2].Used.0", 0, 0, NULL },
784 	{ "System.Email[2].EventList.PowerModule.RedundancyLost.1", ST_FLAG_RW, 0, "System.Email[2].EventList.PowerModule.RedundancyLost.1", 0, 0, NULL },
785 	{ "System.Email[2].EventList.PowerModule.RedundancyLost.0", ST_FLAG_RW, 0, "System.Email[2].EventList.PowerModule.RedundancyLost.0", 0, 0, NULL },
786 	{ "System.Email[2].EventList.PowerModule.ProtectionLost.1", ST_FLAG_RW, 0, "System.Email[2].EventList.PowerModule.ProtectionLost.1", 0, 0, NULL },
787 	{ "System.Email[2].EventList.PowerModule.ProtectionLost.0", ST_FLAG_RW, 0, "System.Email[2].EventList.PowerModule.ProtectionLost.0", 0, 0, NULL },
788 	{ "System.Email[2].EventList.FirmwareUpgrade", ST_FLAG_RW, 0, "System.Email[2].EventList.FirmwareUpgrade", 0, 0, NULL },
789 	{ "System.Email[2].EventList.Environment.CommunicationLost", ST_FLAG_RW, 0, "System.Email[2].EventList.Environment.CommunicationLost", 0, 0, NULL },
790 	{ "System.Email[2].EventList.Environment.Notify", ST_FLAG_RW, 0, "System.Email[2].EventList.Environment.Notify", 0, 0, NULL },
791 	{ "System.Email[3].Recipient", ST_FLAG_RW, 0, "System.Email[3].Recipient", 0, 0, NULL },
792 	{ "System.Email[3].Selected", ST_FLAG_RW, 0, "System.Email[3].Selected", 0, 0, NULL },
793 	{ "System.Email[3].Enotify", ST_FLAG_RW, 0, "System.Email[3].Enotify", 0, 0, NULL },
794 	{ "System.Email[3].Measures.Log", ST_FLAG_RW, 0, "System.Email[3].Measures.Log", 0, 0, NULL },
795 	{ "System.Email[3].Events.Log", ST_FLAG_RW, 0, "System.Email[3].Events.Log", 0, 0, NULL },
796 	{ "System.Email[3].SystemEvents.Log", ST_FLAG_RW, 0, "System.Email[3].SystemEvents.Log", 0, 0, NULL },
797 	{ "System.Email[3].Environment.Log", ST_FLAG_RW, 0, "System.Email[3].Environment.Log", 0, 0, NULL },
798 	{ "System.Email[3].Report.Periodicity", ST_FLAG_RW, 0, "System.Email[3].Report.Periodicity", 0, 0, NULL },
799 	{ "System.Email[3].Report.Hour", ST_FLAG_RW, 0, "System.Email[3].Report.Hour", 0, 0, NULL },
800 	{ "System.Email[3].Report.Next", ST_FLAG_RW, 0, "System.Email[3].Report.Next", 0, 0, NULL },
801 	{ "System.Email[3].EventList.Discharging", ST_FLAG_RW, 0, "System.Email[3].EventList.Discharging", 0, 0, NULL },
802 	{ "System.Email[3].EventList.ACPresent", ST_FLAG_RW, 0, "System.Email[3].EventList.ACPresent", 0, 0, NULL },
803 	{ "System.Email[3].EventList.RunTimeToShutdown", ST_FLAG_RW, 0, "System.Email[3].EventList.RunTimeToShutdown", 0, 0, NULL },
804 	{ "System.Email[3].EventList.BelowRemainingCapacityLimit", ST_FLAG_RW, 0, "System.Email[3].EventList.BelowRemainingCapacityLimit", 0, 0, NULL },
805 	{ "System.Email[3].EventList.NeedReplacement.1", ST_FLAG_RW, 0, "System.Email[3].EventList.NeedReplacement.1", 0, 0, NULL },
806 	{ "System.Email[3].EventList.NeedReplacement.0", ST_FLAG_RW, 0, "System.Email[3].EventList.NeedReplacement.0", 0, 0, NULL },
807 	{ "System.Email[3].EventList.Overload.1", ST_FLAG_RW, 0, "System.Email[3].EventList.Overload.1", 0, 0, NULL },
808 	{ "System.Email[3].EventList.Overload.0", ST_FLAG_RW, 0, "System.Email[3].EventList.Overload.0", 0, 0, NULL },
809 	{ "System.Email[3].EventList.InternalFailure.1", ST_FLAG_RW, 0, "System.Email[3].EventList.InternalFailure.1", 0, 0, NULL },
810 	{ "System.Email[3].EventList.InternalFailure.0", ST_FLAG_RW, 0, "System.Email[3].EventList.InternalFailure.0", 0, 0, NULL },
811 	{ "System.Email[3].EventList.CommunicationLost.1", ST_FLAG_RW, 0, "System.Email[3].EventList.CommunicationLost.1", 0, 0, NULL },
812 	{ "System.Email[3].EventList.CommunicationLost.0", ST_FLAG_RW, 0, "System.Email[3].EventList.CommunicationLost.0", 0, 0, NULL },
813 	{ "System.Email[3].EventList.Charger.InternalFailure", ST_FLAG_RW, 0, "System.Email[3].EventList.Charger.InternalFailure", 0, 0, NULL },
814 	{ "System.Email[3].EventList.Input[2].Used.1", ST_FLAG_RW, 0, "System.Email[3].EventList.Input[2].Used.1", 0, 0, NULL },
815 	{ "System.Email[3].EventList.Input[2].Used.0", ST_FLAG_RW, 0, "System.Email[3].EventList.Input[2].Used.0", 0, 0, NULL },
816 	{ "System.Email[3].EventList.PowerModule.RedundancyLost.1", ST_FLAG_RW, 0, "System.Email[3].EventList.PowerModule.RedundancyLost.1", 0, 0, NULL },
817 	{ "System.Email[3].EventList.PowerModule.RedundancyLost.0", ST_FLAG_RW, 0, "System.Email[3].EventList.PowerModule.RedundancyLost.0", 0, 0, NULL },
818 	{ "System.Email[3].EventList.PowerModule.ProtectionLost.1", ST_FLAG_RW, 0, "System.Email[3].EventList.PowerModule.ProtectionLost.1", 0, 0, NULL },
819 	{ "System.Email[3].EventList.PowerModule.ProtectionLost.0", ST_FLAG_RW, 0, "System.Email[3].EventList.PowerModule.ProtectionLost.0", 0, 0, NULL },
820 	{ "System.Email[3].EventList.FirmwareUpgrade", ST_FLAG_RW, 0, "System.Email[3].EventList.FirmwareUpgrade", 0, 0, NULL },
821 	{ "System.Email[3].EventList.Environment.CommunicationLost", ST_FLAG_RW, 0, "System.Email[3].EventList.Environment.CommunicationLost", 0, 0, NULL },
822 	{ "System.Email[3].EventList.Environment.Notify", ST_FLAG_RW, 0, "System.Email[3].EventList.Environment.Notify", 0, 0, NULL },
823 	{ "System.Schedule[0].Off", ST_FLAG_RW, 0, "System.Schedule[0].Off", 0, 0, NULL },
824 	{ "System.Schedule[0].On", ST_FLAG_RW, 0, "System.Schedule[0].On", 0, 0, NULL },
825 	{ "System.Schedule[1].Off", ST_FLAG_RW, 0, "System.Schedule[1].Off", 0, 0, NULL },
826 	{ "System.Schedule[1].On", ST_FLAG_RW, 0, "System.Schedule[1].On", 0, 0, NULL },
827 	{ "System.Schedule[2].Off", ST_FLAG_RW, 0, "System.Schedule[2].Off", 0, 0, NULL },
828 	{ "System.Schedule[2].On", ST_FLAG_RW, 0, "System.Schedule[2].On", 0, 0, NULL },
829 	{ "System.Schedule[3].Off", ST_FLAG_RW, 0, "System.Schedule[3].Off", 0, 0, NULL },
830 	{ "System.Schedule[3].On", ST_FLAG_RW, 0, "System.Schedule[3].On", 0, 0, NULL },
831 	{ "System.Schedule[4].Off", ST_FLAG_RW, 0, "System.Schedule[4].Off", 0, 0, NULL },
832 	{ "System.Schedule[4].On", ST_FLAG_RW, 0, "System.Schedule[4].On", 0, 0, NULL },
833 	{ "System.Schedule[5].Off", ST_FLAG_RW, 0, "System.Schedule[5].Off", 0, 0, NULL },
834 	{ "System.Schedule[5].On", ST_FLAG_RW, 0, "System.Schedule[5].On", 0, 0, NULL },
835 	{ "System.Schedule[6].Off", ST_FLAG_RW, 0, "System.Schedule[6].Off", 0, 0, NULL },
836 	{ "System.Schedule[6].On", ST_FLAG_RW, 0, "System.Schedule[6].On", 0, 0, NULL },
837 	{ "System.NetworkManagementSystem[0].Name", ST_FLAG_RW, 0, "System.NetworkManagementSystem[0].Name", 0, 0, NULL },
838 	{ "System.NetworkManagementSystem[0].HostName", ST_FLAG_RW, 0, "System.NetworkManagementSystem[0].HostName", 0, 0, NULL },
839 	{ "System.NetworkManagementSystem[0].TrapCommunity", ST_FLAG_RW, 0, "System.NetworkManagementSystem[0].TrapCommunity", 0, 0, NULL },
840 	{ "System.NetworkManagementSystem[0].TrapSnmpVersion", ST_FLAG_RW, 0, "System.NetworkManagementSystem[0].TrapSnmpVersion", 0, 0, NULL },
841 	{ "System.NetworkManagementSystem[0].TrapSelectedMibs", ST_FLAG_RW, 0, "System.NetworkManagementSystem[0].TrapSelectedMibs", 0, 0, NULL },
842 	{ "System.NetworkManagementSystem[1].Name", ST_FLAG_RW, 0, "System.NetworkManagementSystem[1].Name", 0, 0, NULL },
843 	{ "System.NetworkManagementSystem[1].HostName", ST_FLAG_RW, 0, "System.NetworkManagementSystem[1].HostName", 0, 0, NULL },
844 	{ "System.NetworkManagementSystem[1].TrapCommunity", ST_FLAG_RW, 0, "System.NetworkManagementSystem[1].TrapCommunity", 0, 0, NULL },
845 	{ "System.NetworkManagementSystem[1].TrapSnmpVersion", ST_FLAG_RW, 0, "System.NetworkManagementSystem[1].TrapSnmpVersion", 0, 0, NULL },
846 	{ "System.NetworkManagementSystem[1].TrapSelectedMibs", ST_FLAG_RW, 0, "System.NetworkManagementSystem[1].TrapSelectedMibs", 0, 0, NULL },
847 	{ "System.NetworkManagementSystem[2].Name", ST_FLAG_RW, 0, "System.NetworkManagementSystem[2].Name", 0, 0, NULL },
848 	{ "System.NetworkManagementSystem[2].HostName", ST_FLAG_RW, 0, "System.NetworkManagementSystem[2].HostName", 0, 0, NULL },
849 	{ "System.NetworkManagementSystem[2].TrapCommunity", ST_FLAG_RW, 0, "System.NetworkManagementSystem[2].TrapCommunity", 0, 0, NULL },
850 	{ "System.NetworkManagementSystem[2].TrapSnmpVersion", ST_FLAG_RW, 0, "System.NetworkManagementSystem[2].TrapSnmpVersion", 0, 0, NULL },
851 	{ "System.NetworkManagementSystem[2].TrapSelectedMibs", ST_FLAG_RW, 0, "System.NetworkManagementSystem[2].TrapSelectedMibs", 0, 0, NULL },
852 	{ "System.ClientCfg.ShutdownTimer.Select", ST_FLAG_RW, 0, "System.ClientCfg.ShutdownTimer.Select", 0, 0, NULL },
853 	{ "System.ClientCfg.ShutdownTimer", ST_FLAG_RW, 0, "System.ClientCfg.ShutdownTimer", 0, 0, NULL },
854 	{ "System.ClientCfg.ShutdownDuration", ST_FLAG_RW, 0, "System.ClientCfg.ShutdownDuration", 0, 0, NULL },
855 	{ "System.ClientCfg.BroadcastAdmins", ST_FLAG_RW, 0, "System.ClientCfg.BroadcastAdmins", 0, 0, NULL },
856 	{ "System.ClientCfg.BroadcastUsers", ST_FLAG_RW, 0, "System.ClientCfg.BroadcastUsers", 0, 0, NULL },
857 	{ "Environment.iName", ST_FLAG_RW, 0, "Environment.iName", 0, 0, NULL },
858 	{ "Environment.Temperature.Unit", ST_FLAG_RW, 0, "Environment.Temperature.Unit", 0, 0, NULL },
859 	{ "Environment.Temperature.Hysteresis", ST_FLAG_RW, 0, "Environment.Temperature.Hysteresis", 0, 0, NULL },
860 	{ "Environment.Temperature.Offset", ST_FLAG_RW, 0, "Environment.Temperature.Offset", 0, 0, NULL },
861 	{ "Environment.Temperature.HighNotify", ST_FLAG_RW, 0, "Environment.Temperature.HighNotify", 0, 0, NULL },
862 	{ "Environment.Temperature.LowNotify", ST_FLAG_RW, 0, "Environment.Temperature.LowNotify", 0, 0, NULL },
863 	{ "Environment.Temperature.HighShutdown", ST_FLAG_RW, 0, "Environment.Temperature.HighShutdown", 0, 0, NULL },
864 	{ "Environment.Temperature.LowShutdown", ST_FLAG_RW, 0, "Environment.Temperature.LowShutdown", 0, 0, NULL },
865 	{ "Environment.Humidity.Hysteresis", ST_FLAG_RW, 0, "Environment.Humidity.Hysteresis", 0, 0, NULL },
866 	{ "Environment.Humidity.Offset", ST_FLAG_RW, 0, "Environment.Humidity.Offset", 0, 0, NULL },
867 	{ "Environment.Humidity.HighNotify", ST_FLAG_RW, 0, "Environment.Humidity.HighNotify", 0, 0, NULL },
868 	{ "Environment.Humidity.LowNotify", ST_FLAG_RW, 0, "Environment.Humidity.LowNotify", 0, 0, NULL },
869 	{ "Environment.Humidity.HighShutdown", ST_FLAG_RW, 0, "Environment.Humidity.HighShutdown", 0, 0, NULL },
870 	{ "Environment.Humidity.LowShutdown", ST_FLAG_RW, 0, "Environment.Humidity.LowShutdown", 0, 0, NULL },
871 	{ "Environment.Input[1].iName", ST_FLAG_RW, 0, "Environment.Input[1].iName", 0, 0, NULL },
872 	{ "Environment.Input[1].State[0].Description", ST_FLAG_RW, 0, "Environment.Input[1].State[0].Description", 0, 0, NULL },
873 	{ "Environment.Input[1].State[0].Notify", ST_FLAG_RW, 0, "Environment.Input[1].State[0].Notify", 0, 0, NULL },
874 	{ "Environment.Input[1].State[0].Shutdown", ST_FLAG_RW, 0, "Environment.Input[1].State[0].Shutdown", 0, 0, NULL },
875 	{ "Environment.Input[1].State[1].Description", ST_FLAG_RW, 0, "Environment.Input[1].State[1].Description", 0, 0, NULL },
876 	{ "Environment.Input[1].State[1].Notify", ST_FLAG_RW, 0, "Environment.Input[1].State[1].Notify", 0, 0, NULL },
877 	{ "Environment.Input[1].State[1].Shutdown", ST_FLAG_RW, 0, "Environment.Input[1].State[1].Shutdown", 0, 0, NULL },
878 	{ "Environment.Input[2].iName", ST_FLAG_RW, 0, "Environment.Input[2].iName", 0, 0, NULL },
879 	{ "Environment.Input[2].State[0].Description", ST_FLAG_RW, 0, "Environment.Input[2].State[0].Description", 0, 0, NULL },
880 	{ "Environment.Input[2].State[0].Notify", ST_FLAG_RW, 0, "Environment.Input[2].State[0].Notify", 0, 0, NULL },
881 	{ "Environment.Input[2].State[0].Shutdown", ST_FLAG_RW, 0, "Environment.Input[2].State[0].Shutdown", 0, 0, NULL },
882 	{ "Environment.Input[2].State[1].Description", ST_FLAG_RW, 0, "Environment.Input[2].State[1].Description", 0, 0, NULL },
883 	{ "Environment.Input[2].State[1].Notify", ST_FLAG_RW, 0, "Environment.Input[2].State[1].Notify", 0, 0, NULL },
884 	{ "Environment.Input[2].State[1].Shutdown", ST_FLAG_RW, 0, "Environment.Input[2].State[1].Shutdown", 0, 0, NULL },
885 	{ "System.TimeSync", ST_FLAG_RW, 0, "System.TimeSync", 0, 0, NULL },
886 	{ "System.TimeNtp", ST_FLAG_RW, 0, "System.TimeNtp", 0, 0, NULL },
887 	{ "System.TimeZone", ST_FLAG_RW, 0, "System.TimeZone", 0, 0, NULL },
888 	{ "System.TimeDaylight", ST_FLAG_RW, 0, "System.TimeDaylight", 0, 0, NULL },
889 #endif  /* not interresting for NUT */
890 
891 	/* Special case: boolean values that are mapped to ups.status and ups.alarm */
892 	{ NULL, 0, 0, "UPS.PowerSummary.PresentStatus.ACPresent", 0, 0, online_info },
893 	{ NULL, 0, 0, "UPS.PowerSummary.PresentStatus.Charging", 0, 0, charging_info },
894 	/* NMC bug: keep discharging test AFTER charging test */
895 	{ NULL, 0, 0, "UPS.PowerSummary.PresentStatus.Discharging", 0, 0, discharging_info },
896 	{ NULL, 0, 0, "UPS.PowerSummary.PresentStatus.BelowRemainingCapacityLimit", 0, 0, lowbatt_info },
897 	{ NULL, 0, 0, "UPS.PowerSummary.PresentStatus.Overload", 0, 0, overload_info },
898 	{ NULL, 0, 0, "UPS.PowerSummary.PresentStatus.NeedReplacement", 0, 0, replacebatt_info },
899 	{ NULL, 0, 0, "UPS.PowerConverter.Input[1].PresentStatus.Buck", 0, 0, trim_info },
900 	{ NULL, 0, 0, "UPS.PowerConverter.Input[1].PresentStatus.Boost", 0, 0, boost_info },
901 	{ NULL, 0, 0, "UPS.PowerConverter.Input[1].PresentStatus.VoltageOutOfRange", 0, 0, vrange_info },
902 	{ NULL, 0, 0, "UPS.PowerConverter.Input[1].PresentStatus.FrequencyOutOfRange", 0, 0, frange_info },
903 	{ NULL, 0, 0, "UPS.PowerConverter.Input[1].PresentStatus.FuseFault", 0, 0, fuse_fault_info },
904 	{ NULL, 0, 0, "UPS.PowerConverter.Input[1].PresentStatus.InternalFailure", 0, 0, internalfailure_info },
905 	{ NULL, 0, 0, "UPS.PowerSummary.PresentStatus.Good", 0, 0, off_info },
906 	/* { NULL, 0, 0, "UPS.PowerConverter.Input[1].PresentStatus.Used", 0, 0, online_info }, */
907 	{ NULL, 0, 0, "UPS.PowerConverter.Input[2].PresentStatus.Used", 0, 0, bypass_aut_info }, /* Automatic bypass */
908 	/* { NULL, 0, 0, "UPS.PowerConverter.Input[3].PresentStatus.Used", 0, 0, onbatt_info }, */
909 	{ NULL, 0, 0, "UPS.PowerConverter.Input[4].PresentStatus.Used", 0, 0, bypass_man_info }, /* Manual bypass */
910 	{ NULL, 0, 0, "UPS.PowerSummary.PresentStatus.FanFailure", 0, 0, fanfail_info },
911 	{ NULL, 0, 0, "UPS.BatterySystem.Battery.PresentStatus.Present", 0, 0, nobattery_info },
912 	{ NULL, 0, 0, "UPS.BatterySystem.Charger.PresentStatus.InternalFailure", 0, 0, chargerfail_info },
913 	{ NULL, 0, 0, "UPS.BatterySystem.Charger.PresentStatus.VoltageTooHigh", 0, 0, battvolthi_info },
914 	{ NULL, 0, 0, "UPS.BatterySystem.Charger.PresentStatus.VoltageTooLow", 0, 0, battvoltlo_info },
915 	{ NULL, 0, 0, "UPS.PowerSummary.PresentStatus.InternalFailure", 0, 0, internalfailure_info },
916 	{ NULL, 0, 0, "UPS.PowerSummary.PresentStatus.CommunicationLost", 0, 0, commfault_info },
917 	{ NULL, 0, 0, "UPS.PowerSummary.PresentStatus.OverTemperature", 0, 0, overheat_info },
918 	/* { NULL, 0, 0, "UPS.PowerSummary.PresentStatus.ShutdownImminent", 0, 0, shutdownimm_info }, */
919 
920 	/* Battery page */
921 	{ "battery.charge", 0, 0, "UPS.PowerSummary.RemainingCapacity", 0, 0, NULL },
922 	{ "battery.charge.low", 0, 0, "UPS.PowerSummary.RemainingCapacityLimitSetting", 0, 0, NULL },
923 	{ "battery.charge.low", 0, 0, "UPS.PowerSummary.RemainingCapacityLimit", 0, 0, NULL }, /* Read only */
924 	{ "battery.charge.restart", 0, 0, "UPS.PowerSummary.RestartLevel", 0, 0, NULL },
925 	{ "battery.capacity", 0, 0, "UPS.BatterySystem.Battery.DesignCapacity", 0, 0, mge_battery_capacity }, /* conversion needed from As to Ah */
926 	{ "battery.runtime", 0, 0, "UPS.PowerSummary.RunTimeToEmpty", 0, 0, NULL },
927 	{ "battery.runtime.low", ST_FLAG_RW, 0, "System.RunTimeToEmptyLimit", 0, 0, NULL },
928 	{ "battery.temperature", 0, 0, "UPS.BatterySystem.Battery.Temperature", 0, 0, NULL },
929 	{ "battery.packs.external", 0, 0, "UPS.BatterySystem.Battery.Count", 0, 0, NULL },
930 	{ "battery.type", ST_FLAG_STATIC, 0, "UPS.PowerSummary.iDeviceChemistry", 0, 0, NULL },
931 	{ "battery.type", ST_FLAG_STATIC, 0, "UPS.PowerSummary.iDeviceChemistery", 0, 0, NULL }, /* [sic] */
932 	{ "battery.voltage.nominal", ST_FLAG_STATIC, 0, "UPS.BatterySystem.ConfigVoltage", 0, 0, NULL },
933 	{ "battery.protection", 0, 0, "UPS.BatterySystem.Battery.DeepDischargeProtection", 0, 0, yes_no_info },
934 	{ "battery.energysave", 0, 0, "UPS.PowerConverter.Input[3].EnergySaving", 0, 0, yes_no_info },
935 
936 	/* UPS page */
937 	{ "ups.mfr", ST_FLAG_STATIC, 0, "UPS.PowerSummary.iManufacturer", 0, 0, NULL },
938 	{ "ups.model", ST_FLAG_STATIC, 0, "System.Description", 0, 0, NULL },
939 	{ "ups.model", ST_FLAG_STATIC, 0, "UPS.PowerSummary.iProduct", 0, 0, NULL },
940 	{ "ups.model.aux", ST_FLAG_STATIC, 0, "UPS.PowerSummary.iModel", 0, 0, NULL },
941 	{ "ups.time", 0, 0, "System.LastAcquisition", 0, 0, split_date_time },
942 	/* -> XML variable System.Location [Computer Room] doesn't map to any NUT variable */
943 	/* -> XML variable System.Contact [Computer Room Manager] doesn't map to any NUT variable */
944 	/* -> XML variable UPS.PowerSummary.iProduct [Evolution] doesn't map to any NUT variable */
945 	/* -> XML variable UPS.PowerSummary.iModel [650] doesn't map to any NUT variable */
946 	{ "ups.serial", ST_FLAG_STATIC, 0, "UPS.PowerSummary.iSerialNumber", 0, 0, NULL },
947 	{ "ups.firmware", ST_FLAG_STATIC, 0, "UPS.PowerSummary.iVersion", 0, 0, NULL },
948 	{ "ups.load", 0, 0, "UPS.PowerSummary.PercentLoad", 0, 0, NULL },
949 	{ "ups.load.high", 0, 0, "UPS.Flow[4].ConfigPercentLoad", 0, 0, NULL },
950 	{ "ups.delay.shutdown", ST_FLAG_RW, 0, "System.ShutdownDuration", 0, 0, NULL },
951 	{ "ups.timer.start", ST_FLAG_RW, 0, "UPS.PowerSummary.DelayBeforeStartup", 0, 0, NULL},
952 	{ "ups.timer.shutdown", ST_FLAG_RW, 0, "UPS.PowerSummary.DelayBeforeShutdown", 0, 0, mge_timer_shutdown },
953 	/* Catch shutdown imminent criteria, keep it after
954 	UPS.PowerSummary.DelayBeforeShutdown managment */
955 	{ NULL, 0, 0, "System.RunTimeToShutdown", 0, 0, mge_shutdown_imminent },
956 	{ "ups.timer.reboot", 0, 0, "UPS.PowerSummary.DelayBeforeReboot", 0, 0, NULL },
957 	{ "ups.test.result", 0, 0, "UPS.BatterySystem.Battery.Test", 0, 0, mge_test_result_info },
958 	{ "ups.test.interval", 0, 0, "UPS.BatterySystem.Battery.TestPeriod", 0, 0, NULL },
959 	{ "ups.beeper.status", 0 ,0, "UPS.BatterySystem.Battery.AudibleAlarmControl", 0, 0, mge_beeper_info },
960 	{ "ups.beeper.status", 0 ,0, "UPS.PowerSummary.AudibleAlarmControl", 0, 0, mge_beeper_info },
961 	{ "ups.temperature", 0, 0, "UPS.PowerSummary.Temperature", 0, 0, NULL },
962 	{ "ups.power", 0, 0, "UPS.PowerConverter.Output.ApparentPower", 0, 0, NULL },
963 	{ "ups.L1.power", 0, 0, "UPS.PowerConverter.Output.Phase[1].ApparentPower", 0, 0, ignore_if_zero },
964 	{ "ups.L2.power", 0, 0, "UPS.PowerConverter.Output.Phase[2].ApparentPower", 0, 0, ignore_if_zero },
965 	{ "ups.L3.power", 0, 0, "UPS.PowerConverter.Output.Phase[3].ApparentPower", 0, 0, ignore_if_zero },
966 	{ "ups.power.nominal", ST_FLAG_STATIC, 0, "UPS.Flow[4].ConfigApparentPower", 0, 0, NULL },
967 	{ "ups.realpower", 0, 0, "UPS.PowerConverter.Output.ActivePower", 0, 0, NULL },
968 	{ "ups.L1.realpower", 0, 0, "UPS.PowerConverter.Output.Phase[1].ActivePower", 0, 0, ignore_if_zero },
969 	{ "ups.L2.realpower", 0, 0, "UPS.PowerConverter.Output.Phase[2].ActivePower", 0, 0, ignore_if_zero },
970 	{ "ups.L3.realpower", 0, 0, "UPS.PowerConverter.Output.Phase[3].ActivePower", 0, 0, ignore_if_zero },
971 	{ "ups.realpower.nominal", ST_FLAG_STATIC, 0, "UPS.Flow[4].ConfigActivePower", 0, 0, NULL },
972 	{ "ups.start.auto", 0, 0, "UPS.PowerConverter.Input[1].AutomaticRestart", 0, 0, yes_no_info },
973 	{ "ups.start.battery", 0, 0, "UPS.PowerConverter.Input[3].StartOnBattery", 0, 0, yes_no_info },
974 	{ "ups.start.reboot", 0, 0, "UPS.PowerConverter.Output.ForcedReboot", 0, 0, yes_no_info },
975 	{ "ups.type", ST_FLAG_STATIC, 0, "UPS.PowerConverter.ConverterType", 0, 0, mge_upstype_conversion },
976 
977 	/* Input page */
978 	{ "input.voltage", 0, 0, "UPS.PowerConverter.Input[1].Voltage", 0, 0, NULL },
979 	{ "input.L1-N.voltage", 0, 0, "UPS.PowerConverter.Input[1].Phase[1].Voltage", 0, 0, NULL },
980 	{ "input.L2-N.voltage", 0, 0, "UPS.PowerConverter.Input[1].Phase[2].Voltage", 0, 0, NULL },
981 	{ "input.L3-N.voltage", 0, 0, "UPS.PowerConverter.Input[1].Phase[3].Voltage", 0, 0, NULL },
982 	{ "input.L1-L2.voltage", 0, 0, "UPS.PowerConverter.Input[1].Phase[12].Voltage", 0, 0, NULL },
983 	{ "input.L2-L3.voltage", 0, 0, "UPS.PowerConverter.Input[1].Phase[23].Voltage", 0, 0, NULL },
984 	{ "input.L3-L1.voltage", 0, 0, "UPS.PowerConverter.Input[1].Phase[31].Voltage", 0, 0, NULL },
985 	{ "input.L1-L2.voltage", 0, 0, "UPS.PowerConverter.Input[1].Phase[11].Voltage", 0, 0, convert_deci },
986 	{ "input.L2-L3.voltage", 0, 0, "UPS.PowerConverter.Input[1].Phase[22].Voltage", 0, 0, convert_deci },
987 	{ "input.L3-L1.voltage", 0, 0, "UPS.PowerConverter.Input[1].Phase[33].Voltage", 0, 0, convert_deci },
988 	{ "input.voltage.nominal", 0, 0, "UPS.Flow[1].ConfigVoltage", 0, 0, NULL },
989 	{ "input.current", 0, 0, "UPS.PowerConverter.Input[1].Current", 0, 0, NULL },
990 	{ "input.L1.current", 0, 0, "UPS.PowerConverter.Input[1].Phase[1].Current", 0, 0, convert_deci },
991 	{ "input.L2.current", 0, 0, "UPS.PowerConverter.Input[1].Phase[2].Current", 0, 0, convert_deci },
992 	{ "input.L3.current", 0, 0, "UPS.PowerConverter.Input[1].Phase[3].Current", 0, 0, convert_deci },
993 	{ "input.current.nominal", 0, 0, "UPS.Flow[1].ConfigCurrent", 0, 0, NULL },
994 	{ "input.frequency", 0, 0, "UPS.PowerConverter.Input[1].Frequency", 0, 0, NULL },
995 	{ "input.frequency.nominal", 0, 0, "UPS.Flow[1].ConfigFrequency", 0, 0, NULL },
996 	{ "input.voltage.extended", 0, 0, "UPS.PowerConverter.Output.ExtendedVoltageMode", 0, 0, yes_no_info },
997 	{ "input.frequency.extended", 0, 0, "UPS.PowerConverter.Output.ExtendedFrequencyMode", 0, 0, yes_no_info },
998 	/* same as "input.transfer.boost.low" */
999 	{ "input.transfer.low", 0, 0, "UPS.PowerConverter.Output.LowVoltageTransfer", 0, 0, NULL },
1000 	{ "input.transfer.boost.low", 0, 0, "UPS.PowerConverter.Output.LowVoltageBoostTransfer", 0, 0, NULL },
1001 	{ "input.transfer.boost.high", 0, 0, "UPS.PowerConverter.Output.HighVoltageBoostTransfer", 0, 0, NULL },
1002 	{ "input.transfer.trim.low", 0, 0, "UPS.PowerConverter.Output.LowVoltageBuckTransfer", 0, 0, NULL },
1003 	/* same as "input.transfer.trim.high" */
1004 	{ "input.transfer.high", 0, 0, "UPS.PowerConverter.Output.HighVoltageTransfer", 0, 0, NULL },
1005 	{ "input.transfer.trim.high", 0, 0, "UPS.PowerConverter.Output.HighVoltageBuckTransfer", 0, 0, NULL },
1006 	{ "input.sensitivity", 0, 0, "UPS.PowerConverter.Output.SensitivityMode", 0, 0, mge_sensitivity_info },
1007 
1008 	/* Bypass page */
1009 	{ "input.bypass.voltage", 0, 0, "UPS.PowerConverter.Input[2].Voltage", 0, 0, NULL },
1010 	{ "input.bypass.L1-N.voltage", 0, 0, "UPS.PowerConverter.Input[2].Phase[1].Voltage", 0, 0, NULL },
1011 	{ "input.bypass.L2-N.voltage", 0, 0, "UPS.PowerConverter.Input[2].Phase[2].Voltage", 0, 0, NULL },
1012 	{ "input.bypass.L3-N.voltage", 0, 0, "UPS.PowerConverter.Input[2].Phase[3].Voltage", 0, 0, NULL },
1013 	{ "input.bypass.L1-L2.voltage", 0, 0, "UPS.PowerConverter.Input[2].Phase[12].Voltage", 0, 0, NULL },
1014 	{ "input.bypass.L2-L3.voltage", 0, 0, "UPS.PowerConverter.Input[2].Phase[23].Voltage", 0, 0, NULL },
1015 	{ "input.bypass.L3-L1.voltage", 0, 0, "UPS.PowerConverter.Input[2].Phase[31].Voltage", 0, 0, NULL },
1016 	{ "input.bypass.L1-L2.voltage", 0, 0, "UPS.PowerConverter.Input[2].Phase[11].Voltage", 0, 0, NULL },
1017 	{ "input.bypass.L2-L3.voltage", 0, 0, "UPS.PowerConverter.Input[2].Phase[22].Voltage", 0, 0, NULL },
1018 	{ "input.bypass.L3-L1.voltage", 0, 0, "UPS.PowerConverter.Input[2].Phase[33].Voltage", 0, 0, NULL },
1019 	{ "input.bypass.voltage.nominal", 0, 0, "UPS.Flow[2].ConfigVoltage", 0, 0, NULL },
1020 	{ "input.bypass.current", 0, 0, "UPS.PowerConverter.Input[2].Current", 0, 0, NULL },
1021 	{ "input.bypass.L1.current", 0, 0, "UPS.PowerConverter.Input[2].Phase[1].Current", 0, 0, NULL },
1022 	{ "input.bypass.L2.current", 0, 0, "UPS.PowerConverter.Input[2].Phase[2].Current", 0, 0, NULL },
1023 	{ "input.bypass.L3.current", 0, 0, "UPS.PowerConverter.Input[2].Phase[3].Current", 0, 0, NULL },
1024 	{ "input.bypass.current.nominal", 0, 0, "UPS.Flow[2].ConfigCurrent", 0, 0, NULL },
1025 	{ "input.bypass.frequency", 0, 0, "UPS.PowerConverter.Input[2].Frequency", 0, 0, NULL },
1026 	{ "input.bypass.frequency.nominal", 0, 0, "UPS.Flow[2].ConfigFrequency", 0, 0, NULL },
1027 
1028 	/* Output page */
1029 	{ "output.voltage", 0, 0, "UPS.PowerConverter.Output.Voltage", 0, 0, NULL },
1030 	{ "output.L1-N.voltage", 0, 0, "UPS.PowerConverter.Output.Phase[1].Voltage", 0, 0, NULL },
1031 	{ "output.L2-N.voltage", 0, 0, "UPS.PowerConverter.Output.Phase[2].Voltage", 0, 0, NULL },
1032 	{ "output.L3-N.voltage", 0, 0, "UPS.PowerConverter.Output.Phase[3].Voltage", 0, 0, NULL },
1033 	{ "output.L1-L2.voltage", 0, 0, "UPS.PowerConverter.Output.Phase[12].Voltage", 0, 0, NULL },
1034 	{ "output.L2-L3.voltage", 0, 0, "UPS.PowerConverter.Output.Phase[23].Voltage", 0, 0, NULL },
1035 	{ "output.L3-L1.voltage", 0, 0, "UPS.PowerConverter.Output.Phase[31].Voltage", 0, 0, NULL },
1036 	{ "output.L1-L2.voltage", 0, 0, "UPS.PowerConverter.Output.Phase[11].Voltage", 0, 0, ignore_if_zero },
1037 	{ "output.L2-L3.voltage", 0, 0, "UPS.PowerConverter.Output.Phase[22].Voltage", 0, 0, ignore_if_zero },
1038 	{ "output.L3-L1.voltage", 0, 0, "UPS.PowerConverter.Output.Phase[33].Voltage", 0, 0, ignore_if_zero },
1039 	{ "output.voltage.nominal", 0, 0, "UPS.Flow[4].ConfigVoltage", 0, 0, NULL },
1040 	{ "output.current", 0, 0, "UPS.PowerConverter.Output.Current", 0, 0, NULL },
1041 	{ "output.L1.current", 0, 0, "UPS.PowerConverter.Output.Phase[1].Current", 0, 0, convert_deci },
1042 	{ "output.L2.current", 0, 0, "UPS.PowerConverter.Output.Phase[2].Current", 0, 0, convert_deci },
1043 	{ "output.L3.current", 0, 0, "UPS.PowerConverter.Output.Phase[3].Current", 0, 0, convert_deci },
1044 	{ "output.current.nominal", 0, 0, "UPS.Flow[4].ConfigCurrent", 0, 0, NULL },
1045 	{ "output.frequency", 0, 0, "UPS.PowerConverter.Output.Frequency", 0, 0, NULL },
1046 	{ "output.frequency.nominal", 0, 0, "UPS.Flow[4].ConfigFrequency", 0, 0, NULL },
1047 	{ "output.powerfactor", 0, 0, "UPS.PowerConverter.Output.PowerFactor", 0, 0, mge_powerfactor_conversion },
1048 
1049 	/* Ambient page */
1050 	{ "ambient.humidity", 0, 0, "Environment.Humidity", 0, 0, NULL },
1051 	{ "ambient.humidity.high", ST_FLAG_RW, 0, "Environment.Humidity.HighThreshold", 0, 0, NULL },
1052 	{ "ambient.humidity.low", ST_FLAG_RW, 0, "Environment.Humidity.LowThreshold", 0, 0, NULL },
1053 	{ "ambient.humidity.maximum", 0, 0, "Environment.PresentStatus.HighHumidity", 0, 0, mge_ambient_info },
1054 	{ "ambient.humidity.minimum", 0, 0, "Environment.PresentStatus.LowHumidity", 0, 0, mge_ambient_info },
1055 	{ "ambient.temperature", 0, 0, "Environment.Temperature", 0, 0, NULL },
1056 	{ "ambient.temperature.high", ST_FLAG_RW, 0, "Environment.Temperature.HighThreshold", 0, 0, NULL },
1057 	{ "ambient.temperature.low", ST_FLAG_RW, 0, "Environment.Temperature.LowThreshold", 0, 0, NULL },
1058 	{ "ambient.temperature.maximum", 0, 0, "Environment.PresentStatus.HighTemperature", 0, 0, mge_ambient_info },
1059 	{ "ambient.temperature.minimum", 0, 0, "Environment.PresentStatus.LowTemperature", 0, 0, mge_ambient_info },
1060 
1061 	/* Outlet page (using MGE UPS SYSTEMS - PowerShare technology) */
1062 	{ "outlet.id", 0, 0, "UPS.OutletSystem.Outlet[1].OutletID", 0, 0, NULL },
1063 	{ "outlet.desc", 0, 0, "UPS.OutletSystem.Outlet[1].iName", 0, 0, NULL },
1064 	{ "outlet.switchable", 0, 0, "UPS.OutletSystem.Outlet[1].PresentStatus.Switchable", 0, 0, yes_no_info },
1065 
1066 	{ "outlet.1.id", 0, 0, "UPS.OutletSystem.Outlet[2].OutletID", 0, 0, NULL },
1067 	{ "outlet.1.desc", 0, 0, "UPS.OutletSystem.Outlet[2].iName", 0, 0, NULL },
1068 	{ "outlet.1.switchable", 0, 0, "UPS.OutletSystem.Outlet[2].PresentStatus.Switchable", 0, 0, yes_no_info },
1069 	{ "outlet.1.status", 0, 0, "UPS.OutletSystem.Outlet[2].PresentStatus.SwitchOnOff", 0, 0, on_off_info },
1070 	/* For low end models, with 1 non backup'ed outlet */
1071 	{ "outlet.1.status", 0, 0, "UPS.PowerSummary.PresentStatus.ACPresent", 0, 0, NULL }, /* on_off_info */
1072 	{ "outlet.1.battery.charge.low", 0, 0, "UPS.OutletSystem.Outlet[2].RemainingCapacityLimit", 0, 0, NULL },
1073 	{ "outlet.1.timer.start", 0, 0, "UPS.OutletSystem.Outlet[2].DelayBeforeStartup", 0, 0, NULL },
1074 	{ "outlet.1.timer.shutdown", 0, 0, "UPS.OutletSystem.Outlet[2].DelayBeforeShutdown", 0, 0, NULL },
1075 	{ "outlet.1.delay.start", 0, 0, "UPS.OutletSystem.Outlet[2].StartupTimer", 0, 0, NULL },
1076 	/* { "outlet.1.delay.shutdown", 0, 0, "UPS.OutletSystem.Outlet[2].ShutdownTimer", 0, 0, NULL }, */
1077 	{ "outlet.1.delay.shutdown", ST_FLAG_RW, 0, "System.Outlet[2].ShutdownDuration", 0, 0, NULL },
1078 
1079 	{ "outlet.2.id", 0, 0, "UPS.OutletSystem.Outlet[3].OutletID", 0, 0, NULL },
1080 	{ "outlet.2.desc", 0, 0, "UPS.OutletSystem.Outlet[3].iName", 0, 0, NULL },
1081 	{ "outlet.2.switchable", 0, 0, "UPS.OutletSystem.Outlet[3].PresentStatus.Switchable", 0, 0, yes_no_info },
1082 	{ "outlet.2.status", 0, 0, "UPS.OutletSystem.Outlet[3].PresentStatus.SwitchOnOff", 0, 0, on_off_info },
1083 	{ "outlet.2.battery.charge.low", 0, 0, "UPS.OutletSystem.Outlet[3].RemainingCapacityLimit", 0, 0, NULL },
1084 	{ "outlet.2.timer.start", 0, 0, "UPS.OutletSystem.Outlet[3].DelayBeforeStartup", 0, 0, NULL },
1085 	{ "outlet.2.timer.shutdown", 0, 0, "UPS.OutletSystem.Outlet[3].DelayBeforeShutdown", 0, 0, NULL },
1086 	{ "outlet.2.delay.start", 0, 0, "UPS.OutletSystem.Outlet[3].StartupTimer", 0, 0, NULL },
1087 	/* { "outlet.2.delay.shutdown", 0, 0, "UPS.OutletSystem.Outlet[3].ShutdownTimer", 0, 0, NULL }, */
1088 	{ "outlet.2.delay.shutdown", ST_FLAG_RW, 0, "System.Outlet[3].ShutdownDuration", 0, 0, NULL },
1089 
1090 	/* For newer ePDU Monitored */
1091 	{ "outlet.1.desc", 0, 0, "PDU.OutletSystem.Outlet[1].iName", 0, 0, NULL },
1092 	{ "outlet.1.current", 0, 0, "PDU.OutletSystem.Outlet[1].Current", 0, 0, convert_deci },
1093 	/* FIXME: also map these?
1094 	 * "PDU.OutletSystem.Outlet[1].CurrentLimit" => settable, triggers CurrentTooHigh
1095 	 * "PDU.OutletSystem.Outlet[1].PresentStatus.CurrentTooHigh" (0/1)
1096 	 */
1097 	{ "outlet.2.desc", 0, 0, "PDU.OutletSystem.Outlet[2].iName", 0, 0, NULL },
1098 	{ "outlet.2.current", 0, 0, "PDU.OutletSystem.Outlet[2].Current", 0, 0, convert_deci },
1099 	{ "outlet.3.desc", 0, 0, "PDU.OutletSystem.Outlet[3].iName", 0, 0, NULL },
1100 	{ "outlet.3.current", 0, 0, "PDU.OutletSystem.Outlet[3].Current", 0, 0, convert_deci },
1101 	{ "outlet.4.desc", 0, 0, "PDU.OutletSystem.Outlet[2].iName", 0, 0, NULL },
1102 	{ "outlet.4.current", 0, 0, "PDU.OutletSystem.Outlet[2].Current", 0, 0, convert_deci },
1103 	{ "outlet.5.desc", 0, 0, "PDU.OutletSystem.Outlet[3].iName", 0, 0, NULL },
1104 	{ "outlet.5.current", 0, 0, "PDU.OutletSystem.Outlet[3].Current", 0, 0, convert_deci },
1105 	{ "outlet.6.desc", 0, 0, "PDU.OutletSystem.Outlet[2].iName", 0, 0, NULL },
1106 	{ "outlet.6.current", 0, 0, "PDU.OutletSystem.Outlet[2].Current", 0, 0, convert_deci },
1107 	{ "outlet.7.desc", 0, 0, "PDU.OutletSystem.Outlet[3].iName", 0, 0, NULL },
1108 	{ "outlet.7.current", 0, 0, "PDU.OutletSystem.Outlet[3].Current", 0, 0, convert_deci },
1109 	{ "outlet.8.desc", 0, 0, "PDU.OutletSystem.Outlet[2].iName", 0, 0, NULL },
1110 	{ "outlet.8.current", 0, 0, "PDU.OutletSystem.Outlet[2].Current", 0, 0, convert_deci },
1111 
1112 	{ NULL, 0, 0, NULL, 0, 0, NULL }
1113 };
1114 
1115 /* A start-element callback for element with given namespace/name. */
mge_xml_startelm_cb(void * userdata,int parent,const char * nspace,const char * name,const char ** atts)1116 static int mge_xml_startelm_cb(void *userdata, int parent, const char *nspace, const char *name, const char **atts)
1117 {
1118 	int	state = _UNEXPECTED;
1119 	NUT_UNUSED_VARIABLE(userdata);
1120 	NUT_UNUSED_VARIABLE(nspace);
1121 
1122 	switch(parent)
1123 	{
1124 	case ROOTPARENT:
1125 		if (!strcasecmp(name, "PRODUCT_INFO")) {
1126 			/* name="Network Management Card" type="Mosaic M" version="BA" */
1127 			/* name="Network Management Card" type="Transverse" version="GB (SN 49EH29101)" */
1128 			/* name="Monitored ePDU" type="Monitored ePDU" version="Version Upgrade" */
1129 			/* name="PDU Network Management Card" type="SCOB" version="02.00.0036" signature="34008876" protocol="XML.V4" */
1130 			int	i;
1131 			for (i = 0; atts[i] && atts[i+1]; i += 2) {
1132 				if (!strcasecmp(atts[i], "name")) {
1133 					snprintf(val, sizeof(val), "%s", atts[i+1]);
1134 				}
1135 				if (!strcasecmp(atts[i], "type")) {
1136 					snprintfcat(val, sizeof(val), "/%s", atts[i+1]);
1137 					if (!strcasecmp(atts[i+1], "Transverse")) {
1138 						mge_ambient_value = 1;
1139 					} else if (strstr(atts[i+1], "ePDU")) {
1140 						dstate_setinfo("device.type", "pdu");
1141 					}
1142 				}
1143 				if (!strcasecmp(atts[i], "version")) {
1144 					char	*s;
1145 					snprintfcat(val, sizeof(val), "/%s", atts[i+1]);
1146 					s = strstr(val, " (SN ");
1147 					if (s) {
1148 						dstate_setinfo("ups.serial", "%s", str_rtrim(s + 5, ')'));
1149 						s[0] = '\0';
1150 					}
1151 					dstate_setinfo("ups.firmware.aux", "%s", val);
1152 				}
1153 				/* netxml-ups currently only supports XML version 3 (for UPS),
1154 				 * and not version 4 (for UPS and PDU)! */
1155 				if (!strcasecmp(atts[i], "protocol")) {
1156 					if (!strcasecmp(atts[i+1], "XML.V4")) {
1157 						fatalx(EXIT_FAILURE, "XML v4 protocol is not supported!");
1158 					}
1159 				}
1160 			}
1161 			state = PRODUCT_INFO;
1162 			break;
1163 		}
1164 		if (!strcasecmp(name, "SUMMARY")) {
1165 			state = SUMMARY;
1166 			break;
1167 		}
1168 		if (!strcasecmp(name, "GET_OBJECT")) {
1169 			state = GET_OBJECT;
1170 			break;
1171 		}
1172 		if (!strcasecmp(name, "SET_OBJECT")) {
1173 			state = SET_OBJECT;
1174 			break;
1175 		}
1176 		if (!strcasecmp(name, "ALARM")) {
1177 			int	i;
1178 			var[0] = val[0] = '\0';
1179 			for (i = 0; atts[i] && atts[i+1]; i += 2) {
1180 				if (!strcasecmp(atts[i], "object")) {
1181 					snprintf(var, sizeof(var), "%s", atts[i+1]);
1182 				}
1183 				if (!strcasecmp(atts[i], "value")) {
1184 					snprintf(val, sizeof(var), "%s", atts[i+1]);
1185 				}
1186 				if (!strcasecmp(atts[i], "date")) {
1187 					dstate_setinfo("ups.time", "%s", split_date_time(atts[i+1]));
1188 				}
1189 			}
1190 			state = ALARM;
1191 			break;
1192 		}
1193 		if (!strcasecmp(name, "XML-CLIENT")) {
1194 			state = XML_CLIENT;
1195 			break;
1196 		}
1197 		break;
1198 
1199 	case PRODUCT_INFO:
1200 		if (!strcasecmp(name, "SUMMARY")) {
1201 			state = PI_SUMMARY;
1202 			break;
1203 		}
1204 
1205 		if (!strcasecmp(name, "ALARMS")) {
1206 			state = PI_ALARMS;
1207 			break;
1208 		}
1209 
1210 		if (!strcasecmp(name, "MANAGEMENT")) {
1211 			state = PI_MANAGEMENT;
1212 			break;
1213 		}
1214 
1215 		if ( (!strcasecmp(name, "UPS_DATA"))
1216 			|| (!strcasecmp(name, "DEV_DATA")) ) {
1217 			state = PI_UPS_DATA;
1218 			break;
1219 		}
1220 		break;
1221 
1222 	case PI_SUMMARY:
1223 		if (!strcasecmp(name, "HTML_PROPERTIES_PAGE")) {
1224 			/* url="mgeups/default.htm" */
1225 			state = PI_HTML_PROPERTIES_PAGE;
1226 			break;
1227 		}
1228 		if (!strcasecmp(name, "XML_SUMMARY_PAGE")) {
1229 			/* url="upsprop.xml" or url="ws/summary.xml" */
1230 			int	i;
1231 			for (i = 0; atts[i] && atts[i+1]; i += 2) {
1232 				if (!strncasecmp(atts[i], "url", 3)) {
1233 					free(mge_xml_subdriver.summary);
1234 					mge_xml_subdriver.summary = strdup(url_convert(atts[i+1]));
1235 				}
1236 			}
1237 			state = PI_XML_SUMMARY_PAGE;
1238 			break;
1239 		}
1240 		if (!strcasecmp(name, "CENTRAL_CFG")) {
1241 			/* url="config.xml" */
1242 			int	i;
1243 			for (i = 0; atts[i] && atts[i+1]; i += 2) {
1244 				if (!strncasecmp(atts[i], "url", 3)) {
1245 					free(mge_xml_subdriver.configure);
1246 					mge_xml_subdriver.configure = strdup(url_convert(atts[i+1]));
1247 				}
1248 			}
1249 			state = PI_CENTRAL_CFG;
1250 			break;
1251 		}
1252 		if (!strcasecmp(name, "CSV_LOGS")) {
1253 			/* url="logevent.csv" dateRange="no" eventFiltering="no" */
1254 			state = PI_CSV_LOGS;
1255 			break;
1256 		}
1257 		break;
1258 
1259 	case PI_ALARMS:
1260 		if (!strcasecmp(name, "SUBSCRIPTION")) {
1261 			/* url="subscribe.cgi" security="basic" */
1262 			int	i;
1263 			for (i = 0; atts[i] && atts[i+1]; i += 2) {
1264 				if (!strncasecmp(atts[i], "url", 3)) {
1265 					free(mge_xml_subdriver.subscribe);
1266 					mge_xml_subdriver.subscribe = strdup(url_convert(atts[i+1]));
1267 				}
1268 			}
1269 			state = PI_SUBSCRIPTION;
1270 			break;
1271 		}
1272 
1273 		if (!strcasecmp(name, "POLLING")) {
1274 			/* url="mgeups/lastalarms.cgi" security="none" */
1275 			state = PI_POLLING;
1276 			break;
1277 		}
1278 		break;
1279 
1280 
1281 	case PI_MANAGEMENT:
1282 		if (!strcasecmp(name, "MANAGEMENT_PAGE")) {
1283 			/* name="Manager list" id="ManagerList" url="FS/FLASH0/TrapReceiverList.cfg" security="none" */
1284 			/* name="Shutdown criteria settings" id="Shutdown" url="FS/FLASH0/ShutdownParameters.cfg" security="none" */
1285 			/* name="Network settings" id="Network" url="FS/FLASH0/NetworkSettings.cfg" security="none" */
1286 			/* name="Centralized configuration settings" id="ClientCfg" url="FS/FLASH0/CentralizedConfig.cfg" security="none" */
1287 			state = PI_MANAGEMENT_PAGE;
1288 			break;
1289 		}
1290 		if (!strcasecmp(name, "XML_MANAGEMENT_PAGE")) {
1291 			/* name="Set Card Time" id="SetTime" url="management/set_time.xml" security="none" */
1292 			state = PI_XML_MANAGEMENT_PAGE;
1293 			break;
1294 		}
1295 		break;
1296 
1297 	case PI_UPS_DATA:
1298 		if (!strcasecmp(name, "GET_OBJECT")) {
1299 			/* url="getvalue.cgi" security="none" */
1300 			int	i;
1301 			for (i = 0; atts[i] && atts[i+1]; i += 2) {
1302 				if (!strncasecmp(atts[i], "url", 3)) {
1303 					free(mge_xml_subdriver.getobject);
1304 					mge_xml_subdriver.getobject = strdup(url_convert(atts[i+1]));
1305 				}
1306 			}
1307 			state = PI_GET_OBJECT;
1308 			break;
1309 		}
1310 		if (!strcasecmp(name, "SET_OBJECT")) {
1311 			/* url="setvalue.cgi" security="ssl" */
1312 			int	i;
1313 			for (i = 0; atts[i] && atts[i+1]; i += 2) {
1314 				if (!strncasecmp(atts[i], "url", 3)) {
1315 					free(mge_xml_subdriver.setobject);
1316 					mge_xml_subdriver.setobject = strdup(url_convert(atts[i+1]));
1317 				}
1318 			}
1319 			state = PI_SET_OBJECT;
1320 			break;
1321 		}
1322 		break;
1323 
1324 	case SUMMARY:
1325 		if (!strcasecmp(name, "OBJECT")) {
1326 			/* name="UPS.PowerSummary.iProduct" */
1327 			int	i;
1328 			for (i = 0; atts[i] && atts[i+1]; i += 2) {
1329 				if (!strcasecmp(atts[i], "name")) {
1330 					snprintf(var, sizeof(var), "%s", atts[i+1]);
1331 					val[0] = '\0';	/*don't inherit something from another object */
1332 				}
1333 			}
1334 			state = SU_OBJECT;
1335 			break;
1336 		}
1337 		break;
1338 
1339 	case GET_OBJECT:
1340 		if (!strcasecmp(name, "OBJECT")) {
1341 			/* name="System.RunTimeToEmptyLimit" unit="s" access="RW" */
1342 			int	i;
1343 			for (i = 0; atts[i] && atts[i+1]; i += 2) {
1344 				if (!strcasecmp(atts[i], "name")) {
1345 					snprintf(var, sizeof(var), "%s", atts[i+1]);
1346 					val[0] = '\0';	/*don't inherit something from another object */
1347 				}
1348 				if (!strcasecmp(atts[i], "access")) {
1349 					/* do something with RO/RW access? */
1350 				}
1351 			}
1352 			state = GO_OBJECT;
1353 			break;
1354 		}
1355 		break;
1356 
1357 	case XML_CLIENT:
1358 		if (!strcasecmp(name, "GENERAL")) {
1359 			state = XC_GENERAL;
1360 			break;
1361 		}
1362 		/* FIXME? Is the fall-through to handling "GENERAL" intended?
1363 		 * was so in legacy code before the goto below... */
1364 		goto fallthrough_case_general;
1365 
1366 	case XC_GENERAL:
1367 	fallthrough_case_general:
1368 		if (!strcasecmp(name, "STARTUP")) {
1369 			/* config="CENTRALIZED" */
1370 			state = XC_STARTUP;
1371 			break;
1372 		}
1373 		if (!strcasecmp(name, "SHUTDOWN")) {
1374 			/* shutdownTimer="NONE" shutdownDuration="150" */
1375 			int	i;
1376 			for (i = 0; atts[i] && atts[i+1]; i += 2) {
1377 				if (!strcasecmp(atts[i], "shutdownTimer")) {
1378 					dstate_setinfo("driver.timer.shutdown", "%s", atts[i+1]);
1379 				}
1380 				if (!strcasecmp(atts[i], "shutdownDuration")) {
1381 					dstate_setinfo("driver.delay.shutdown", "%s", atts[i+1]);
1382 				}
1383 			}
1384 			state = XC_SHUTDOWN;
1385 			break;
1386 		}
1387 		if (!strcasecmp(name, "BROADCAST")) {
1388 			/* admins="ON" users="ON" */
1389 			state = XC_BROADCAST;
1390 			break;
1391 		}
1392 	}
1393 
1394 	upsdebugx(3, "%s: name <%s> (parent = %d, state = %d)", __func__, name, parent, state);
1395 	return state;
1396 }
1397 
1398 /* Character data callback; may return non-zero to abort the parse. */
mge_xml_cdata_cb(void * userdata,int state,const char * cdata,size_t len)1399 static int mge_xml_cdata_cb(void *userdata, int state, const char *cdata, size_t len)
1400 {
1401 	NUT_UNUSED_VARIABLE(userdata);
1402 
1403 	/* skip empty lines */
1404 	if ((len == 1) && (cdata[0] == '\n')) {
1405 		upsdebugx(3, "%s: cdata ignored (state = %d)", __func__, state);
1406 		return 0;
1407 	}
1408 
1409 	upsdebugx(3, "%s: cdata [%.*s] (state = %d)", __func__, (int)len, cdata, state);
1410 
1411 	switch(state)
1412 	{
1413 	case ALARM:
1414 		upsdebugx(2, "ALARM%.*s", (int)len, cdata);
1415 		break;
1416 
1417 	case SU_OBJECT:
1418 	case GO_OBJECT:
1419 		snprintfcat(val, sizeof(val), "%.*s", (int)len, cdata);
1420 		break;
1421 	}
1422 
1423 	return 0;
1424 }
1425 
1426 /* End element callback; may return non-zero to abort the parse. */
mge_xml_endelm_cb(void * userdata,int state,const char * nspace,const char * name)1427 static int mge_xml_endelm_cb(void *userdata, int state, const char *nspace, const char *name)
1428 {
1429 	xml_info_t	*info;
1430 	const char	*value;
1431 	NUT_UNUSED_VARIABLE(userdata);
1432 	NUT_UNUSED_VARIABLE(nspace);
1433 
1434 	/* ignore objects for which no value was set */
1435 	if (strlen(val) == 0) {
1436 		upsdebugx(3, "%s: name </%s> ignored, no value set (state = %d)", __func__, name, state);
1437 		return 0;
1438 	}
1439 
1440 	upsdebugx(3, "%s: name </%s> (state = %d)", __func__, name, state);
1441 
1442 	switch(state)
1443 	{
1444 	case ALARM:
1445 	case SU_OBJECT:
1446 	case GO_OBJECT:
1447 		for (info = mge_xml2nut; info->xmlname != NULL; info++) {
1448 			if (strcasecmp(var, info->xmlname)) {
1449 				continue;
1450 			}
1451 
1452 			upsdebugx(3, "-> XML variable %s [%s] maps to NUT variable %s", var, val, info->nutname);
1453 
1454 			if ((info->nutflags & ST_FLAG_STATIC) && dstate_getinfo(info->nutname)) {
1455 				return 0;
1456 			}
1457 
1458 			if (info->convert) {
1459 				value = info->convert(val);
1460 				upsdebugx(4, "-> XML variable %s [%s] which maps to NUT variable %s was converted to value %s for the NUT driver state", var, val, info->nutname, value);
1461 			} else {
1462 				value = val;
1463 			}
1464 
1465 			if (value != NULL) {
1466 				dstate_setinfo(info->nutname, "%s", value);
1467 			}
1468 
1469 			return 0;
1470 		}
1471 
1472 		upsdebugx(3, "-> XML variable %s [%s] doesn't map to any NUT variable", var, val);
1473 		break;
1474 
1475 	case PI_GET_OBJECT:
1476 	case GET_OBJECT:
1477 		/* We've just got a snapshot of all runtime data, saved well into
1478 		 * dstate's already, so can estimate missing values if needed. */
1479 
1480 		/* For phase setup, we assume it does not change during run-time.
1481 		 * Essentially this means that once we've detected it is N-phase,
1482 		 * it stays this way for the rest of the driver run/life-time. */
1483 		/* To change this behavior just flip the maychange flag to "1" */
1484 
1485 		dstate_detect_phasecount("input.", 1,
1486 			&inited_phaseinfo_in, &num_inphases, 0);
1487 		dstate_detect_phasecount("input.bypass.", 1,
1488 			&inited_phaseinfo_bypass, &num_bypassphases, 0);
1489 		dstate_detect_phasecount("output.", 1,
1490 			&inited_phaseinfo_out, &num_outphases, 0);
1491 
1492 		break;
1493 	}
1494 
1495 	return 0;
1496 }
1497 
1498 subdriver_t mge_xml_subdriver = {
1499 	MGE_XML_VERSION,
1500 	MGE_XML_INITUPS,
1501 	MGE_XML_INITINFO,
1502 	NULL,
1503 	NULL,
1504 	NULL,
1505 	NULL,
1506 	NULL,
1507 	mge_xml_startelm_cb,
1508 	mge_xml_cdata_cb,
1509 	mge_xml_endelm_cb,
1510 };
1511 
vname_nut2mge_xml(const char * name)1512 const char *vname_nut2mge_xml(const char *name) {
1513 	assert(NULL != name);
1514 
1515 	size_t i = 0;
1516 
1517 	for (; i < sizeof(mge_xml2nut) / sizeof(xml_info_t); ++i) {
1518 		xml_info_t *info = mge_xml2nut + i;
1519 
1520 		if (NULL != info->nutname)
1521 			if (0 == strcasecmp(name, info->nutname))
1522 				return info->xmlname;
1523 	}
1524 
1525 	return NULL;
1526 }
1527 
vname_mge_xml2nut(const char * name)1528 const char *vname_mge_xml2nut(const char *name) {
1529 	assert(NULL != name);
1530 
1531 	size_t i = 0;
1532 
1533 	for (; i < sizeof(mge_xml2nut) / sizeof(xml_info_t); ++i) {
1534 		xml_info_t *info = mge_xml2nut + i;
1535 
1536 		if (NULL != info->xmlname)
1537 			if (0 == strcasecmp(name, info->xmlname))
1538 				return info->nutname;
1539 	}
1540 
1541 	return NULL;
1542 }
1543 
vvalue_mge_xml2nut(const char * name,const char * value,size_t len)1544 char *vvalue_mge_xml2nut(const char *name, const char *value, size_t len) {
1545 	assert(NULL != name);
1546 
1547 	size_t i = 0;
1548 
1549 	for (; i < sizeof(mge_xml2nut) / sizeof(xml_info_t); ++i) {
1550 		xml_info_t *info = mge_xml2nut + i;
1551 
1552 		if (NULL != info->nutname)
1553 			if (0 == strcasecmp(name, info->nutname)) {
1554 				/* Copy value */
1555 				char *vcpy = (char *)malloc((len + 1) * sizeof(char));
1556 
1557 				if (NULL == vcpy)
1558 					return vcpy;
1559 
1560 				memcpy(vcpy, value, len * sizeof(char));
1561 				vcpy[len] = '\0';
1562 
1563 				/* Convert */
1564 				if (NULL != info->convert) {
1565 					char *vconv = (char *)info->convert(vcpy);
1566 
1567 					free(vcpy);
1568 
1569 					return vconv;
1570 				}
1571 				else
1572 					return vcpy;
1573 			}
1574 	}
1575 
1576 	return NULL;
1577 }
1578 
vname_register_rw(void)1579 void vname_register_rw(void) {
1580 	size_t i = 0;
1581 
1582 	for (; i < sizeof(mge_xml2nut) / sizeof(xml_info_t); ++i) {
1583 		xml_info_t *info = mge_xml2nut + i;
1584 
1585 		if (NULL != info->nutname && info->nutflags & ST_FLAG_RW) {
1586 			dstate_setinfo(info->nutname, "%s", "");
1587 			dstate_setflags(info->nutname, ST_FLAG_RW);
1588 		}
1589 	}
1590 }
1591