1 /*
2 Copyright (C) 2016-2021, Dirk Krause
3 SPDX-License-Identifier: BSD-3-Clause
4 */
5 
6 /*
7 	WARNING: This file was generated by the dkct program (see
8 	http://dktools.sourceforge.net/ for details).
9 	Changes you make here will be lost if dkct is run again!
10 	You should modify the original source and run dkct on it.
11 	Original source: pjsnmp.ctr
12 */
13 
14 /**	@file pjsnmp.c The pjsnmp module.
15 */
16 
17 
18 #include "dk4conf.h"
19 #include <libdk4base/dk4types.h>
20 
21 #include <stdio.h>
22 
23 #if DK4_HAVE_SYS_TYPES_H
24 #include <sys/types.h>
25 #endif
26 
27 #if DK4_HAVE_UNISTD_H
28 #include <unistd.h>
29 #endif
30 
31 
32 #if DK4_HAVE_LIBNETSNMP && ((DK4_HAVE_SIGACTION) || (DK4_HAVE_SIGSET))
33 
34 #include <net-snmp/net-snmp-config.h>
35 #include <net-snmp/net-snmp-includes.h>
36 #include <net-snmp/utilities.h>
37 #include <net-snmp/library/snmp_logging.h>
38 
39 #include <libdk4base/dk4types.h>
40 #include <libdk4c/dk4inst.h>
41 #include <libdk4ma/dk4maasz.h>
42 #include <libdk4ma/dk4maadu.h>
43 #include <libdk4base/dk4mem.h>
44 #include <libdk4c/dk4sto.h>
45 #include <libdk4base/dk4str8.h>
46 #include <libdk4c/dk4fopc8.h>
47 #include <libdk4c/dk4stat.h>
48 #include <libdk4c/dk4stat8.h>
49 #include <libdk4maio8d/dk4mai8dus.h>
50 #include <libdk4maio8h/dk4mai8huc.h>
51 #include <libdk4maio8d/dk4mai8dii.h>
52 #include <libdk4maio8d/dk4mai8ddu.h>
53 #include <libdk4maio8d/dk4mao8d.h>
54 #include <libdk4maio8h/dk4mao8h.h>
55 #include <libdk4c/dk4time.h>
56 #include <libdk4c/dk4time08.h>
57 #include <libdk4sock/dk4sock.h>
58 #include <libdk4c/dk4isadm.h>
59 #include <libdk4c/dk4lprng.h>
60 #include <libdk4base/dk4unused.h>
61 
62 
63 
64 
65 
66 #endif
67 /* if DK4_HAVE_LIBNETSNMP && ((DK4_HAVE_SIGACTION) || (DK4_HAVE_SIGSET)) */
68 
69 
70 
71 /**	One status text entry from SNMP model.
72 */
73 typedef struct {
74   unsigned char		*text;	/**< Text pointer, not 0-terminated. */
75   size_t		 size;	/**< Text size. */
76   int			 state;	/**< Summary state if text was found. */
77   int			 start;	/**< Flag: Text here is start text only. */
78 } status_text_t;
79 
80 
81 #if DK4_HAVE_LIBNETSNMP && ((DK4_HAVE_SIGACTION) || (DK4_HAVE_SIGSET))
82 
83 
84 /**	SNMP device status.
85 */
86 enum {
87   SNMP_DEVST_UNKNOWN	= 1 ,	/**< Status is unknown. */
88 
89   SNMP_DEVST_RUNNING	= 2 ,	/**< Running. */
90 
91   SNMP_DEVST_WARNING	= 3 ,	/**< Warning condition active. */
92 
93   SNMP_DEVST_TESTING	= 4 ,	/**< In self test. */
94 
95   SNMP_DEVST_DOWN	= 5	/**< Down due to error condition. */
96 };
97 
98 
99 /**	SNMP printer status.
100 */
101 enum {
102   SNMP_PRST_OTHER	= 1 ,	/**< Any state not mentioned below. */
103 
104   SNMP_PRST_UNKNOWN	= 2 ,	/**< Unknown. */
105 
106   SNMP_PRST_IDLE	= 3 ,	/**< Ready, waiting for next job. */
107 
108   SNMP_PRST_PRINTING	= 4 ,	/**< Printing a job. */
109 
110   SNMP_PRST_WARMUP	= 5	/**< Warming up. */
111 };
112 
113 
114 /**	State summary.
115 	For accounting we would only need to distinguish between
116 	standby/idle (secure to retrieve page counter) and anything
117 	else.
118 	But we want to print human readable state summaries to status
119 	file which are shown by lpq -L.
120 */
121 enum {
122   PJSNMP_ST_UNKNOWN	= 0 ,	/**< Failed to retrieve printer state. */
123 
124   PJSNMP_ST_UNREACHABLE	= 1 ,	/**< Printer is unreachable. */
125 
126   PJSNMP_ST_ERROR	= 2 ,	/**< Error state on printer. */
127 
128   PJSNMP_ST_BUSY	= 3 ,	/**< Printer is printing. */
129 
130   PJSNMP_ST_IDLE	= 4 ,	/**< Printer idle, can retrieve page counter. */
131 
132   PJSNMP_ST_WARMUP	= 5 ,	/**< Warming up. */
133 
134   PJSNMP_ST_STANDBY	= 6 ,	/**< Standby. */
135 };
136 
137 
138 /**	@defgroup	pdes	Printer detected error states.
139 	The first byte in the octet string is the most significant byte
140 	in the unsigned long value.
141 */
142 /**@{*/
143 /**	Warning: Paper low.
144 */
145 #define	PDES_WARNING_PAPER_LOW	0x80000000UL
146 
147 /**	Error: Out of paper.
148 */
149 #define	PDES_ERROR_NO_PAPER	0x40000000UL
150 
151 /**	Warning: Toner low.
152 */
153 #define	PDES_WARNING_TONER_LOW	0x20000000UL
154 
155 /**	Error: Out of toner.
156 */
157 #define	PDES_ERROR_NO_TONER	0x10000000UL
158 
159 /**	Error: Door open.
160 */
161 #define	PDES_ERROR_DOOR_OPEN	0x08000000UL
162 
163 /**	Error: Paper jam.
164 */
165 #define	PDES_ERROR_PAPER_JAM	0x04000000UL
166 
167 /**	Error: Printer offline.
168 */
169 #define	PDES_ERROR_OFFLINE	0x02000000UL
170 
171 /**	Warning: Service requested.
172 */
173 #define	PDES_WARNING_SERVICE	0x01000000UL
174 
175 /**	Input tray removed.
176 */
177 #define	PDES_ERROR_INPUT_TRAY_MISSING	0x00800000UL
178 
179 /**	Output tray removed.
180 */
181 #define	PDES_ERROR_OUTPUT_TRAY_MISSING	0x00400000UL
182 
183 /**	Marker supply missing.
184 */
185 #define	PDES_ERROR_MARKER_SUPPLY_MISSING	0x00200000UL
186 
187 /**	Output tray nearly full.
188 */
189 #define	PDES_WARNING_OUTPUT_NEAR_FULL		0x00100000UL
190 
191 /**	Output tray full.
192 */
193 #define	PDES_ERROR_OUTPUT_FULL		0x00080000UL
194 
195 /**	At least one input tray empty.
196 */
197 #define	PDES_WARNING_INPUT_TRAY_EMPTY		0x00040000UL
198 
199 /**	Overdue preventive maintenance.
200 */
201 #define	PDES_WARNING_OVERDUE_PREVENT_MAINT	0x00020000UL
202 
203 
204 /**	Bitmask to check if there is any error condition.
205 */
206 #define	PDES_ANY_ERROR	\
207 ( PDES_ERROR_NO_PAPER \
208 | PDES_ERROR_NO_TONER \
209 | PDES_ERROR_DOOR_OPEN \
210 | PDES_ERROR_PAPER_JAM \
211 | PDES_ERROR_OFFLINE \
212 | PDES_ERROR_INPUT_TRAY_MISSING \
213 | PDES_ERROR_OUTPUT_TRAY_MISSING \
214 | PDES_ERROR_MARKER_SUPPLY_MISSING \
215 | PDES_ERROR_OUTPUT_FULL)
216 
217 
218 /**	Bitmask to check if there is any warning condition.
219 */
220 #define	PDES_ANY_WARNING \
221 ( PDES_WARNING_PAPER_LOW \
222 | PDES_WARNING_TONER_LOW \
223 | PDES_WARNING_SERVICE \
224 | PDES_WARNING_OUTPUT_NEAR_FULL \
225 | PDES_WARNING_OVERDUE_PREVENT_MAINT \
226 | PDES_WARNING_INPUT_TRAY_EMPTY)
227 
228 
229 /**	Bitmask to check whether any error or warning condition is set.
230 */
231 #define	PDES_ANY_CONDITION ((PDES_ANY_WARNING) | (PDES_ANY_ERROR))
232 
233 /**@}*/
234 
235 
236 /**	Buffer for sending.
237 	Should be large to minimize number of I/O operations.
238 */
239 #if DK4_SIZEOF_SIZE_T > 2
240 static	char		pjsnmp_buf[1048576];
241 #else
242 static	char		pjsnmp_buf[16384];
243 #endif
244 
245 
246 /**	Current status text, also used in accounting.
247 */
248 static	char		stat_text[2048];
249 
250 
251 /**	Buffer for responses from printer.
252 */
253 static	char		dummy_text[2048];
254 
255 
256 /**	Previous status text.
257 */
258 static	char		ostat_text[sizeof(stat_text)];
259 
260 
261 /**	Buffer for automatically constructed job name.
262 */
263 static	char		job_name_buf[32+(8*sizeof(dk4_um_t))];
264 
265 
266 /**	Status text oid.
267 */
268 static	oid		oid_st[MAX_OID_LEN];
269 
270 
271 /**	OID for device status.
272 */
273 static const	oid oid_ds[] = {
274   (oid)1,  (oid)3, (oid)6, (oid)1, (oid)2, (oid)1,
275   (oid)25, (oid)3, (oid)2, (oid)1, (oid)5, (oid)1
276 };
277 
278 
279 /**	OID for printer status.
280 */
281 static	const oid	oid_ps[] = {
282   (oid)1,  (oid)3, (oid)6, (oid)1, (oid)2, (oid)1,
283   (oid)25, (oid)3, (oid)5, (oid)1, (oid)1, (oid)1
284 };
285 
286 
287 /**	OID for pagecount value.
288 */
289 static	const oid	oid_pc[] = {
290   (oid)1,  (oid)3,  (oid)6, (oid)1, (oid)2, (oid)1,
291   (oid)43, (oid)10, (oid)2, (oid)1, (oid)4, (oid)1, (oid)1
292 };
293 
294 
295 /**	OID for printer detected error state.
296 */
297 static	const oid	oid_pe[] = {
298   (oid)1,  (oid)3, (oid)6, (oid)1, (oid)2, (oid)1,
299   (oid)25, (oid)3, (oid)5, (oid)1, (oid)2, (oid)1
300 };
301 
302 
303 /**	Default OID for status text.
304 */
305 static	const oid	oid_dst[] = {
306  (oid)1,  (oid)3,  (oid)6, (oid)1, (oid)2, (oid)1,
307  (oid)43, (oid)16, (oid)5, (oid)1, (oid)2, (oid)1, (oid)1
308 };
309 
310 
311 /**	Constant texts, not localized.
312 */
313 static const char * const	pjsnmp_kw[] = {
314 /* 0 */
315 "\n",
316 
317 /* 1 */
318 " ",
319 
320 /* 2 */
321 "PRINTCAP_ENTRY",
322 
323 /* 3 */
324 "*",
325 
326 /* 4 */
327 "pjsnmp",
328 
329 /* 5 */
330 "public",
331 
332 /* 6 */
333 "acct-check",
334 
335 /* 7 */
336 "Device and printer status:    ",
337 
338 /* 8 */
339 "/",
340 
341 /* 9 */
342 "Printer detected error state: ",
343 
344 /* 10 */
345 "Current printer state:        ",
346 
347 /* 11 */
348 "not found",
349 
350 /* 12 */
351 "unknown",
352 
353 /* 13 */
354 "running",
355 
356 /* 14 */
357 "warning",
358 
359 /* 15 */
360 "testing",
361 
362 /* 16 */
363 "down",
364 
365 /* 17 */
366 "not found",
367 
368 /* 18 */
369 "other",
370 
371 /* 19 */
372 "unknown",
373 
374 /* 20 */
375 "idle",
376 
377 /* 21 */
378 "printing",
379 
380 /* 22 */
381 "warmup",
382 
383 /* 23 */
384 "UNKNOWN",
385 
386 /* 24 */
387 "UNREACHABLE",
388 
389 /* 25 */
390 "ERROR",
391 
392 /* 26 */
393 "BUSY",
394 
395 /* 27 */
396 "IDLE",
397 
398 /* 28 */
399 "WARMUP",
400 
401 /* 29 */
402 "STANDBY",
403 
404 /* 30 */
405 "\"",
406 
407 /* 31 */
408 "\"\n",
409 
410 /* 32 */
411 "ERROR:   ",
412 
413 /* 33 */
414 "Warning: ",
415 
416 /* 34 */
417 "Paper low (printer will run out of paper soon).\n",
418 
419 /* 35 */
420 "Out of paper!\n",
421 
422 /* 36 */
423 "Toner low (printer will run out of toner soon).\n",
424 
425 /* 37 */
426 "Out of toner!\n",
427 
428 /* 38 */
429 "Door open!\n",
430 
431 /* 39 */
432 "Paper jam!\n",
433 
434 /* 40 */
435 "Offline!\n",
436 
437 /* 41 */
438 "Service requested.\n",
439 
440 /* 42 */
441 "Input tray missing!\n",
442 
443 /* 43 */
444 "Output tray missing!\n",
445 
446 /* 44 */
447 "Marker supply missing!\n",
448 
449 /* 45 */
450 "Output tray nearly full (will be full soon).\n",
451 
452 /* 46 */
453 "Output tray full!\n",
454 
455 /* 47 */
456 "At least one input tray is empty.\n",
457 
458 /* 48 */
459 "Overdue preventive maintenance.\n",
460 
461 /* 49 */
462 "ERROR ON PRINTER, MANUAL INTERVENTION REQUIRED!\n",
463 
464 /* 50 */
465 "PRINTER PROBABLY REQUIRES MANUAL INTERVENTION!\n",
466 
467 /* 51 */
468 "acct-start",
469 
470 /* 52 */
471 "acct-end",
472 
473 /* 53 */
474 "acct-charge",
475 
476 /* 54 */
477 "print-job",
478 
479 /* 55 */
480 "Print job finished.\n",
481 
482 /* 56 */
483 "Job size:      ",
484 
485 /* 57 */
486 "Data transfer: ",
487 
488 /* 58 */
489 "Processing:    ",
490 
491 /* 59 */
492 "Pages:         ",
493 
494 /* 60 */
495 " bytes\n",
496 
497 /* 61 */
498 " seconds\n",
499 
500 /* 62 */
501 "# ",
502 
503 /* 63 */
504 "Configuration problem (command line arguments)!\n",
505 
506 /* 64 */
507 "Configuration problem (printcap file)!\n",
508 
509 /* 65 */
510 "Configuration problem (SNMP model file)!\n",
511 
512 /* 66 */
513 "ERROR: Missing option name!\n",
514 
515 /* 67 */
516 "ERROR: Missing option argument!\n",
517 
518 /* 68 */
519 "ERROR: Non-option command line argument found!\n",
520 
521 /* 69 */
522 "ERROR: No user name specified!\n",
523 
524 /* 70 */
525 "ERROR: No print queue name specified!\n",
526 
527 /* 71 */
528 "ERROR: No print job name specified!\n",
529 
530 /* 72 */
531 "Warning: Redefinition of \"",
532 
533 /* 73 */
534 "\" to \"",
535 
536 /* 74 */
537 "\"!\n",
538 
539 /* 75 */
540 "ERROR: Empty text for option \"",
541 
542 /* 76 */
543 "\"!\n",
544 
545 /* 77 */
546 "ERROR: Missing text for \"",
547 
548 /* 78 */
549 "\"!\n",
550 
551 /* 79 */
552 "ERROR: Option \"",
553 
554 /* 80 */
555 "\" requires unsigned short number!\nIllegal text: \"",
556 
557 /* 81 */
558 "\"!",
559 
560 /* 82 */
561 "ERROR: Illegal SNMP version: \"",
562 
563 /* 83 */
564 "\"!\nAllowed: \"1\", \"2c\", \"3\"!\n",
565 
566 /* 84 */
567 "ERROR: Option \"",
568 
569 /* 85 */
570 "\" requires an integer value!\nIllegal text: \"",
571 
572 /* 86 */
573 "\"!\n",
574 
575 /* 87 */
576 "ERROR: Missing \"]\"!\n",
577 
578 /* 88 */
579 "ERROR: Missing model name!\n",
580 
581 /* 89 */
582 "ERROR: Illegal summary state: \"",
583 
584 /* 90 */
585 "\"!\n",
586 
587 /* 91 */
588 "ERROR: Illegal printer status name: \"",
589 
590 /* 92 */
591 "\"!\n",
592 
593 /* 93 */
594 "ERROR: Illegal device status name: \"",
595 
596 /* 94 */
597 "\"!",
598 
599 /* 95 */
600 "ERROR: Missing printer status name!\n",
601 
602 /* 96 */
603 "ERROR: Missing summary state name!\n",
604 
605 /* 97 */
606 "ERROR: Illegal condition name: \"",
607 
608 /* 98 */
609 "\"!\n",
610 
611 /* 99 */
612 "ERROR: OID too long!\n",
613 
614 /* 100 */
615 "ERROR: Numeric overflow for sub id: \"",
616 
617 /* 101 */
618 "\"!\n",
619 
620 /* 102 */
621 "ERROR: Not a number: \"",
622 
623 /* 103 */
624 "\"!\n",
625 
626 /* 104 */
627 "ERROR: Empty OID text!\n",
628 
629 /* 105 */
630 "ERROR: Memory allocation failed!\n",
631 
632 /* 106 */
633 "ERROR: Empty string!\n",
634 
635 /* 107 */
636 "ERROR: Incorrect string specification!\n",
637 
638 /* 108 */
639 "ERROR: Not a hexadecimal byte: \"",
640 
641 /* 109 */
642 "\"!\n",
643 
644 /* 110 */
645 "ERROR: Value required!\n",
646 
647 /* 111 */
648 "ERROR: Not a boolean: \"",
649 
650 /* 112 */
651 "\"!\n",
652 
653 /* 113 */
654 "ERROR: Illegal key: \"",
655 
656 /* 114 */
657 "\"!\n",
658 
659 /* 115 */
660 "ERROR: Model not found: \"",
661 
662 /* 116 */
663 "\"!\n",
664 
665 /* 117 */
666 "ERROR: Failed to open model file!\n\"",
667 
668 /* 118 */
669 "\"!\n",
670 
671 /* 119 */
672 "ERROR: Missing host name for printer!\n",
673 
674 /* 120 */
675 "ERROR: PRINTCAP_ENTRY not found in environment!\n",
676 
677 /* 121 */
678 "ERROR: Failed to create SNMP session!\n",
679 
680 /* 122 */
681 "ERROR: Failed to send data to accounting system!\n",
682 
683 /* 123 */
684 "ERROR: Partial success when sending data to accounting system!\n",
685 
686 /* 124 */
687 "ERROR: Failed to shut down accounting socket!\n",
688 
689 /* 125 */
690 "ERROR: Failed to connect to accounting system!\n",
691 
692 /* 126 */
693 "ERROR: Failed to start accounting program!\n",
694 
695 /* 127 */
696 "ERROR: Missing command name for accounting program!\n",
697 
698 /* 128 */
699 "ERROR: Failed to open accounting file!\n",
700 
701 /* 129 */
702 "ERROR: Can not receive response from pipe!\n",
703 
704 /* 130 */
705 "ERROR: Can not receive response from file!\n",
706 
707 /* 131 */
708 "Checking permission: user=\"",
709 
710 /* 132 */
711 "\" printer=\"",
712 
713 /* 133 */
714 "\".\n",
715 
716 /* 134 */
717 "Printing allowed.\n",
718 
719 /* 135 */
720 "ERROR: PRINTING DENIED BY ACCOUNTING/QUOTA SYSTEM!\n",
721 
722 /* 136 */
723 "ERROR: Printer unreachable too long!\n",
724 
725 /* 137 */
726 "ERROR: Network connection not writeable (timeout)!\n",
727 
728 /* 138 */
729 "ERROR: Failed to send data!\n",
730 
731 /* 139 */
732 "ERROR: Failed to read print data from standard input!\n",
733 
734 /* 140 */
735 "ERROR: Failed to connect to printer!\n",
736 
737 /* 141 */
738 "ERROR: Failed to set up signal handlers!\n",
739 
740 /* 142 */
741 "ERROR: Failed to restore signal handlers!\n",
742 
743 /* 143 */
744 ":",
745 
746 /* 144 */
747 "",
748 
749 /* 145 */
750 "Retrieving page counter at start.\n",
751 
752 /* 146 */
753 "Retrieving page counter at end.\n",
754 
755 /* 147 */
756 "Page counter at start: ",
757 
758 /* 148 */
759 "Page counter at end:   ",
760 
761 /* 149 */
762 "Failed to retrieve page counter value!\n",
763 
764 /* 150 */
765 "---\n",
766 
767 /* 151 */
768 "Starting print data transfer.\n",
769 
770 /* 152 */
771 "Finished print data transfer.\n",
772 
773 /* 153 */
774 "Print data transfer aborted.\n",
775 
776 /* 154 */
777 "Transmitting accounting data via network socket.\n",
778 
779 /* 155 */
780 "Writing accounting data pipe.\n",
781 
782 /* 156 */
783 "Transmitting accounting data via local socket.\n",
784 
785 /* 157 */
786 "Writing accounting data to file.\n",
787 
788 /* 158 */
789 "Transmitting accounting data to fd 3.\n",
790 
791 /* 159 */
792 "Accounting data transmitted successfully.\n",
793 
794 /* 160 */
795 "ERROR: Failed to transmit accounting data!\n",
796 
797 /* 161 */
798 "\" requires an unsigned integer value!\nIllegal text: \"",
799 
800 /* 162 */
801 "Warning: Unusual change to idle/standby state.\nWaiting ",
802 
803 /* 163 */
804 " seconds ",
805 
806 /* 164 */
807 "for printer to resume printing.\n",
808 
809 /* 165 */
810 "ERROR: No accounting destination configured!\n",
811 
812 /* 166 */
813 "Response from accounting system: \"",
814 
815 /* 167 */
816 "\".\n",
817 
818 /* 168 */
819 "Printer in error state too long!\n",
820 
821 /* 169 */
822 "Command line arguments:\n",
823 
824 /* 170 */
825 "ERROR: Failed to initialize socket subsystem!\n",
826 
827 /* 171 */
828 "pjsnmp@localhost+",
829 
830 NULL
831 
832 };
833 
834 
835 
836 /**	Responses from accounting system.
837 */
838 static const char * const	accounting_responses[] = {
839 /* 0 */
840 "ACCEPT",
841 
842 /* 1 */
843 "HOLD",
844 
845 /* 2 */
846 "REMOVE",
847 
848 NULL
849 
850 };
851 
852 
853 
854 /**	Names for configuration items in the printcap entry.
855 */
856 static const char * const	printcap_entry_names[] = {
857 /* 0 */
858 "pjsnmp-host",
859 
860 /* 1 */
861 "pjsnmp-port",
862 
863 /* 2 */
864 "pjsnmp-ordrel",
865 
866 /* 3 */
867 "pjsnmp-accounting-enable",
868 
869 /* 4 */
870 "pjsnmp-accounting-check",
871 
872 /* 5 */
873 "pjsnmp-accounting-file",
874 
875 /* 6 */
876 "pjsnmp-accounting-host",
877 
878 /* 7 */
879 "pjsnmp-accounting-port",
880 
881 /* 8 */
882 "pjsnmp-require-printing",
883 
884 /* 9 */
885 "pjsnmp-version",
886 
887 /* 10 */
888 "pjsnmp-community",
889 
890 /* 11 */
891 "pjsnmp-during-transfer",
892 
893 /* 12 */
894 "pjsnmp-model-file",
895 
896 /* 13 */
897 "pjsnmp-model-name",
898 
899 /* 14 */
900 "pjsnmp-ignore-failed-session",
901 
902 /* 15 */
903 "pjsnmp-allow-printing-if-accounting-connection-failed",
904 
905 /* 16 */
906 "pjsnmp-pdes-always",
907 
908 /* 17 */
909 "pjsnmp-unknown-busy",
910 
911 /* 18 */
912 "pjsnmp-unreachable-timeout-start",
913 
914 /* 19 */
915 "pjsnmp-unreachable-timeout-end",
916 
917 /* 20 */
918 "pjsnmp-unreachable-timeout-printing",
919 
920 /* 21 */
921 "pjsnmp-local-port",
922 
923 /* 22 */
924 "pjsnmp-unwriteable-timeout-printing",
925 
926 /* 23 */
927 "pjsnmp-read-response",
928 
929 /* 24 */
930 "pjsnmp-force-printable-status-text",
931 
932 /* 25 */
933 "pjsnmp-error-timeout-start",
934 
935 /* 26 */
936 "pjsnmp-error-timeout-end",
937 
938 /* 27 */
939 "pjsnmp-error-timeout-printing",
940 
941 /* 28 */
942 "pjsnmp-verbose",
943 
944 /* 29 */
945 "pjsnmp-non-ascii-job-title",
946 
947 /* 30 */
948 "pjsnmp-accounting-start-end",
949 
950 NULL
951 
952 };
953 
954 
955 /**	SNMP version names, 2 and 2c are the same.
956 */
957 static const char * const	snmp_version_names[] = {
958 /* 0 */
959 "1",
960 
961 /* 1 */
962 "2",
963 
964 /* 2 */
965 "2c",
966 
967 /* 3 */
968 "3",
969 
970 NULL
971 
972 };
973 
974 
975 /**	Keywords used in the SNMP models file.
976 */
977 static const char * const	model_keys[] = {
978 /* 0 */
979 "map",
980 
981 /* 1 */
982 "error condition",
983 
984 /* 2 */
985 "add error condition",
986 
987 /* 3 */
988 "status text oid",
989 
990 /* 4 */
991 "text standby",
992 
993 /* 5 */
994 "start standby",
995 
996 /* 6 */
997 "text idle",
998 
999 /* 7 */
1000 "start idle",
1001 
1002 /* 8 */
1003 "always use status text",
1004 
1005 /* 9 */
1006 "text busy",
1007 
1008 /* 10 */
1009 "start busy",
1010 
1011 /* 11 */
1012 "text unknown",
1013 
1014 /* 12 */
1015 "start unknown",
1016 
1017 /* 13 */
1018 "text error",
1019 
1020 /* 14 */
1021 "start error",
1022 
1023 /* 15 */
1024 "text warmup",
1025 
1026 /* 16 */
1027 "start warmup",
1028 
1029 NULL
1030 
1031 };
1032 
1033 
1034 /**	Summary state keywords used in the models file, can be abbreviated.
1035 */
1036 static const char * const	summary_state_names[] = {
1037 /* 0 */
1038 "u$nknown",
1039 
1040 /* 1 */
1041 "e$rror",
1042 
1043 /* 2 */
1044 "b$usy",
1045 
1046 /* 3 */
1047 "i$dle",
1048 
1049 /* 4 */
1050 "w$armup",
1051 
1052 /* 5 */
1053 "s$tandby",
1054 
1055 NULL
1056 
1057 };
1058 
1059 
1060 /**	Device status names, can be abbreviated.
1061 */
1062 static const char * const	device_status_names[] = {
1063 /* 0 */
1064 "u$nknown",
1065 
1066 /* 1 */
1067 "r$unning",
1068 
1069 /* 2 */
1070 "w$arning",
1071 
1072 /* 3 */
1073 "t$esting",
1074 
1075 /* 4 */
1076 "d$own",
1077 
1078 NULL
1079 
1080 };
1081 
1082 
1083 /**	Printer status names, can be abbreviated.
1084 */
1085 static const char * const	printer_status_names[] = {
1086 /* 0 */
1087 "o$ther",
1088 
1089 /* 1 */
1090 "u$nknown",
1091 
1092 /* 2 */
1093 "i$dle",
1094 
1095 /* 3 */
1096 "p$rinting",
1097 
1098 /* 4 */
1099 "w$armup",
1100 
1101 NULL
1102 
1103 };
1104 
1105 
1106 /**	Names for the condition bits in the SNMP models file.
1107 */
1108 static const char * const	condition_names[] = {
1109 /* 0 */
1110 "low-paper",
1111 
1112 /* 1 */
1113 "no-paper",
1114 
1115 /* 2 */
1116 "low-toner",
1117 
1118 /* 3 */
1119 "no-toner",
1120 
1121 /* 4 */
1122 "door-open",
1123 
1124 /* 5 */
1125 "paper-jam",
1126 
1127 /* 6 */
1128 "offline",
1129 
1130 /* 7 */
1131 "service-requested",
1132 
1133 /* 8 */
1134 "input-tray-missing",
1135 
1136 /* 9 */
1137 "output-tray-missing",
1138 
1139 /* 10 */
1140 "marker-supply-missing",
1141 
1142 /* 11 */
1143 "output-near-full",
1144 
1145 /* 12 */
1146 "output-full",
1147 
1148 /* 13 */
1149 "input-tray-empty",
1150 
1151 /* 14 */
1152 "overdue-preventive-maintenance",
1153 
1154 NULL
1155 
1156 };
1157 
1158 
1159 /**	Default configuration file for SNMP models.
1160 */
1161 static const char		def_model_file[] = {
1162 DK4_INST_DIR_SHARE "/dktools/print-snmp.conf"
1163 };
1164 
1165 
1166 /**	Option values for uppercase options.
1167 */
1168 static char	*upper[]	= {
1169   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1170   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
1171 };
1172 
1173 
1174 /**	Option values for lowercase options.
1175 */
1176 static char	*lower[] = {
1177   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1178   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
1179 };
1180 
1181 
1182 /**	Mapping from device/printer status combinations to short summaries.
1183 */
1184 static int	summary_states[]	= {
1185   /* unknown-other    */	PJSNMP_ST_UNKNOWN ,
1186   /* unknown-unknown  */	PJSNMP_ST_UNKNOWN ,
1187   /* unknown-idle     */	PJSNMP_ST_UNKNOWN ,
1188   /* unknown-printing */	PJSNMP_ST_UNKNOWN ,
1189   /* unknown-warmup   */	PJSNMP_ST_WARMUP ,
1190 
1191   /* running-other    */	PJSNMP_ST_STANDBY ,
1192   /* running-unknown  */	PJSNMP_ST_UNKNOWN ,
1193   /* running-idle     */	PJSNMP_ST_IDLE ,
1194   /* running-printing */	PJSNMP_ST_BUSY ,
1195   /* running-warmup   */	PJSNMP_ST_WARMUP ,
1196 
1197   /* warning-other    */	PJSNMP_ST_STANDBY ,
1198   /* warning-unknown  */	PJSNMP_ST_UNKNOWN ,
1199   /* warning-idle     */	PJSNMP_ST_IDLE ,
1200   /* warning-printing */	PJSNMP_ST_BUSY ,
1201   /* warning-warmup   */	PJSNMP_ST_WARMUP ,
1202 
1203   /* testing-other    */	PJSNMP_ST_UNKNOWN ,
1204   /* testing-unknown  */	PJSNMP_ST_UNKNOWN ,
1205   /* testing-idle     */	PJSNMP_ST_UNKNOWN ,
1206   /* testing-printing */	PJSNMP_ST_UNKNOWN ,
1207   /* testing-warmup   */	PJSNMP_ST_WARMUP ,
1208 
1209   /*    down-other    */	PJSNMP_ST_ERROR ,
1210   /*    down-unknown  */	PJSNMP_ST_ERROR ,
1211   /*    down-idle     */	PJSNMP_ST_ERROR ,
1212   /*    down-printing */	PJSNMP_ST_ERROR ,
1213   /*    down-warmup   */	PJSNMP_ST_WARMUP
1214 };
1215 
1216 
1217 
1218 /**	Error report for number of bytes transferred.
1219 */
1220 static	dk4_er_t	er_bytes;
1221 
1222 
1223 /**	Copy of the printcap entry from PRINTCAP_ENTRY environment variable
1224 	(allocated, freed during cleanup before exit).
1225 */
1226 static	char		*printcap_entry	= NULL;
1227 
1228 
1229 /**	Printer host name (from printcap entry).
1230 */
1231 static	char		*host_name	= NULL;
1232 
1233 
1234 /**	User name to be charged for the job (from -n or -L option).
1235 */
1236 static	char		*user_name	= NULL;
1237 
1238 
1239 /**	Print queue name (from -P or -Q option).
1240 */
1241 static	char		*queue_name	= NULL;
1242 
1243 
1244 /**	Job title (from -J -f or -N option).
1245 */
1246 static	char	*job_title	= NULL;
1247 
1248 
1249 /**	Job name from -A -j -t or -D option
1250 	(only needed for old accounting system).
1251 */
1252 static	char		*job_name	= NULL;
1253 
1254 
1255 /**	File, socket, pipe or host name for accounting
1256 	(from pjsnmp-accounting-file in printcap entry).
1257 */
1258 static	char		*acct_name	= NULL;
1259 
1260 
1261 /**	Host to connect to for accounting
1262 	(from pjsnmp-accounting-host in printcap entry).
1263 */
1264 static	char		*acct_host	= NULL;
1265 
1266 
1267 /**	SNMP community name
1268 	(from pjsnmp-community in printcap entry).
1269 */
1270 static	char		*snmp_comm	= NULL;
1271 
1272 
1273 /**	File name containing SNMP models
1274 	(from pjsnmp-model-file in printcap entry).
1275 */
1276 static	char		*model_file	= NULL;
1277 
1278 
1279 /**	SNMP model name (from pjsnmp-model-name in printcap entry).
1280 */
1281 static	char		*model_name	= NULL;
1282 
1283 
1284 /**	Status file for log messages (name obtained from -s cmd arg).
1285 */
1286 static	FILE		*stt_file	= NULL;
1287 
1288 
1289 /**	Output file to use for log messages.
1290 	This is either stt_file or stderr, but never NULL.
1291 */
1292 static	FILE		*out_file	= NULL;
1293 
1294 
1295 /**	SNMP session.
1296 */
1297 static	struct snmp_session	*snmp_sess	= NULL;
1298 
1299 
1300 /**	Storage for status text nodes.
1301 */
1302 static	dk4_sto_t	*s_stn		= NULL;
1303 
1304 
1305 /**	Iterator through storage above.
1306 */
1307 static	dk4_sto_it_t	*i_stn		= NULL;
1308 
1309 
1310 /**	Number of bytes transferred.
1311 */
1312 static	dk4_um_t	 bytes_trans	= (dk4_um_t)0UL;
1313 
1314 
1315 /**	Timeout if printer not seen printing
1316 	(from pjsnmp-require-printing in printcap entry).
1317 	If the first page contains a complicated graphics it
1318 	might take a longer time to start printing.
1319 */
1320 static	dk4_um_t	 print_timeout	= (dk4_um_t)600UL;
1321 
1322 
1323 /**	Timeout if printer is unreachable at start of print job
1324 	(from pjsnmp-unreachable-timeout-start in printcap entry).
1325 */
1326 static	dk4_um_t	 unto_start	= (dk4_um_t)900UL;
1327 
1328 
1329 /**	 Timeout if printer is unreachable during data transfer
1330 	(from pjsnmp-unreachable-timeout-printing in printcap entry).
1331 */
1332 static	dk4_um_t	 unto_print	= (dk4_um_t)120UL;
1333 
1334 /**	Timeout if printer socket is unwriteable during data transfer
1335 	(from pjsnmp-unwriteable-timeout-printing in printcap entry).
1336 */
1337 static	dk4_um_t	 unwt_print	= (dk4_um_t)900UL;
1338 
1339 /**	Timeout if printer is unreachable at end of print job
1340 	(from pjsnmp-unreachable-timeout-end in printcap entry).
1341 */
1342 static	dk4_um_t	 unto_end	= (dk4_um_t)120UL;
1343 
1344 /**	Timeout for error condition before printing to skip job.
1345 */
1346 static	dk4_um_t	 erto_start	= (dk4_um_t)900UL;
1347 
1348 /**	Timeout if printer is in error state during printing.
1349 */
1350 static	dk4_um_t	 erto_print	= (dk4_um_t)86400UL;
1351 
1352 /**	Timeout if printer is in error state after job.
1353 */
1354 static	dk4_um_t	 erto_end	= (dk4_um_t)3600UL;
1355 
1356 /**	Start time printer gone unreachable.
1357 */
1358 static	dk4_time_t	start_unreach	= (dk4_time_t)0UL;
1359 
1360 /**	Start time printer gone error.
1361 */
1362 static	dk4_time_t	start_error	= (dk4_time_t)0UL;
1363 
1364 
1365 /**	Size of device status OID (number of elements).
1366 */
1367 static	const size_t	sz_oid_ds = sizeof(oid_ds)/sizeof(oid);
1368 
1369 
1370 /**	Size of printer status OID (number of elements).
1371 */
1372 static	const size_t	sz_oid_ps = sizeof(oid_ps)/sizeof(oid);
1373 
1374 
1375 /**	Size of page counter OID (number of elements).
1376 */
1377 static	const size_t	sz_oid_pc = sizeof(oid_pc)/sizeof(oid);
1378 
1379 
1380 /**	Size of printer error OID (number of elements).
1381 */
1382 static	const size_t	sz_oid_pe = sizeof(oid_pe)/sizeof(oid);
1383 
1384 
1385 /**	Size of printer error OID (number of elements).
1386 */
1387 static	const size_t	sz_oid_dst = sizeof(oid_dst)/sizeof(oid);
1388 
1389 
1390 /**	Size of printer error OID (number of bytes).
1391 */
1392 static	const size_t	by_oid_dst = sizeof(oid_dst);
1393 
1394 
1395 /**	Number of items in status text OID.
1396 */
1397 static	size_t		sz_oid_st = sizeof(oid_dst)/sizeof(oid);
1398 
1399 
1400 /**	Number of bytes in status text OID.
1401 */
1402 static	size_t		by_oid_st	= sizeof(oid_dst);
1403 
1404 
1405 /**	Number of bytes currently stored in stat_text.
1406 */
1407 static	size_t		sz_stat_text	= 0;
1408 
1409 
1410 /**	Number of bytes stored in ostat_text.
1411 */
1412 static	size_t		sz_ostat_text	= 0;
1413 
1414 
1415 /**	Start of program.
1416 */
1417 static	dk4_time_t	t1		= (dk4_time_t)0UL;
1418 
1419 
1420 /**	Start of data transfer.
1421 */
1422 static	dk4_time_t	t2		= (dk4_time_t)0UL;
1423 
1424 
1425 /**	End of data transfer.
1426 */
1427 static	dk4_time_t	t3		= (dk4_time_t)0UL;
1428 
1429 
1430 /**	End of program.
1431 */
1432 static	dk4_time_t	t4		= (dk4_time_t)0UL;
1433 
1434 
1435 /**	SNMP version number (from pjsnmp-version in printcap entry).
1436 */
1437 static	long		 snmp_version	= SNMP_VERSION_1;
1438 
1439 
1440 /**	Bit mask to retrieve real error conditions from
1441 	hrPrinterDetectedErrorStates
1442 	(modified by error condition and add error condition in model).
1443 */
1444 static	unsigned long	 pdes_error	= PDES_ANY_ERROR ;
1445 
1446 
1447 /**	Previous printer detected error state conditions.
1448 */
1449 static	unsigned long	 opdes_cond	= 0UL;
1450 
1451 
1452 /**	Current printer detected error state conditions.
1453 */
1454 static	unsigned long	 pdes_cond	= 0UL;
1455 
1456 
1457 /**	Page counter at start of job.
1458 */
1459 static	unsigned long	 pc_start	= 0UL;
1460 
1461 
1462 /**	Unusable page counter value (start value or at last error).
1463 */
1464 static	unsigned long	 pc_error	= 0UL;
1465 
1466 
1467 /**	Page counter at end of job.
1468 */
1469 static	unsigned long	 pc_end		= 0UL;
1470 
1471 
1472 /**	Current page counter.
1473 */
1474 static	unsigned long	 pcnt		= 0UL;
1475 
1476 
1477 #endif
1478 /* if DK4_HAVE_LIBNETSNMP && ((DK4_HAVE_SIGACTION) || (DK4_HAVE_SIGSET)) */
1479 
1480 
1481 
1482 /**	Exit status code, must be one from the enum.
1483 */
1484 static	int		exval	= LPRNG_EXIT_REMOVE;
1485 
1486 
1487 #if DK4_HAVE_LIBNETSNMP && ((DK4_HAVE_SIGACTION) || (DK4_HAVE_SIGSET))
1488 
1489 
1490 /**	Flag: Verbose
1491 */
1492 static	int		 verbose	= 0;
1493 
1494 
1495 /**	Flag: Allow non-ASCII characters in job title for accounting.
1496 */
1497 static	int		 allow_non_ascii	= 0;
1498 
1499 
1500 /**	Always use status text (default: only if summary is "unknown").
1501 */
1502 static	int		 stat_always	= 0;
1503 
1504 
1505 /**	Flag: Always use printer detected error state
1506 	(from pjsnmp-pdes-always in printcap entry), default: on.
1507 */
1508 static	int		 pdes_always	= 1;
1509 
1510 
1511 /**	Flag: Reset of pdes_error was done.
1512 */
1513 static	int		 pdes_reset	= 0;
1514 
1515 
1516 /**	Flag: Report unknown states as busy
1517 	(from pjsnmp-unknown-busy in printcap entry), default: off.
1518 */
1519 static	int		 unkn_busy	= 0;
1520 
1521 
1522 /**	Flag: Do orderly release (from pjsnmp-ordrel in printcap entry).
1523 */
1524 static	int		 host_ordr	= 0;
1525 
1526 
1527 /**	Flag: Accounting enabled
1528 	(from pjsnmp-accounting-enable in printcap entry).
1529 */
1530 static	int		 acct_enab	= 0;
1531 
1532 
1533 /**	Flag: Quota check enabled
1534 	(from pjsnmp-accounting-check in printcap entry).
1535 */
1536 static	int		 acct_achk	= 0;
1537 
1538 
1539 /**	Flag: Use separated start/end lines for accounting.
1540 	Default is to use just one charge line at end.
1541 */
1542 static	int		 acct_start_end	= 0;
1543 
1544 
1545 /**	Flag: Read printer responses
1546 	(from pjsnmp-read-response in printcap entry).
1547 */
1548 static	int		 read_responses	= 0;
1549 
1550 
1551 /**	Flag: Force printable status text
1552 	(from pjsnmp-force-printable-status-text in printcap entry).
1553 */
1554 static	int		 force_printable_status_text	= 1;
1555 
1556 /**	Flag: SNMP check during transfer
1557 	(from pjsnmp-during-transfer in printcap entry).
1558 */
1559 static	int		 check_trans	= 1;
1560 
1561 
1562 /**	Flag: EOF found on standard input.
1563 */
1564 static	int		 have_eof	= 0;
1565 
1566 
1567 /**	Ignore failed SNMP session
1568 	(from pjsnmp-ignore-failed-session in printcap entry).
1569 */
1570 static	int		 snmp_igfs	= 0;
1571 
1572 
1573 /**	Allow printing if accounting connection failed.
1574 	(from pjsnmp-allow-printing-if-accounting-connection-failed).
1575 */
1576 static	int		 acct_apcf	= 0;
1577 
1578 
1579 /**	Flag: Have page counter at start.
1580 */
1581 static	int		 have_pcs	= 0;
1582 
1583 
1584 /**	Flag: Have page counter at end.
1585 */
1586 static	int		 have_pce	= 0;
1587 
1588 
1589 /**	Previous device status.
1590 */
1591 static	int		 odevst		= 0;
1592 
1593 
1594 /**	Current device status.
1595 */
1596 static	int		 devst		= 0;
1597 
1598 
1599 /**	Previous printer status.
1600 */
1601 static	int		 oprist		= 0;
1602 
1603 
1604 /**	Current printer status.
1605 */
1606 static	int		 prist		= 0;
1607 
1608 
1609 /**	Previous summary status.
1610 */
1611 static	int		 ostsum		= PJSNMP_ST_UNKNOWN;
1612 
1613 
1614 /**	Current summary status.
1615 */
1616 static	int		 stsum		= PJSNMP_ST_UNKNOWN;
1617 
1618 
1619 /**	Flag: The printer was seen in printing state.
1620 	This flag is cleared if the printer was seen in error state,
1621 	as some printers go from error to printing via idle.
1622 */
1623 static	int		 seen_printing	= 0;
1624 
1625 
1626 /**	Last header used for log messages.
1627 */
1628 static	int		 last_header	= 0;
1629 
1630 
1631 /**	Decision from permission check
1632 	0=unknown
1633 	1=accept
1634 	2=hold
1635 	3=remove
1636 */
1637 static	int		 decision	= 0;
1638 
1639 
1640 /**	Port number to send data to in host representation
1641 	(from pjsnmp-port in printcap entry).
1642 */
1643 static	unsigned short	 host_port	= 9100;
1644 
1645 
1646 /**	Local port number.
1647 	(from pjsnmp-local-port in printcap entry).
1648 */
1649 static	unsigned short	 local_port	= 0;
1650 
1651 
1652 /**	Accounting port number in host representation
1653 	(from pjsnmp-accounting-port in printcap entry).
1654 */
1655 static	unsigned short	 acct_port	= 9100;
1656 
1657 
1658 #ifdef SIGPIPE
1659 /**	Indicator: SIGPIPE signal received.
1660 */
1661 static
1662 DK4_VOLATILE
1663 dk4_sig_atomic_t	sig_had_pipe	=	0;
1664 #endif
1665 
1666 
1667 /**	Indicator: SIGINT signal received.
1668 */
1669 static
1670 DK4_VOLATILE
1671 dk4_sig_atomic_t	sig_had_int	=	0;
1672 
1673 
1674 /**	Indicator: SIGTERM signal received.
1675 */
1676 static
1677 DK4_VOLATILE
1678 dk4_sig_atomic_t	sig_had_term	=	0;
1679 
1680 
1681 /**	Pass volatile pointer through to caller.
1682 	The CERT C coding standard recommends to set signal indicator
1683 	variables through pointers to avoid
1684 	compilers from optimizing too hard (they might attempt
1685 	to keep the value in a register although properly marked
1686 	as volatile).
1687 	@param	ptr	Address of volatile indicator variable.
1688 	@return	Same pointer as ptr.
1689 */
1690 static
1691 DK4_VOLATILE
1692 dk4_sig_atomic_t *
sig_pass_pointer(DK4_VOLATILE dk4_sig_atomic_t * ptr)1693 sig_pass_pointer(DK4_VOLATILE dk4_sig_atomic_t *ptr)
1694 {
1695   return ptr;
1696 }
1697 
1698 
1699 #ifdef SIGPIPE
1700 /**	Handler for SIGPIPE signal.
1701 	@param	signo	Signal number (always SIGPIPE, ignored).
1702 */
1703 static
1704 void
sig_handler_pipe(int DK4_ARG_UNUSED (signo))1705 sig_handler_pipe(int DK4_ARG_UNUSED(signo) )
1706 {
1707   DK4_UNUSED_ARG(signo)
1708   *sig_pass_pointer(&sig_had_pipe) = 1;
1709 }
1710 #endif
1711 
1712 
1713 /**	Handler for SIGINT signal.
1714 	@param	signo	Signal number (always SIGINT, ignored).
1715 */
1716 static
1717 void
sig_handler_int(int DK4_ARG_UNUSED (signo))1718 sig_handler_int(int DK4_ARG_UNUSED(signo) )
1719 {
1720   DK4_UNUSED_ARG(signo)
1721   *sig_pass_pointer(&sig_had_int) = 1;
1722 }
1723 
1724 
1725 /**	Handler for SIGTERM signal.
1726 	@param	signo	Signal number (always SIGTERM, ignored).
1727 */
1728 static
1729 void
sig_handler_term(int DK4_ARG_UNUSED (signo))1730 sig_handler_term(int DK4_ARG_UNUSED(signo) )
1731 {
1732   DK4_UNUSED_ARG(signo)
1733   *sig_pass_pointer(&sig_had_term) = 1;
1734 }
1735 
1736 
1737 /**	Read value from volatile atomic type.
1738 	This function is necessary as some compilers mis-optimize
1739 	direct access to volatile variables (at least if you believe
1740 	one of the coding standards).
1741 	@param	ap	Pointer to volatile atomic variable.
1742 	@return	Contents of the variable.
1743 */
1744 static
1745 dk4_sig_atomic_t
sig_read_atomic(DK4_VOLATILE dk4_sig_atomic_t * ap)1746 sig_read_atomic(DK4_VOLATILE dk4_sig_atomic_t *ap)
1747 {
1748   return (*ap);
1749 }
1750 
1751 
1752 /**	Check whether we can continue or must abort due to signal.
1753 	@param	dopipe	Flag: Check for SIGPIPE too.
1754 	@return	1 if we can continue, 0 otherwise.
1755 */
1756 static
1757 int
can_continue(int dopipe)1758 can_continue(int dopipe)
1759 {
1760   int		 back	= 1;
1761   if (0 != sig_read_atomic(&sig_had_term)) { back = 0; }
1762   if (0 != sig_read_atomic(&sig_had_int))  { back = 0; }
1763 #ifdef SIGPIPE
1764   if (0 != dopipe) {
1765     if (0 != sig_read_atomic(&sig_had_pipe)) { back = 0; }
1766   }
1767 #endif
1768   return back;
1769 }
1770 
1771 
1772 /**	Log a timestamp.
1773 	@return	1 if time changed since previous log, 0 otherwise.
1774 */
1775 static
1776 int
log_timestamp(void)1777 log_timestamp(void)
1778 {
1779   char			buf[64];
1780   static dk4_time_t	previous_log	= (dk4_time_t)0UL;
1781   dk4_time_t		current;
1782   int			back		= 0;
1783 
1784   dk4time_get(&current);
1785   if (current != previous_log) {
1786     if (dk4time_as_text_c8(buf, sizeof(buf), &current, NULL)) {
1787       back = 1;
1788       fputs(pjsnmp_kw[62], out_file);
1789       fputs(buf, out_file);
1790       fputs(pjsnmp_kw[0], out_file);
1791       previous_log = current;
1792     }
1793   }
1794   return back;
1795 }
1796 
1797 
1798 
1799 /**	Log a 1 component message with header line.
1800 	@param	h	Header line chooser (1, 2 or 3).
1801 	@param	i	Index of message text in pjsnmp_kw.
1802 */
1803 static
1804 void
log_1_with_header(int h,size_t i)1805 log_1_with_header(int h, size_t i)
1806 {
1807   (void)log_timestamp();
1808   if (last_header != h) {
1809     fputs(pjsnmp_kw[62 + h], out_file);
1810     last_header = h;
1811   }
1812   fputs(pjsnmp_kw[i], out_file);
1813   fflush(out_file);
1814 }
1815 
1816 
1817 
1818 /**	Log a 3 components message with header line.
1819 	@param	h	Header line chooser (1, 2 or 3).
1820 	@param	i1	Index of first text component in pjsnmp_kw.
1821 	@param	i2	Index of third text component in pjsnmp_kw.
1822 	@param	s	Second text component (variable text).
1823 */
1824 static
1825 void
log_3_with_header(int n,size_t i1,size_t i2,const char * s)1826 log_3_with_header(int n, size_t i1, size_t i2, const char *s)
1827 {
1828   (void)log_timestamp();
1829   if (last_header != n) {
1830     fputs(pjsnmp_kw[62 + n], out_file);
1831     last_header = n;
1832   }
1833   fputs(pjsnmp_kw[i1], out_file);
1834   if (NULL != s) { fputs(s, out_file); }
1835   fputs(pjsnmp_kw[i2], out_file);
1836   fflush(out_file);
1837 }
1838 
1839 
1840 
1841 /**	Log a 5 components message with header line.
1842 	@param	h	Header line chooser (1, 2 or 3).
1843 	@param	i1	Index of first text component in pjsnmp_kw.
1844 	@param	i2	Index of third text component in pjsnmp_kw.
1845 	@param	i3	Index of fifth text component in pjsnmp_kw.
1846 	@param	s1	Second text component (variable text).
1847 	@param	s2	Fourth text component (variable text).
1848 */
1849 static
1850 void
log_5_with_header(int n,size_t i1,size_t i2,size_t i3,const char * s1,const char * s2)1851 log_5_with_header(
1852   int		n,
1853   size_t	i1,
1854   size_t	i2,
1855   size_t	i3,
1856   const char	*s1,
1857   const char	*s2
1858 )
1859 {
1860   (void)log_timestamp();
1861   if (last_header != n) {
1862     fputs(pjsnmp_kw[62 + n], out_file);
1863     last_header = n;
1864   }
1865   fputs(pjsnmp_kw[i1], out_file);
1866   if (NULL != s1) { fputs(s1, out_file); }
1867   fputs(pjsnmp_kw[i2], out_file);
1868   if (NULL != s2) { fputs(s2, out_file); }
1869   fputs(pjsnmp_kw[i3], out_file);
1870   fflush(out_file);
1871 }
1872 
1873 
1874 
1875 /**	Log a 1 component message without header line.
1876 	@param	i	Index of text component in pjsnmp_kw.
1877 */
1878 static
1879 void
log_1_no_header(size_t i)1880 log_1_no_header(size_t i)
1881 {
1882 
1883   log_timestamp();
1884   fputs(pjsnmp_kw[i], out_file);
1885   fflush(out_file);
1886 
1887 }
1888 
1889 
1890 
1891 /**	Log a 3 components message without header line.
1892 	@param	i1	Index of first text component in pjsnmp_kw.
1893 	@param	i2	Index of third text component in pjsnmp_kw.
1894 	@param	s	Second text component (variable text).
1895 */
1896 static
1897 void
log_3_no_header(size_t i1,size_t i2,const char * s)1898 log_3_no_header(size_t i1, size_t i2, const char *s)
1899 {
1900 
1901   log_timestamp();
1902   fputs(pjsnmp_kw[i1], out_file);
1903   if (NULL != s) { fputs(s, out_file); }
1904   fputs(pjsnmp_kw[i2], out_file);
1905   fflush(out_file);
1906 
1907 }
1908 
1909 
1910 
1911 /**	Log a 5 components message without header line.
1912 	@param	i1	Index of first text component in pjsnmp_kw.
1913 	@param	i2	Index of third text component in pjsnmp_kw.
1914 	@param	i3	Index of fifth text component in pjsnmp_kw.
1915 	@param	s1	Second text component (variable text).
1916 	@param	s2	Fourth text component (variable text).
1917 */
1918 static
1919 void
log_5_no_header(size_t i1,size_t i2,size_t i3,const char * s1,const char * s2)1920 log_5_no_header(
1921   size_t	i1,
1922   size_t	i2,
1923   size_t	i3,
1924   const char	*s1,
1925   const char 	*s2
1926 )
1927 {
1928   log_timestamp();
1929   fputs(pjsnmp_kw[i1], out_file);
1930   if (NULL != s1) { fputs(s1, out_file); }
1931   fputs(pjsnmp_kw[i2], out_file);
1932   if (NULL != s2) { fputs(s2, out_file); }
1933   fputs(pjsnmp_kw[i3], out_file);
1934   fflush(out_file);
1935 }
1936 
1937 
1938 
1939 /**	Log a 1 component message related to model file.
1940 	@param	lineno	Line number in model file to complain about.
1941 	@param	i	Index of first text component in pjsnmp_kw.
1942 */
1943 static
1944 void
log_model_1(dk4_um_t lineno,size_t i)1945 log_model_1(dk4_um_t lineno, size_t i)
1946 {
1947   char		 buf[8*sizeof(dk4_um_t)];
1948   const char	*fn;
1949   const char	*ptr;
1950   int		 res;
1951 
1952   (void)log_timestamp();
1953   if (3 != last_header) {
1954     last_header = 3;
1955     fputs(pjsnmp_kw[65], out_file);
1956   }
1957   if ((dk4_um_t)0UL < lineno) {
1958     res = dk4ma_write_c8_decimal_unsigned(buf, sizeof(buf), lineno, 0, NULL);
1959     if (0 != res) {
1960       fn = ((NULL != model_file) ? model_file : def_model_file);
1961       ptr = dk4str8_rchr(fn, '/');
1962       if (NULL != ptr) {
1963         ptr++;
1964       } else {
1965         ptr = fn;
1966       }
1967       fputs(ptr, out_file);
1968       fputs(pjsnmp_kw[143], out_file);
1969       fputs(buf, out_file);
1970       fputs(pjsnmp_kw[143], out_file);
1971       fputs(pjsnmp_kw[1], out_file);
1972     }
1973   }
1974   fputs(pjsnmp_kw[i], out_file);
1975   fflush(out_file);
1976 }
1977 
1978 
1979 
1980 /**	Log a 3 components message related to model file.
1981 	@param	lineno	Line number in model file to complain about.
1982 	@param	i1	Index of first text component in pjsnmp_kw.
1983 	@param	i2	Index of third text component in pjsnmp_kw.
1984 	@param	s	Second text component (variable text).
1985 */
1986 static
1987 void
log_model_3(dk4_um_t lineno,size_t i1,size_t i2,const char * s)1988 log_model_3(
1989   dk4_um_t	lineno,
1990   size_t	i1,
1991   size_t	i2,
1992   const char	*s
1993 )
1994 {
1995   char		 buf[8*sizeof(dk4_um_t)];
1996   const char	*fn;
1997   const char	*ptr;
1998   int		 res;
1999 
2000   (void)log_timestamp();
2001   if (3 != last_header) {
2002     last_header = 3;
2003     fputs(pjsnmp_kw[65], out_file);
2004   }
2005   if ((dk4_um_t)0UL < lineno) {
2006     res = dk4ma_write_c8_decimal_unsigned(buf, sizeof(buf), lineno, 0, NULL);
2007     if (0 != res) {
2008       fn = ((NULL != model_file) ? model_file : def_model_file);
2009       ptr = dk4str8_rchr(fn, '/');
2010       if (NULL != ptr) {
2011         ptr++;
2012       } else {
2013         ptr = fn;
2014       }
2015       fputs(ptr, out_file);
2016       fputs(pjsnmp_kw[143], out_file);
2017       fputs(buf, out_file);
2018       fputs(pjsnmp_kw[143], out_file);
2019       fputs(pjsnmp_kw[1], out_file);
2020     }
2021   }
2022   fputs(pjsnmp_kw[i1], out_file);
2023   if (NULL != s) { fputs(s, out_file); }
2024   fputs(pjsnmp_kw[i2], out_file);
2025   fflush(out_file);
2026 }
2027 
2028 
2029 
2030 /**	Create new status text node.
2031 	@param	t	Text, not 0-terminated.
2032 	@param	tsz	Text size.
2033 	@param	st	Summary state if text is found.
2034 	@param	fl	Flag: This is the start text only.
2035 	@return	Valid pointer on success, NULL on error.
2036 */
2037 static
2038 status_text_t *
stt_new(const unsigned char * t,size_t tsz,int st,int fl)2039 stt_new(
2040   const unsigned char	*t,
2041   size_t		 tsz,
2042   int			 st,
2043   int			 fl
2044 )
2045 {
2046   status_text_t		*back	= NULL;
2047 
2048   if ((NULL != t) && (0 < tsz)) {
2049     back = dk4mem_new(status_text_t,1,NULL);
2050     if (NULL != back) {
2051       DK4_MEMRES(back, sizeof(status_text_t));
2052       back->start = fl;
2053       back->state = st;
2054       back->size  = tsz;
2055       back->text  = dk4mem_new(unsigned char,tsz,NULL);
2056       if (NULL != back->text) {
2057         DK4_MEMCPY(back->text, t, tsz);
2058       } else {
2059         dk4mem_free(back);
2060 	back = NULL;
2061       }
2062     }
2063 #if TRACE_DEBUG
2064     else {
2065     }
2066 #endif
2067   }
2068 #if TRACE_DEBUG
2069   else {
2070   }
2071 #endif
2072 
2073   return back;
2074 }
2075 
2076 
2077 
2078 /**	Destroy status text node, release memory.
2079 	@param	ptr	Node to destroy.
2080 */
2081 static
2082 void
stt_delete(status_text_t * ptr)2083 stt_delete(status_text_t *ptr)
2084 {
2085 
2086   if (NULL != ptr) {
2087     dk4mem_release(ptr->text);
2088     dk4mem_free(ptr);
2089   }
2090 
2091 }
2092 
2093 
2094 
2095 /**	Compare two status text nodes.
2096 	While building the storage the start flag is ignored.
2097 	When searching a text for a status text received via SNMP
2098 	we have to consider the flag.
2099 	@param	l	Left object.
2100 	@param	r	Right object.
2101 	@param	cr	Comparison criteria (0=build storage, 1=search).
2102 	@return	Comparison result.
2103 */
2104 static
2105 int
stt_compare(const void * l,const void * r,int cr)2106 stt_compare(const void *l, const void *r, int cr)
2107 {
2108   const	status_text_t	*pl;		/* Left operand */
2109   const	status_text_t	*pr;		/* Right operand */
2110   size_t		 min;		/* Minimum of both text sizes */
2111   int		 	 back	= 0;
2112 
2113   if (NULL != l) {
2114     if (NULL != r) {
2115       pl = (const status_text_t *)l;
2116       pr = (const status_text_t *)r;
2117       min = pl->size;
2118       if (min > pr->size) { min = pr->size; }
2119       if (0 < min) {
2120         back = dk4mem_cmp(pl->text, pr->text, min, NULL);
2121       }
2122       if (0 == back) {
2123         if ((0 == cr) || (0 == pl->start)) {
2124 	  if (pl->size > pr->size) {
2125 	    back = 1;
2126 	  } else {
2127 	    if (pl->size < pr->size) {
2128 	      back = -1;
2129 	    }
2130 	  }
2131 	}
2132       }
2133     } else {
2134       back = 1;
2135     }
2136   } else {
2137     if (NULL != r) {
2138       back = -1;
2139     }
2140   }
2141 
2142   return back;
2143 }
2144 
2145 
2146 
2147 /**	Set one command line option.
2148 	@param	Option character.
2149 	@param	Option argument.
2150 */
2151 static
2152 void
set_option(char c,char * val)2153 set_option(char c, char *val)
2154 {
2155   size_t	sz	= 0;		/* Index of option in arguments array */
2156 
2157   if (NULL != val) {
2158     if (('a' <= c) && ('z' >= c)) {
2159       sz = (size_t)(c - 'a');
2160       if (DK4_SIZEOF(lower,DK4_PCHAR) > sz) {
2161         lower[sz] = val;
2162       }
2163     } else {
2164       if (('A' <= c) && ('Z' >= c)) {
2165         sz = (size_t)(c - 'A');
2166 	if (DK4_SIZEOF(upper,DK4_PCHAR) > sz) {
2167 	  upper[sz] = val;
2168 	}
2169       }
2170     }
2171   }
2172 }
2173 
2174 
2175 
2176 /**	Retrieve argument for one option.
2177 	@param	c	Option character (option name).
2178 	@return	The value provided as option argument, NULL otherwise.
2179 */
2180 static
2181 char *
get_option(char c)2182 get_option(char c)
2183 {
2184   char		*back	= NULL;
2185   size_t	 sz	= 0;		/* Index of option in arguments array */
2186 
2187   if (('a' <= c) && ('z' >= c)) {
2188     sz = (size_t)(c - 'a');
2189     if (DK4_SIZEOF(lower,DK4_PCHAR) > sz) {
2190       back = lower[sz];
2191     }
2192   } else {
2193     if (('A' <= c) && ('Z' >= c)) {
2194       sz = (size_t)(c - 'A');
2195       if (DK4_SIZEOF(upper,DK4_PCHAR) > sz) {
2196         back = upper[sz];
2197       }
2198     }
2199   }
2200   return back;
2201 }
2202 
2203 
2204 
2205 /**	Process command line arguments.
2206 	@param	argc	Number of command line arguments.
2207 	@param	argv	Command line arguments array.
2208 	@return	1 on success, 0 on error.
2209 */
2210 static
2211 int
process_command_line_arguments(int argc,char * argv[])2212 process_command_line_arguments(int argc, char *argv[])
2213 {
2214   char		*curarg;	/* Current argument to process */
2215   char		*s_name;	/* Status file name */
2216   size_t	 szjnb;		/* Size of job name buffer */
2217   int		 back	= 1;
2218   int		 i;		/* Index of current argument */
2219   int		 res;		/* Result for number to text conversion */
2220   char		 c;		/* Option name */
2221 
2222   for (i = 1; i < argc; i++) {
2223     curarg = argv[i];
2224     if ('-' == *curarg) {
2225       curarg++;
2226       if ('\0' != *curarg) {
2227         c = *(curarg++);
2228 	if ('\0' != *curarg) {
2229 	  set_option(c, curarg);
2230 	} else {
2231 #if VERSION_BEFORE_20160208
2232 	  /*	-c may appear without an argument.
2233 	  */
2234 	  back = 0;
2235 	  /* ERROR: Missing option argument */
2236 	  log_1_with_header(1, 67);
2237 #else
2238 	  set_option(c, (char *)(pjsnmp_kw[144]));
2239 #endif
2240 	}
2241       } else {
2242         back = 0;
2243         /* ERROR: Only minus */
2244 	log_1_with_header(1, 66);
2245       }
2246     } else {
2247 #if 0
2248       /*	2016-02-15	Seeing non-option arguments is not an error,
2249       				the accounting file name is passed once
2250 				as argument to -a and once as file name.
2251       */
2252       back = 0;
2253       /* ERROR: Non-option argument found */
2254       log_1_with_header(1, 68);
2255 #endif
2256     }
2257   }
2258   if (0 != back) {
2259     s_name = get_option('s');
2260     if (NULL != s_name) {
2261       stt_file = fopen(s_name, "w");
2262       if (NULL != stt_file) {
2263         out_file = stt_file;
2264       }
2265 #if TRACE_DEBUG
2266       else {
2267       }
2268 #endif
2269     }
2270 #if TRACE_DEBUG
2271     else {
2272     }
2273 #endif
2274     user_name = get_option('n');
2275     if (NULL == user_name) user_name = get_option('L');
2276     if (NULL != user_name) {
2277       user_name = dk4str8_start(user_name, NULL);
2278     }
2279     if (NULL != user_name) {
2280       (void)dk4str8_next(user_name, NULL);
2281       if (0 == strlen(user_name)) { user_name = NULL; }
2282     }
2283     if (NULL == user_name) {
2284       /* ERROR: No user name */
2285       log_1_with_header(1, 69);
2286       back = 0;
2287     }
2288 #if TRACE_DEBUG
2289     else {
2290     }
2291 #endif
2292     if (0 != back) {
2293       queue_name = get_option('P');
2294       if (NULL == queue_name) queue_name = get_option('Q');
2295       if (NULL != queue_name) {
2296         queue_name = dk4str8_start(queue_name, NULL);
2297       }
2298       if (NULL != queue_name) {
2299         (void)dk4str8_next(queue_name, NULL);
2300 	if (0 == strlen(queue_name)) { queue_name = NULL; }
2301       }
2302       if (NULL == queue_name) {
2303         /* ERROR: No queue name */
2304 	log_1_with_header(1, 70);
2305 	back = 0;
2306       }
2307 #if TRACE_DEBUG
2308       else {
2309       }
2310 #endif
2311     }
2312     if (0 != back) {
2313       job_name = get_option('A');
2314       if (NULL == job_name) job_name = get_option('j');
2315       if (NULL == job_name) job_name = get_option('t');
2316       if (NULL == job_name) job_name = get_option('D');
2317       if (NULL != job_name) {
2318         job_name = dk4str8_start(job_name, NULL);
2319       }
2320       if (NULL != job_name) {
2321         (void)dk4str8_next(job_name, NULL);
2322         if (0 == strlen(job_name)) { job_name = NULL; }
2323       }
2324       if (NULL == job_name) {
2325         szjnb = sizeof(job_name_buf);
2326         if (0 != dk4str8_cpy_s(job_name_buf, szjnb, pjsnmp_kw[171], NULL)) {
2327 	  res = dk4ma_write_c8_decimal_unsigned(
2328 	    &(job_name_buf[strlen(job_name_buf)]),
2329 	    (szjnb - strlen(job_name_buf)), (dk4_um_t)getpid(), 0, NULL
2330 	  );
2331 	  if (0 != res) {
2332 	    job_name = job_name_buf;
2333 	  }
2334 	}
2335       }
2336       if (NULL == job_name) {
2337         /* ERROR: No job name */
2338 	log_1_with_header(1, 71);
2339         back = 0;
2340       }
2341 #if TRACE_DEBUG
2342       else {
2343       }
2344 #endif
2345     }
2346     if (0 != back) {
2347       job_title = get_option('J');
2348       if (NULL == job_title) job_title = get_option('f');
2349       if (NULL == job_title) job_title = get_option('N');
2350       if (NULL != job_title) {
2351         job_title = dk4str8_start(job_title, NULL);
2352       }
2353       if (NULL != job_title) {
2354         dk4str8_normalize(job_title, NULL);
2355       }
2356 #if 0
2357       /*	20160206
2358 		Allow job_title to be NULL, pjsnmp_kw[54] is used instead.
2359       */
2360       if (NULL == job_title) {
2361         back = 0;
2362       }
2363 #endif
2364 #if TRACE_DEBUG
2365       else {
2366       }
2367 #endif
2368     }
2369   }
2370 
2371   return back;
2372 }
2373 
2374 
2375 
2376 /**	Set string pointer.
2377 	@param	dptr	Address of pointer to set.
2378 	@param	src	Value.
2379 	@param	name	Configuration entry name.
2380 	@return	1 on success, 0 on error.
2381 */
2382 static
2383 int
set_string(char ** dptr,char * src,const char * name)2384 set_string(char **dptr, char *src, const char *name)
2385 {
2386   int		 back	= 0;
2387 
2388   if (NULL != src) {
2389     src = dk4str8_start(src, NULL);
2390     if (NULL != src) {
2391       if (NULL != *dptr) {
2392         /* WARNING: Redefinition */
2393 	log_5_with_header(2, 72, 73, 74, name, src);
2394       }
2395       *dptr = src;
2396       back = 1;
2397     } else {
2398       /* ERROR: Empty text */
2399       log_3_with_header(2, 75, 76, name);
2400     }
2401   } else {
2402     /* ERROR: Text string required */
2403     log_3_with_header(2, 77, 78, name);
2404   }
2405   return back;
2406 }
2407 
2408 
2409 
2410 /**	Set unsigned short variable.
2411 	@param	dptr	Address of variable to set.
2412 	@param	src	Text containing the value.
2413 	@return	1 on success, 0 on error.
2414 */
2415 static
2416 int
set_unsigned_short(unsigned short * dptr,char * src,const char * name)2417 set_unsigned_short(unsigned short *dptr, char *src, const char *name)
2418 {
2419   const char	*ep	= NULL;		/* First unprocessabe char */
2420   int		 back	= 0;
2421   int		 res;			/* Operation result */
2422   unsigned short us;
2423 
2424   if (NULL != src) {
2425     src = dk4str8_start(src, NULL);
2426     if (NULL != src) {
2427       res = dk4ma_input_c8_dec_ushort(&us, src, &ep, 1, NULL);
2428       if (0 != res) {
2429         *dptr = us;
2430 	back = 1;
2431       } else {
2432         /* ERROR: Not a number! */
2433 	log_5_with_header(2, 79, 80, 81, name, src);
2434       }
2435     } else {
2436       /* ERROR: Empty text */
2437       log_3_with_header(2, 75, 76, name);
2438     }
2439   } else {
2440     /* ERROR: Numeric value required */
2441     log_3_with_header(2, 77, 78, name);
2442   }
2443   return back;
2444 }
2445 
2446 
2447 
2448 /**	Set SNMP version.
2449 	@param	dptr	Address of variable to set.
2450 	@param	src	Text containing the SNMP version.
2451 	@return	1 on success, 0 on error.
2452 */
2453 static
2454 int
set_snmp_version(long * dptr,char * src)2455 set_snmp_version(long *dptr, char *src)
2456 {
2457   int		 back	= 0;
2458 
2459   if (NULL != src) {
2460     src = dk4str8_start(src, NULL);
2461     if (NULL != src) {
2462       switch (dk4str8_array_index(snmp_version_names, src, 0)) {
2463         case 0: {
2464 	  *dptr = SNMP_VERSION_1;
2465 	  back = 1;
2466 	} break;
2467 	case 1: case 2: {
2468 	  *dptr = SNMP_VERSION_2c;
2469 	  back = 1;
2470 	} break;
2471 	case 3: {
2472 	  *dptr = SNMP_VERSION_3;
2473 	  back = 1;
2474 	} break;
2475 	default: {
2476 	  /* ERROR: Illegal SNMP version */
2477 	  log_3_with_header(2, 82, 83, src);
2478 	} break;
2479       }
2480     } else {
2481       /* ERROR: Empty text */
2482       log_3_with_header(2, 75, 76, printcap_entry_names[9]);
2483     }
2484   } else {
2485     /* ERROR: Value required */
2486     log_3_with_header(2, 77, 78, printcap_entry_names[9]);
2487   }
2488 
2489   return back;
2490 }
2491 
2492 
2493 
2494 /**	Set maximum unsigned integer variable from text.
2495 	@param	dptr	Address of destination variable.
2496 	@param	src	Text containing the value.
2497 	@param	name	Setting name for diagnostics.
2498 	@return	1 on success, 0 on error.
2499 */
2500 static
2501 int
set_umax(dk4_um_t * dptr,char * src,const char * name)2502 set_umax(dk4_um_t *dptr, char *src, const char *name)
2503 {
2504   const char	*ep	= NULL;		/* First unprocessable character */
2505   dk4_um_t	 i	= 0UL;		/* Result value */
2506   int		 back	= 0;
2507   int		 res;			/* Operation result */
2508 
2509   if (NULL != src) {
2510     res = dk4ma_input_c8_dec_dk4_um_t(&i, src, &ep, 1, NULL);
2511     if (0 != res) {
2512       *dptr = i;
2513       back = 1;
2514     } else {
2515       /* ERROR: Not a numeric value */
2516       log_5_with_header(2, 84, 161, 86, name, src);
2517     }
2518   } else {
2519     /* ERROR: Value required */
2520     log_3_with_header(2, 77, 78, name);
2521   }
2522   return back;
2523 }
2524 
2525 
2526 
2527 #if 0
2528 
2529 /**	Set integer variable from text.
2530 	@param	dptr	Address of destination variable.
2531 	@param	src	Text containing the value.
2532 	@param	name	Setting name for diagnostics.
2533 	@return	1 on success, 0 on error.
2534 */
2535 static
2536 int
2537 set_integer(int *dptr, char *src, const char *name)
2538 {
2539   const char	*ep	= NULL;		/* First unprocessable character */
2540   int		 i	= 0;		/* Result value */
2541   int		 back	= 0;
2542   int		 res;			/* Operation result */
2543 
2544   if (NULL != src) {
2545     res = dk4ma_input_c8_dec_int(&i, src, &ep, 1, NULL);
2546     if (0 != res) {
2547       *dptr = i;
2548       back = 1;
2549     } else {
2550       /* ERROR: Not a numeric value */
2551       log_5_with_header(2, 84, 85, 86, name, src);
2552     }
2553   } else {
2554     /* ERROR: Value required */
2555     log_3_with_header(2, 77, 78, name);
2556   }
2557   return back;
2558 }
2559 
2560 #endif
2561 
2562 
2563 
2564 /**	Process one configuration item from a printcap entry.
2565 	@param	ci	Item to process.
2566 	@return	1 on success, 0 on error.
2567 */
2568 static
2569 int
process_one_config_item(char * ci)2570 process_one_config_item(char *ci)
2571 {
2572   char		*value	= NULL;		/* Value for config item */
2573   int		 btrue	= 1;		/* Condition */
2574   int		 back	= 1;
2575 
2576   value = dk4str8_chr(ci, '=');
2577   if (NULL != value) {
2578     *(value++) = '\0';
2579     value = dk4str8_start(value, NULL);
2580   } else {
2581     value = dk4str8_chr(ci, '@');
2582     if (NULL != value) {
2583       *value = '\0';
2584       btrue = 0;
2585     }
2586 #if TRACE_DEBUG
2587     else {
2588     }
2589 #endif
2590   }
2591   switch (dk4str8_array_index(printcap_entry_names, ci, 0)) {
2592     case 0: {
2593       if (0 == set_string(&host_name, value, printcap_entry_names[0])) {
2594         back = 0;
2595       }
2596     } break;
2597     case 1: {
2598       if (0 == set_unsigned_short(&host_port, value, printcap_entry_names[1])) {
2599         back = 0;
2600       }
2601     } break;
2602     case 2: {
2603       host_ordr = btrue;
2604     } break;
2605     case 3: {
2606       acct_enab = btrue;
2607     } break;
2608     case 4: {
2609       acct_achk = btrue;
2610     } break;
2611     case 5: {
2612       if (0 == set_string(&acct_name, value, printcap_entry_names[5])) {
2613         back = 0;
2614       }
2615     } break;
2616     case 6: {
2617       if (0 == set_string(&acct_host, value, printcap_entry_names[6])) {
2618         back = 0;
2619       }
2620     } break;
2621     case 7: {
2622       if (0 == set_unsigned_short(&acct_port, value, printcap_entry_names[7])) {
2623         back = 0;
2624       }
2625     } break;
2626     case 8: {
2627       if (NULL != value) {
2628         if (0 == set_umax(&print_timeout, value, printcap_entry_names[8])) {
2629           back = 0;
2630         }
2631       } else {
2632         if (0 == btrue) { print_timeout = (dk4_um_t)0UL; }
2633 	else { back = 0; }
2634       }
2635     } break;
2636     case 9: {
2637       if (0 == set_snmp_version(&snmp_version, value)) {
2638         back = 0;
2639       }
2640     } break;
2641     case 10: {
2642       if (0 == set_string(&snmp_comm, value, printcap_entry_names[10])) {
2643         back = 0;
2644       }
2645     } break;
2646     case 11: {
2647       check_trans = btrue;
2648     } break;
2649     case 12: {
2650       if (0 == set_string(&model_file, value, printcap_entry_names[12])) {
2651         back = 0;
2652       }
2653     } break;
2654     case 13: {
2655       if (0 == set_string(&model_name, value, printcap_entry_names[13])) {
2656         back = 0;
2657       }
2658     } break;
2659     case 14: {
2660       snmp_igfs = btrue;
2661     } break;
2662     case 15: {
2663       acct_apcf = btrue;
2664     } break;
2665     case 16: {
2666       pdes_always = btrue;
2667     } break;
2668     case 17: {
2669       unkn_busy = btrue;
2670     } break;
2671     case 18: {
2672       if (NULL != value) {
2673         if (0 == set_umax(&unto_start, value, printcap_entry_names[18])) {
2674           back = 0;
2675         }
2676       } else {
2677         if (0 == btrue) { unto_start = (dk4_um_t)0UL; }
2678 	else { back = 0; }
2679       }
2680     } break;
2681     case 19: {
2682       if (NULL != value) {
2683         if (0 == set_umax(&unto_end, value, printcap_entry_names[19])) {
2684           back = 0;
2685         }
2686       } else {
2687         if (0 == btrue) { unto_end = (dk4_um_t)0UL; }
2688 	else { back = 0; }
2689       }
2690     } break;
2691     case 20: {
2692       if (NULL != value) {
2693         if (0 == set_umax(&unto_print, value, printcap_entry_names[20])) {
2694           back = 0;
2695         }
2696       } else {
2697         if (0 == btrue) { unto_print = (dk4_um_t)0UL; }
2698 	else { back = 0; }
2699       }
2700     } break;
2701     case 21: {
2702       if (0 == set_unsigned_short(&local_port, value, printcap_entry_names[21]))
2703       {
2704         back = 0;
2705       }
2706     } break;
2707     case 22: {
2708       if (NULL != value) {
2709         if (0 == set_umax(&unwt_print, value, printcap_entry_names[22])) {
2710 	  back = 0;
2711 	}
2712       } else {
2713         if (0 == btrue) { unwt_print = (dk4_um_t)0UL; }
2714 	else {
2715 	  back = 0;
2716 	}
2717       }
2718     } break;
2719     case 23: {
2720       read_responses = btrue;
2721     } break;
2722     case 24: {
2723       force_printable_status_text = btrue;
2724     } break;
2725     case 25: {
2726       if (NULL != value) {
2727         if (0 == set_umax(&erto_start, value, printcap_entry_names[22])) {
2728 	  back = 0;
2729 	}
2730       } else {
2731         if (0 == btrue) { erto_start = (dk4_um_t)0UL; }
2732 	else {
2733 	  back = 0;
2734 	}
2735       }
2736     } break;
2737     case 26: {
2738       if (NULL != value) {
2739         if (0 == set_umax(&erto_end, value, printcap_entry_names[22])) {
2740 	  back = 0;
2741 	}
2742       } else {
2743         if (0 == btrue) { erto_end = (dk4_um_t)0UL; }
2744 	else {
2745 	  back = 0;
2746 	}
2747       }
2748     } break;
2749     case 27: {
2750       if (NULL != value) {
2751         if (0 == set_umax(&erto_print, value, printcap_entry_names[22])) {
2752 	  back = 0;
2753 	}
2754       } else {
2755         if (0 == btrue) { erto_print = (dk4_um_t)0UL; }
2756 	else {
2757 	  back = 0;
2758 	}
2759       }
2760     } break;
2761     case 28: {
2762       verbose = btrue;
2763     } break;
2764     case 29: {
2765       allow_non_ascii = btrue;
2766     } break;
2767     case 30: {
2768       acct_start_end = btrue;
2769     } break;
2770   }
2771   return back;
2772 }
2773 
2774 
2775 
2776 /**	Check whether the line opens the model we are searching for.
2777 	@param	str	Text to check.
2778 	@return	1 on success, 0 on error.
2779 */
2780 static
2781 int
check_in_model(char * str,dk4_um_t lineno)2782 check_in_model(char *str, dk4_um_t lineno)
2783 {
2784   char		*ptr;		/* Closing square bracket */
2785   int		 back	= 0;
2786 
2787   str = dk4str8_start(str, NULL);
2788   if (NULL != str) {
2789     ptr = dk4str8_chr(str, ']');
2790     if (NULL != ptr) {
2791       *ptr = '\0';
2792       dk4str8_normalize(str, NULL);
2793       if (0 == strcmp(str, model_name)) {
2794         back = 1;
2795       }
2796 #if TRACE_DEBUG
2797       else {
2798       }
2799 #endif
2800     } else {
2801       /* ERROR: Syntax */
2802       log_model_1(lineno, 87);
2803     }
2804   } else {
2805     /* ERROR: Syntax */
2806     log_model_1(lineno, 88);
2807   }
2808   return back;
2809 }
2810 
2811 
2812 
2813 /**	Overwrite one mapping from device/printer status to summary state.
2814 	@param	devst	Device status.
2815 	@param	prst	Printer status.
2816 	@param	sujmst	Summary state resulting from device and printer status.
2817 */
2818 static
2819 void
set_state_mapping(int devst,int prst,int sumst)2820 set_state_mapping(int devst, int prst, int sumst)
2821 {
2822 
2823   if ((0 < devst) && (6 > devst)) {
2824     if ((0 < prst) && (6 > prst)) {
2825       summary_states[5 * devst + prst - 6] = sumst;
2826     }
2827 #if TRACE_DEBUG
2828     else {
2829     }
2830 #endif
2831   }
2832 #if TRACE_DEBUG
2833   else {
2834   }
2835 #endif
2836 
2837 }
2838 
2839 
2840 
2841 /**	Map device and printer status to summary state.
2842 	@param	devst	Device status.
2843 	@param	prst	Printer status.
2844 	@return	Summary state.
2845 */
2846 static
2847 int
get_state_mapping(int devst,int prst)2848 get_state_mapping(int devst, int prst)
2849 {
2850   int		 back	= PJSNMP_ST_UNKNOWN;
2851 
2852   if ((0 < devst) && (6 > devst)) {
2853     if ((0 < prst) && (6 > prst)) {
2854       back = summary_states[5 * devst + prst - 6];
2855 
2856     }
2857 #if TRACE_DEBUG
2858     else {
2859     }
2860 #endif
2861   }
2862 #if TRACE_DEBUG
2863   else {
2864   }
2865 #endif
2866 
2867   return back;
2868 }
2869 
2870 
2871 
2872 /**	Add a state mapping.
2873 	@param	str	Mapping text.
2874 	@param	lineno	Line number (for diagnostics).
2875 	@return	1 on success, 0 on error.
2876 */
2877 static
2878 int
model_conf_map(char * str,dk4_um_t lineno)2879 model_conf_map(char *str, dk4_um_t lineno)
2880 {
2881   char		*psummary;	/* Summary state name */
2882   char		*ppr;		/* Printer status */
2883   int		 stsum;		/* Summary state */
2884   int		 stdev;		/* Device status */
2885   int		 stpri;		/* Printer status */
2886   int		 back		= 0;
2887 
2888   psummary = dk4str8_next(str, NULL);
2889   if (NULL != psummary) {
2890     ppr = dk4str8_chr(str, '/');
2891     if (NULL != ppr) {
2892       *(ppr++) = '\0';
2893       ppr = dk4str8_start(ppr, NULL);
2894       if (NULL != ppr) {
2895         back = 1;
2896         switch (dk4str8_abbr_index(summary_state_names, '$', psummary, 0)) {
2897 	  case 0: {
2898 	    stsum = PJSNMP_ST_UNKNOWN;
2899 	  } break;
2900 	  case 1: {
2901 	    stsum = PJSNMP_ST_ERROR;
2902 	  } break;
2903 	  case 2: {
2904 	    stsum = PJSNMP_ST_BUSY;
2905 	  } break;
2906 	  case 3: {
2907 	    stsum = PJSNMP_ST_IDLE;
2908 	  } break;
2909 	  case 4: {
2910 	    stsum = PJSNMP_ST_WARMUP;
2911 	  } break;
2912 	  case 5: {
2913 	    stsum = PJSNMP_ST_STANDBY;
2914 	  } break;
2915 	  default: {
2916 	    back = 0;
2917 	    /* ERROR: Illegal summary state */
2918 	    log_model_3(lineno, 89, 90, psummary);
2919 	  } break;
2920 	}
2921 	if (0 != back) {
2922 	  if (0 == strcmp(str, pjsnmp_kw[3])) {
2923 	    if (0 == strcmp(ppr, pjsnmp_kw[3])) {
2924 	      for (stdev = 1; stdev < 6; stdev++) {
2925 	        for (stpri = 1; stpri < 6; stpri++) {
2926 		  set_state_mapping(stdev, stpri, stsum);
2927 		}
2928 	      }
2929 	    } else {
2930 	      stpri = dk4str8_abbr_index(printer_status_names, '$', ppr, 0);
2931 	      if (-1 < stpri) {
2932 	        stpri++;
2933 		for (stdev = 1; stdev < 6; stdev++) {
2934 		  set_state_mapping(stdev, stpri, stsum);
2935 		}
2936 	      } else {
2937 	        back = 0;
2938 		/* ERROR: Syntax, illegal printer status name */
2939 		log_model_3(lineno, 91, 92, ppr);
2940 	      }
2941 	    }
2942 	  } else {
2943 	    stdev = dk4str8_abbr_index(device_status_names, '$', str, 0);
2944 	    if (-1 < stdev) {
2945 	      stdev++;
2946 	      if (0 == strcmp(ppr, pjsnmp_kw[3])) {
2947 	        for (stpri = 1; stpri < 6; stpri++) {
2948 		  set_state_mapping(stdev, stpri, stsum);
2949 		}
2950 	      } else {
2951 	        stpri = dk4str8_abbr_index(printer_status_names, '$', ppr, 0);
2952 		if (-1 < stpri) {
2953 		  stpri++;
2954 		  set_state_mapping(stdev, stpri, stsum);
2955 		} else {
2956 		  back = 0;
2957 		  /* ERROR: Syntax, illegal printer status name */
2958 		  log_model_3(lineno, 91, 92, ppr);
2959 		}
2960 	      }
2961 	    } else {
2962 	      back = 0;
2963 	      /* ERROR: Syntax, illegal device status name */
2964 	      log_model_3(lineno, 93, 94, ppr);
2965 	    }
2966 	  }
2967 	} else {
2968 	}
2969       } else {
2970         /* ERROR: Syntax, printer status missing */
2971 	log_model_1(lineno, 95);
2972       }
2973     } else {
2974       /* ERROR: Syntax, printer status missing */
2975       log_model_1(lineno, 95);
2976     }
2977   } else {
2978     /* ERROR: Syntax, summary state missing */
2979     log_model_1(lineno, 96);
2980   }
2981   return back;
2982 }
2983 
2984 
2985 
2986 /**	Add a condition to the error conditions list.
2987 	@param	str	Text for condition.
2988 	@param	addcond	Flag: Add to existing list, do not reset.
2989 	@param	lineno	Line number (for diagnostics).
2990 	@return	1 on success, 0 on error.
2991 */
2992 static
2993 int
model_conf_error_condition(char * str,int addcond,dk4_um_t lineno)2994 model_conf_error_condition(char *str, int addcond, dk4_um_t lineno)
2995 {
2996   unsigned long	cond;		/* Used to build condition bit */
2997   int		i;		/* Index of keyword in condition_names */
2998   int		back	= 0;
2999 
3000   if ((0 == addcond) && (0 == pdes_reset)) {
3001     pdes_error = 0UL;
3002   }
3003   pdes_reset = 1;
3004   dk4str8_normalize(str, NULL);
3005   i = dk4str8_array_index(condition_names, str, 0);
3006   if (-1 < i) {
3007     back = 1;
3008     cond = 0x80000000UL;
3009     while (0 < i--) { cond = cond / 2UL; }
3010     pdes_error |= cond;
3011   } else {
3012     /* ERROR: Syntax, illegal condition name */
3013     log_model_3(lineno, 97, 98, str);
3014   }
3015   return back;
3016 }
3017 
3018 
3019 
3020 /**	Set status text OID.
3021 	@param	str	Text containing the OID.
3022 	@param	lineno	Line number (for diagnostics).
3023 	@return	1 on success, 0 on error.
3024 */
3025 static
3026 int
model_conf_status_oid(char * str,dk4_um_t lineno)3027 model_conf_status_oid(char *str, dk4_um_t lineno)
3028 {
3029   const char	*ep;		/* First unprocessable character */
3030   char		*np;		/* Next part */
3031   dk4_um_t	 num;		/* Numeric value for sub-id */
3032   size_t	 used	= 0;	/* Number of used sub-ids */
3033   int		 back	= 1;
3034   int		 res;		/* Operation result  */
3035 
3036   dk4str8_normalize(str, NULL);
3037   if ('.' == *str) {
3038     str++;
3039   }
3040   while ((NULL != str) && (1 == back)) {
3041     np = dk4str8_chr(str, '.');
3042     if (NULL != np) {
3043       *(np++) = '\0';
3044     }
3045     ep = NULL;
3046     res = dk4ma_input_c8_dec_dk4_um_t(&num, str, &ep, 1, NULL);
3047     if (0 != res) {
3048       if ((dk4_um_t)(MAX_SUBID) >= num) {
3049         if (used < DK4_SIZEOF(oid_st,oid)) {
3050 	  oid_st[used++] = (oid)num;
3051 	} else {
3052 	  /* ERROR: Syntax, OID too long */
3053 	  log_model_1(lineno, 99);
3054 	}
3055       } else {
3056         back = 0;
3057 	/* ERROR: Syntax, overflow */
3058 	log_model_3(lineno, 100, 101, str);
3059       }
3060     } else {
3061       back = 0;
3062       /* ERROR: Syntax, not a number */
3063       log_model_3(lineno, 102, 103, str);
3064     }
3065     str = np;
3066   }
3067   if (0 == used) {
3068     back = 0;
3069     /* ERROR: Syntax, empty OID */
3070     log_model_1(lineno, 104);
3071   }
3072   if (0 != back) {
3073     sz_oid_st = used;
3074   } else {
3075     sz_oid_st = 0;
3076   }
3077   by_oid_st = sz_oid_st * sizeof(oid);
3078 
3079   return back;
3080 }
3081 
3082 
3083 
3084 /**	Remove final double quote from string.
3085 	@param	str	String to modify.
3086 	@return	1 on success, 0 on error.
3087 */
3088 static
3089 int
remove_final_double_quote(char * str)3090 remove_final_double_quote(char *str)
3091 {
3092   char		*ptr;		/* Position of final double quote */
3093   int		 back	= 0;
3094 
3095   ptr = dk4str8_rchr(str, '"');
3096   if (NULL != ptr) {
3097     *(ptr++) = '\0';
3098     back = 1;
3099     while ('\0' != *ptr) {
3100       if (' ' != *ptr) {
3101         if ('\t' != *ptr) {
3102 	  if ('\r' != *ptr) {
3103 	    if ('\n' != *ptr) {
3104 	      back = 0;
3105 	    }
3106 	  }
3107 	}
3108       }
3109       ptr++;
3110     }
3111   }
3112 #if TRACE_DEBUG
3113   else {
3114   }
3115 #endif
3116 
3117   return back;
3118 }
3119 
3120 
3121 
3122 /**	Add a text indicating a state to the storage.
3123 	@param	str	Indicator text.
3124 	@param	state	State number indicated by the text.
3125 	@param	start	Flag: This text is just the start of the real text.
3126 	@param	lineno	Line number (for diagnostics).
3127 	@return	1 on success, 0 on error.
3128 */
3129 static
3130 int
model_conf_state_text(char * str,int state,int start,dk4_um_t lineno)3131 model_conf_state_text(char *str, int state, int start, dk4_um_t lineno)
3132 {
3133   status_text_t	*stptr;	/* New configuration node to add */
3134   const char	*ep;	/* First unprocessable char when reading number */
3135   char		*cptr;	/* Current word to process */
3136   char		*nptr;	/* Next word (remaining text) to process */
3137   size_t	 sl;	/* String length */
3138   int		 res;	/* Operation result */
3139   int		 back	= 0;
3140   unsigned char	 uc;	/* Current byte found */
3141 
3142   if (NULL == s_stn) {
3143     s_stn = dk4sto_open(NULL);
3144     if (NULL != s_stn) {
3145       dk4sto_set_comp(s_stn, stt_compare, 0);
3146     }
3147   }
3148   if ((NULL != s_stn) && (NULL == i_stn)) {
3149     i_stn = dk4sto_it_open(s_stn, NULL);
3150   }
3151   if ((NULL != s_stn) && (NULL != i_stn)) {
3152     if (NULL != str) {
3153       if ('"' == *str) {
3154         str++;
3155         if (0 != remove_final_double_quote(str)) {
3156 	  sl = strlen(str);
3157 	  if (0 < sl) {
3158 	    stptr = stt_new((unsigned char *)str, sl, state, start);
3159 	    if (NULL != stptr) {
3160 	      if (0 != dk4sto_add(s_stn, stptr, NULL)) {
3161 	        back = 1;
3162 	      } else {
3163 	        /* ERROR: Allocation failed */
3164 		log_model_1(lineno, 105);
3165 		stt_delete(stptr);
3166 	      }
3167 	    } else {
3168 	      /* ERROR: Allocation failed */
3169 	      log_model_1(lineno, 105);
3170 	    }
3171 	  } else {
3172 	    /* ERROR: Syntax, string empty */
3173 	    log_model_1(lineno, 106);
3174 	  }
3175 	} else {
3176 	  /* ERROR: Syntax, closing double quote missing or text after */
3177 	  log_model_1(lineno, 107);
3178 	}
3179       } else {
3180         sl = 0;
3181 	cptr = str;
3182 	back = 1;
3183 	while ((NULL != cptr) && (0 != back)) {
3184 	  nptr = dk4str8_next(cptr, NULL);
3185 	  ep = NULL;
3186 	  res = dk4ma_input_c8_hex_uchar(&uc, cptr, &ep, 1, NULL);
3187 	  if (0 != res) {
3188 	    str[sl++] = (char)uc;
3189 	  } else {
3190 	    back = 0;
3191 	    /* ERROR: Syntax, not a hexadecimal byte */
3192 	    log_model_3(lineno, 108, 109, cptr);
3193 	  }
3194 	  cptr = nptr;
3195 	}
3196 	if (0 != back) {
3197 	  if (0 < sl) {
3198 	    stptr = stt_new((unsigned char *)str, sl, state, start);
3199 	    if (NULL != stptr) {
3200 	      if (0 == dk4sto_add(s_stn, stptr, NULL)) {
3201 	        back = 0;
3202 		stt_delete(stptr);
3203 		/* ERROR: Allocation failed */
3204 		log_model_1(lineno, 105);
3205 	      }
3206 #if TRACE_DEBUG
3207 	      else {
3208 	      }
3209 #endif
3210 	    } else {
3211 	      back = 0;
3212 	      /* ERROR: Memory allocation failed */
3213 	      log_model_1(lineno, 105);
3214 	    }
3215 	  } else {
3216 	    /* ERROR: Syntax, empty string */
3217 	    log_model_1(lineno, 106);
3218 	  }
3219 	}
3220       }
3221     } else {
3222       /* ERROR: Value required */
3223       log_model_1(lineno, 110);
3224     }
3225   } else {
3226     /* ERROR: Memory allocation failed */
3227     log_model_1(lineno, 105);
3228   }
3229   return back;
3230 }
3231 
3232 
3233 
3234 /**	Process one configuration line from model file.
3235 	@param	str	Line to process.
3236 	@param	lineno	Line number in the file (for diagnostics).
3237 	@return	1 on success, 0 on error.
3238 */
3239 static
3240 int
process_model_line(char * str,dk4_um_t lineno)3241 process_model_line(char *str, dk4_um_t lineno)
3242 {
3243   char		*valptr;	/* Value in line */
3244   int		 back	= 0;
3245 
3246   valptr = dk4str8_chr(str, '=');
3247   if (NULL != valptr) {
3248     *(valptr++) = '\0';
3249     dk4str8_normalize(str, NULL);
3250     valptr = dk4str8_start(valptr, NULL);
3251     if (NULL != valptr) {
3252       switch (dk4str8_array_index(model_keys, str, 0)) {
3253         case 0: {
3254 	  back = model_conf_map(valptr, lineno);
3255 	} break;
3256         case 1: {
3257 	  back = model_conf_error_condition(valptr, 0, lineno);
3258 	} break;
3259         case 2: {
3260 	  back = model_conf_error_condition(valptr, 1, lineno);
3261 	} break;
3262         case 3: {
3263 	  back = model_conf_status_oid(valptr, lineno);
3264 	} break;
3265         case 4: {
3266 	  back = model_conf_state_text(valptr, PJSNMP_ST_STANDBY, 0, lineno);
3267 	} break;
3268         case 5: {
3269 	  back = model_conf_state_text(valptr, PJSNMP_ST_STANDBY, 1, lineno);
3270 	} break;
3271         case 6: {
3272 	  back = model_conf_state_text(valptr, PJSNMP_ST_IDLE, 0, lineno);
3273 	} break;
3274         case 7: {
3275 	  back = model_conf_state_text(valptr, PJSNMP_ST_IDLE, 1, lineno);
3276 	} break;
3277 	case 8: {
3278 	  back = 1;
3279 	  if (NULL != valptr) {
3280 	    valptr = dk4str8_start(valptr, NULL);
3281 	    if (NULL != valptr) {
3282 	      dk4str8_normalize(valptr, NULL);
3283 	      if (dk4str8_is_bool(valptr)) {
3284 	        stat_always = dk4str8_is_on(valptr);
3285 	      } else {
3286 	        back = 0;
3287 		/* ERROR: Not a boolean */
3288 		log_model_3(lineno, 111, 112, valptr);
3289 	      }
3290 	    } else {
3291 	      stat_always = 1;
3292 	    }
3293 	  } else {
3294 	    stat_always = 1;
3295 	  }
3296 	} break;
3297 	case 9: {
3298 	  back = model_conf_state_text(valptr, PJSNMP_ST_BUSY, 0, lineno);
3299 	} break;
3300 	case 10: {
3301 	  back = model_conf_state_text(valptr, PJSNMP_ST_BUSY, 1, lineno);
3302 	} break;
3303 	case 11: {
3304 	  back = model_conf_state_text(valptr, PJSNMP_ST_UNKNOWN, 0, lineno);
3305 	} break;
3306 	case 12: {
3307 	  back = model_conf_state_text(valptr, PJSNMP_ST_UNKNOWN, 1, lineno);
3308 	} break;
3309 	case 13: {
3310 	  back = model_conf_state_text(valptr, PJSNMP_ST_ERROR, 0, lineno);
3311 	} break;
3312 	case 14: {
3313 	  back = model_conf_state_text(valptr, PJSNMP_ST_ERROR, 1, lineno);
3314 	} break;
3315 	case 15: {
3316 	  back = model_conf_state_text(valptr, PJSNMP_ST_WARMUP, 0, lineno);
3317 	} break;
3318 	case 16: {
3319 	  back = model_conf_state_text(valptr, PJSNMP_ST_WARMUP, 1, lineno);
3320 	} break;
3321 	default: {
3322 	  /* ERROR: Syntax, unknown key */
3323 	  log_model_3(lineno, 113, 114, str);
3324 	} break;
3325       }
3326     } else {
3327       /* ERROR: Syntax, missing value */
3328       log_model_1(lineno, 110);
3329     }
3330   } else {
3331     /* ERROR: Syntax, missing value */
3332     log_model_1(lineno, 110);
3333   }
3334   return back;
3335 }
3336 
3337 
3338 
3339 /**	Configure for specified SNMP model.
3340 */
3341 static
3342 int
process_model_setup(void)3343 process_model_setup(void)
3344 {
3345   FILE		*infile;		/* Input file to read */
3346   char		*p1;			/* Start of text in line */
3347   dk4_um_t	 lineno		= (dk4_um_t)0UL;
3348   int		 in_model	= 0;	/* Flag: In model to read */
3349   int		 found		= 0;	/* Flag: Model was found */
3350   int		 back		= 0;
3351 
3352   infile = fopen(((NULL != model_file) ? model_file : def_model_file), "r");
3353   if (NULL != infile) {
3354     back = 1;
3355     while (NULL != fgets(pjsnmp_buf, sizeof(pjsnmp_buf), infile)) {
3356       lineno++;
3357 #if TRACE_DEBUG
3358       dk4str8_delnl(pjsnmp_buf);
3359 #endif
3360       p1 = dk4str8_start(pjsnmp_buf, NULL);
3361       if (NULL != p1) {
3362         if ('[' == *p1) {
3363 	  in_model = check_in_model(++p1, lineno);
3364 	  if (0 != in_model) {
3365 	    found = 1;
3366 	  }
3367 	} else {
3368 	  if (0 != in_model) {
3369 	    if ('#' != *p1) {
3370 #if !TRACE_DEBUG
3371 	      dk4str8_delnl(pjsnmp_buf);
3372 #endif
3373 	      if (0 == process_model_line(p1, lineno)) {
3374 	        back = 0;
3375 	      }
3376 	    }
3377 	  }
3378 	}
3379       }
3380     }
3381     fclose(infile);
3382     if (0 == found) {
3383       back = 0;
3384       /* ERROR: Model not found */
3385       log_model_3((dk4_um_t)0UL, 115, 116, model_name);
3386     }
3387   } else {
3388     /* ERROR: Failed to open model file */
3389     log_model_3(
3390       (dk4_um_t)0UL, 115, 116,
3391       ((NULL != model_file) ? model_file : def_model_file)
3392     );
3393   }
3394   return back;
3395 }
3396 
3397 
3398 
3399 /**	Process PRINTCAP_ENTRY and optionally
3400 	model file.
3401 	@param	argc	Number of command line arguments.
3402 	@param	argv	Command line arguments array.
3403 	@return	1 on success, 0 on error.
3404 */
3405 static
3406 int
process_setup(void)3407 process_setup(void)
3408 {
3409   char		*ptr;			/* Environment variable value */
3410   char		*cl;			/* Current line */
3411   char		*nl;			/* Next line */
3412   char		*ci;			/* Current item */
3413   char		*ni;			/* Next item */
3414   int		 found	= 0;		/* Already item found */
3415   int		 back	= 0;
3416 
3417 
3418   ptr = getenv(pjsnmp_kw[2]);
3419   if (NULL != ptr) {
3420     printcap_entry = dk4str8_dup(ptr, NULL);
3421     if (NULL != printcap_entry) {
3422       back = 1;
3423       cl = printcap_entry;
3424       while (NULL != cl) {
3425         nl = dk4str8_chr(cl, '\n');
3426 	if (NULL != nl) {
3427 	  *(nl++) = '\0';
3428 	  nl = dk4str8_start(nl, NULL);
3429 	}
3430 	ptr = cl;
3431 	while ('\0' != *ptr) {
3432 	  if ('\r' == *ptr) { *ptr = '\0'; } else { ptr++; }
3433 	}
3434 	ci = dk4str8_start(cl, NULL);
3435 	if (NULL != ci) {
3436 	  if ('#' != *ci) {
3437 	    while (NULL != ci) {
3438 	      ni = dk4str8_chr(ci, ':');
3439 	      if (NULL != ni) {
3440 	        *(ni++) = '\0'; ni = dk4str8_start(ni, NULL);
3441 	      }
3442 	      ci = dk4str8_start(ci, NULL);
3443 	      if (NULL != ci) {
3444 	        if (0 != found) {
3445 	          if (0 == process_one_config_item(ci)) {
3446 	            back = 0;
3447 	          }
3448 	        }
3449 	        found = 1;
3450 	      }
3451 	      ci = ni;
3452 	    }
3453 	  }
3454 	}
3455 	cl = nl;
3456       }
3457       if (NULL == host_name) {
3458         back = 0;
3459 	/* ERROR: Host name of printer required */
3460 	log_1_with_header(2, 119);
3461       }
3462       if (0 != back) {
3463         if (NULL != model_name) {
3464 	  back = process_model_setup();
3465 	}
3466       }
3467       if (0 != back) {
3468         if (0 != acct_achk) {
3469 	  acct_enab = 1;
3470 	}
3471 	if (0 != acct_enab) {
3472 	  if (NULL == acct_name) {
3473 	    if ((NULL == acct_host) || (0 == acct_port)) {
3474 	      log_1_with_header(2, 165);
3475 	      back = 0;
3476 	    }
3477 	  }
3478 	}
3479       }
3480     } else {
3481       /* ERROR: Memory allocation failed */
3482       log_1_with_header(2, 105);
3483     }
3484   } else {
3485     /* ERROR: Missing printcap entry environment variable */
3486     log_1_with_header(2, 120);
3487   }
3488 
3489   return back;
3490 }
3491 
3492 
3493 
3494 /**	Eat up remaining input from standard input.
3495 */
3496 static
3497 void
eatup_input(void)3498 eatup_input(void)
3499 {
3500   size_t	 rdb;		/* Number of read bytes */
3501   int		 cc	= 1;
3502 
3503   do {
3504     if (0 != can_continue(0)) {
3505       if (0 == have_eof) {
3506         rdb = fread(pjsnmp_buf, 1, sizeof(pjsnmp_buf), stdin);
3507 	if (0 == rdb) {
3508 	  cc = 0;
3509 	  have_eof = 1;
3510 	}
3511 #if TRACE_DEBUG
3512 	else {
3513 	}
3514 #endif
3515       } else {
3516         cc = 0;
3517       }
3518     } else {
3519       cc = -1;
3520     }
3521   } while (1 == cc);
3522 
3523 }
3524 
3525 
3526 
3527 /**	Release memory for the text nodes in s_stn.
3528 */
3529 static
3530 void
relase_status_text_nodes(void)3531 relase_status_text_nodes(void)
3532 {
3533   status_text_t	*ptr;			/* Current node to release */
3534 
3535   if (NULL != s_stn) {
3536     if (NULL != i_stn) {
3537       dk4sto_it_reset(i_stn);
3538       do {
3539         ptr = (status_text_t *)dk4sto_it_next(i_stn);
3540 	if (NULL != ptr) {
3541 	  stt_delete(ptr);
3542 	}
3543       } while(NULL != ptr);
3544       dk4sto_it_close(i_stn); i_stn = NULL;
3545     }
3546     dk4sto_close(s_stn); s_stn = NULL;
3547   }
3548 
3549 }
3550 
3551 
3552 
3553 /**	Attempt to open an SNMP session.
3554 	@return	1 on success, 0 on error.
3555 */
3556 static
3557 int
attempt_snmp_session(void)3558 attempt_snmp_session(void)
3559 {
3560   struct snmp_session	sesstemp;	/* Template for the session */
3561   int		 	back	= 0;
3562 
3563   init_snmp(pjsnmp_kw[4]);
3564   DK4_MEMRES(&sesstemp, sizeof(sesstemp));
3565   snmp_sess_init(&sesstemp);
3566   sesstemp.version = snmp_version;
3567   sesstemp.peername = host_name;
3568   sesstemp.community = (unsigned char *)snmp_comm;
3569   if (NULL == snmp_comm) {
3570     sesstemp.community = (unsigned char *)(pjsnmp_kw[5]);
3571   }
3572   sesstemp.community_len = strlen((char *)(sesstemp.community));
3573   snmp_sess = snmp_open(&sesstemp);
3574   if (NULL != snmp_sess) {
3575     back = 1;
3576   } else {
3577     /* ERROR: Failed to open SNMP session */
3578     log_1_no_header(121);
3579     if (0 != snmp_igfs) {
3580       back = 1;
3581     }
3582   }
3583   return back;
3584 }
3585 
3586 
3587 
3588 /**	Accounting data exchange via socket (either network socket
3589 	or local UNIX domain socket) and close socket.
3590 	@param	sock		Socket to use for data exchange.
3591 	@param	expect_response	Flag: Response from accounting system expected.
3592 	@return	1 on success, 0 on error.
3593 */
3594 static
3595 int
accounting_ex_socket(dk4_socket_t sock,int expect_response)3596 accounting_ex_socket(dk4_socket_t sock, int expect_response)
3597 {
3598   size_t	 sl;		/* String length */
3599   size_t	 by;		/* Bytes written or read */
3600   int		 res;		/* Operation result */
3601   int		 cutted;	/* String was cutted */
3602   int		 cc;		/* Flag: Can continue */
3603   int		 back	= 0;
3604 
3605   cutted = 0;
3606   if (0 != can_continue(0)) {
3607     sl = strlen(pjsnmp_buf);
3608     by = sl;
3609     res = dk4socket_send(sock, pjsnmp_buf, &by, 0, 0L, 0L, NULL);
3610     if (DK4_SOCKET_RESULT_SUCCESS == res) {
3611       if (by == sl) {
3612         back = 1;
3613       } else {
3614         /* ERROR: Partial send */
3615 	log_1_no_header(123);
3616       }
3617     } else {
3618       /* ERROR: Failed to send data */
3619       log_1_no_header(122);
3620     }
3621     pjsnmp_buf[0] = '\0';
3622     res = dk4socket_shutdown(sock, DK4_SOCKET_SHUT_WRITE, NULL);
3623     if (DK4_SOCKET_RESULT_SUCCESS == res) {
3624       cc = 1;
3625       do {
3626         if (0 != can_continue(0)) {
3627           by = sizeof(stat_text) - 1;
3628           res = dk4socket_recv(sock, stat_text, &by, 0, 0L, 0L, NULL);
3629           if (DK4_SOCKET_RESULT_SUCCESS == res) {
3630 	    if (0 < by) {
3631 	      stat_text[by] = '\0';
3632 	      res = dk4str8_cat_s(pjsnmp_buf,sizeof(pjsnmp_buf),stat_text,NULL);
3633 	      if (0 == res) {
3634 	        cutted = 1;
3635 		back = 0;
3636 	      }
3637 	    } else {
3638 	      cc = 0;
3639 	    }
3640           } else {
3641             cc = -1;
3642           }
3643 	} else {
3644 	  cc = -1;
3645 	  back = 0;
3646 	}
3647       } while(1 == cc);
3648     } else {
3649       back = 0;
3650       /* ERROR: Socket shutdown failed */
3651       log_1_no_header(124);
3652     }
3653     if (0 != expect_response) {
3654       if (0 == strlen(pjsnmp_buf)) {
3655         back = 0;
3656       }
3657       if (0 != cutted) {
3658         back = 0;
3659       }
3660     }
3661   } else {
3662     pjsnmp_buf[0] = '\0';
3663   }
3664   dk4socket_close(sock, NULL);
3665 
3666   return back;
3667 }
3668 
3669 
3670 
3671 /**	Accounting data exchange via local UNIX domain socket.
3672 	@param	expect_response	Flag: Response from accounting system expected.
3673 	@return	1 on success, 0 on error.
3674 */
3675 static
3676 int
accounting_ex_local_socket(int expect_response)3677 accounting_ex_local_socket(int expect_response)
3678 {
3679   dk4_socket_t	 sock;		/* Socket to use for accounting */
3680   int		 back = 0;
3681 
3682   sock = dk4socket_c8_unix_client(acct_name, NULL);
3683   if (INVALID_SOCKET != sock) {
3684     back = accounting_ex_socket(sock, expect_response);
3685     /* Socket not closed here, closed in accounting_ex_socket() */
3686   } else {
3687     /* ERROR: Failed to open UNIX domain socket */
3688     log_1_no_header(125);
3689     pjsnmp_buf[0] = '\0';
3690   }
3691 
3692   return back;
3693 }
3694 
3695 
3696 
3697 /**	Accounting data exchange via network socket.
3698 	@param	expect_response	Flag: Response from accounting system expected.
3699 	@return	1 on success, 0 on error.
3700 */
3701 static
3702 int
accounting_ex_network(int expect_response)3703 accounting_ex_network(int expect_response)
3704 {
3705   dk4_socket_t	 sock;		/* Socket to use for accounting */
3706   int		 back	= 0;
3707 
3708   sock = dk4socket_c8_tcp_client_host_port(acct_host,acct_port,0,0L,0L,NULL);
3709   if (INVALID_SOCKET != sock) {
3710     back = accounting_ex_socket(sock, expect_response);
3711     /* Socket not closed here, closed in accounting_ex_socket() */
3712   } else {
3713     /* ERROR: Failed to open network connection */
3714     log_1_no_header(125);
3715     pjsnmp_buf[0] = '\0';
3716   }
3717 
3718   return back;
3719 }
3720 
3721 
3722 
3723 /**	Accounting data exchange to file.
3724 	@param	fipo		Accounting file.
3725 	@param	expect_response	Flag: Response from accounting system expected.
3726 	@return	1 on success, 0 on error.
3727 */
3728 static
3729 int
accounting_ex_file(FILE * fipo,int expect_response)3730 accounting_ex_file(FILE *fipo, int expect_response)
3731 {
3732   int		 back	= 0;
3733 
3734   if (EOF != fputs(pjsnmp_buf, fipo)) {
3735     if (EOF != fflush(fipo)) {
3736       back = 1;
3737     }
3738 #if TRACE_DEBUG
3739     else {
3740     }
3741 #endif
3742   }
3743 #if TRACE_DEBUG
3744   else {
3745   }
3746 #endif
3747   pjsnmp_buf[0] = '\0';
3748   if (0 != expect_response) {
3749     back = 0;
3750   }
3751   return back;
3752 }
3753 
3754 
3755 
3756 /**	Accounting data exchange via pipe.
3757 	@param	expect_response	Flag: Response from accounting system expected.
3758 	@return	1 on success, 0 on error.
3759 */
3760 static
3761 int
accounting_ex_pipe(int expect_response)3762 accounting_ex_pipe(int expect_response)
3763 {
3764   FILE		*fipo	= NULL;		/* Connection to pipe */
3765   char		*prgn	= NULL;		/* Program name */
3766   int		 back	= 0;
3767   int		 pcres	= 0;		/* Result from pclose */
3768 
3769   prgn = dk4str8_start(&(acct_name[1]), NULL);
3770   if (NULL != prgn) {
3771     fipo = popen(prgn, "w");
3772     if (NULL != fipo) {
3773       back = accounting_ex_file(fipo, 0);
3774       pcres = pclose(fipo);
3775       pjsnmp_buf[0] = '\0';
3776       if (0 != expect_response) {
3777         switch (pcres) {
3778 	  case LPRNG_EXIT_REMOVE : {
3779 	    decision = 3;
3780 	  } break;
3781 	  case LPRNG_EXIT_HOLD : {
3782 	    decision = 2;
3783 	  } break;
3784 	  default : {
3785 	    decision = 1;
3786 	  } break;
3787         }
3788 	log_3_no_header(166, 167, accounting_responses[decision - 1]);
3789       }
3790     } else {
3791       /* ERROR: Failed to start program for pipe */
3792       log_1_no_header(126);
3793       pjsnmp_buf[0] = '\0';
3794     }
3795   } else {
3796     /* ERROR: Not command name found */
3797     log_1_with_header(2, 127);
3798     pjsnmp_buf[0] = '\0';
3799   }
3800   return back;
3801 }
3802 
3803 
3804 
3805 /**	Accounting data exchange via file specified by name.
3806 	@param	expect_response	Flag: Response from accounting system expected.
3807 	@param	crf		Flag: Create new file.
3808 	@return	1 on success, 0 on error.
3809 */
3810 static
3811 int
accounting_ex_filename(int expect_response,int crf)3812 accounting_ex_filename(int expect_response, int crf)
3813 {
3814   dk4_er_t	 er;				/* Error report */
3815   FILE		*fipo	= NULL;			/* File to write to */
3816   int		 back	= 1;
3817   int		 tests	= DK4_FOPEN_SC_USER;	/* Security tests for fopen */
3818 
3819   if (0 != dk4isadmin()) {
3820     tests = DK4_FOPEN_SC_PRIVILEGED;
3821   }
3822   dk4error_init(&er);
3823   fipo = dk4fopen_c8(acct_name, ((0 != crf) ? "w" : "a"), tests, &er);
3824   if (NULL != fipo) {
3825     back = accounting_ex_file(fipo, expect_response);
3826     if(EOF == fclose(fipo)) {
3827       back = 0;
3828     }
3829   } else {
3830     /* ERROR: Failed to open accounting file name */
3831     log_1_no_header(128);
3832     pjsnmp_buf[0] = '\0';
3833   }
3834   return back;
3835 }
3836 
3837 
3838 
3839 #if 0
3840 /*	2016-02-10:
3841 	Although chapter 15.5 of the LPRng reference manual states that the
3842 	:af file is opened (file, pipe or network socket) and passed as
3843 	file descriptor 3 to all filters, this did not work in my tests.
3844 	Text written to fd 3 did not arrive at the accounting system.
3845 */
3846 
3847 /**	Accounting data exchange via file descriptor 3.
3848 	@param	expect_response	Flag: Response from accounting system expected.
3849 	@return	1 on success, 0 on error.
3850 */
3851 static
3852 int
3853 accounting_ex_fd3(int expect_response)
3854 {
3855   size_t	 sl;		/* String length */
3856   ssize_t	 bwr;		/* Number of bytes written or read */
3857   int		 back	= 0;
3858 
3859   sl = strlen(pjsnmp_buf);
3860   bwr = write(3, pjsnmp_buf, sl);
3861   pjsnmp_buf[0] = '\0';
3862   if (0 < bwr) {
3863     if (sl == (size_t)bwr) {
3864       back = 1;
3865     } else {
3866       /* ERROR: Incomplete write operation */
3867       log_1_no_header(122);
3868     }
3869     if (0 != expect_response) {
3870       bwr = read(3, pjsnmp_buf, sizeof(pjsnmp_buf));
3871       if (0 < bwr) {
3872         pjsnmp_buf[bwr] = '\0';
3873       } else {
3874         pjsnmp_buf[0] = '\0';
3875         back = 0;
3876       }
3877     }
3878   } else {
3879     /* ERROR: Write failed */
3880     log_1_no_header(122);
3881   }
3882   return back;
3883 }
3884 
3885 #endif
3886 
3887 
3888 
3889 
3890 
3891 /**	Data exchange with accounting system.
3892 	The contents of pjsnmp_buf is sent to the accounting system,
3893 	the response - if any - is stored in pjsnmp_buf.
3894 	@param	expect_response	Flag: Accounting system should send response.
3895 	@return	1 on successfull exchange, 0 on connection error.
3896 */
3897 static
3898 int
accounting_exchange(int expect_response)3899 accounting_exchange(int expect_response)
3900 {
3901   dk4_stat_t	 stb;			/* File status buffer */
3902   int		 issock	= 0;		/* Flag: File is socket */
3903   int		 back	= 0;		/* Function result */
3904   int		 crf	= 0;		/* Flag: Create log file */
3905 
3906   if ((NULL != acct_host) && (0 < acct_port)) {
3907     log_1_no_header(154);
3908     back = accounting_ex_network(expect_response);
3909     log_1_no_header((0 != back) ? 159 : 160);
3910   } else {
3911     if (NULL != acct_name) {
3912       if ('|' == *acct_name) {
3913 #if 0
3914         if (0 != expect_response) {
3915 	  /* ERROR: Can not receive response from pipe */
3916 	  log_1_with_header(2, 129);
3917 	}
3918 #endif
3919 	log_1_no_header(155);
3920         back = accounting_ex_pipe(expect_response);
3921         log_1_no_header((0 != back) ? 159 : 160);
3922       } else {
3923         if (0 != dk4stat_c8(&stb, acct_name, NULL)) {
3924 	  if (0 != dk4stat_is_unix_domain_socket(&stb, NULL)) {
3925 	    issock = 1;
3926 	  }
3927 	} else {
3928 	  crf = 1;
3929 	}
3930         if (0 != issock) {
3931 	  log_1_no_header(156);
3932 	  back = accounting_ex_local_socket(expect_response);
3933           log_1_no_header((0 != back) ? 159 : 160);
3934 	} else {
3935 	  if (0 != expect_response) {
3936 	    /* ERROR: Can not receive response from file */
3937 	    log_1_with_header(2, 130);
3938 	  }
3939 	  log_1_no_header(157);
3940 	  back = accounting_ex_filename(expect_response, crf);
3941           log_1_no_header((0 != back) ? 159 : 160);
3942 	}
3943       }
3944     } else {
3945 #if 0
3946       log_1_no_header(158);
3947       back = accounting_ex_fd3(expect_response);
3948       log_1_no_header((0 != back) ? 159 : 160);
3949 #else
3950       log_1_with_header(2, 165);
3951 #endif
3952     }
3953   }
3954   return back;
3955 }
3956 
3957 
3958 
3959 /**	Check users permission to print on queue.
3960 	@return	1 if user is allowed to print, 0 otherwise.
3961 */
3962 static
3963 int
check_permission(void)3964 check_permission(void)
3965 {
3966   int		 back	= 1;
3967   int		 res	= 0;			/* Result from check */
3968   const size_t	 bsz	= sizeof(pjsnmp_buf);	/* Buffer size */
3969 
3970   if ((0 != acct_enab) && (0 != acct_achk)) {
3971     /* LOG: Checking print permission */
3972     log_5_no_header(131, 132, 133, user_name, queue_name);
3973     if(0 != dk4str8_cpy_s(pjsnmp_buf, bsz, pjsnmp_kw[6], NULL)) {
3974     if(0 != dk4str8_cat_s(pjsnmp_buf, bsz, pjsnmp_kw[1], NULL)) {
3975     if(0 != dk4str8_cat_s(pjsnmp_buf, bsz, queue_name, NULL)) {
3976     if(0 != dk4str8_cat_s(pjsnmp_buf, bsz, pjsnmp_kw[1], NULL)) {
3977     if(0 != dk4str8_cat_s(pjsnmp_buf, bsz, user_name, NULL)) {
3978     if(0 != dk4str8_cat_s(pjsnmp_buf, bsz, pjsnmp_kw[0], NULL)) {
3979       back = 0;
3980       if (0 != accounting_exchange(1)) {
3981         dk4str8_normalize(pjsnmp_buf, NULL);
3982 	if (0 < strlen(pjsnmp_buf)) {
3983 	  if (0 != decision) {
3984 	    res = decision - 1;
3985 	  } else {
3986 	    res = dk4str8_array_index(accounting_responses, pjsnmp_buf, 0);
3987 	    if (-1 < res) { decision = res + 1; }
3988 	  }
3989 	  switch (res) {
3990 	    case 0: {
3991 	      back = 1;
3992 	    } break;
3993 	    case 1: {
3994 	      exval = LPRNG_EXIT_HOLD;
3995 	    } break;
3996 	  }
3997 	  log_3_no_header(166, 167, pjsnmp_buf);
3998 	} else {
3999 #if 0
4000 	  /*	2016-02-15	An empty response indicates permission
4001 	  			to print.
4002 	  */
4003 	  if (0 != acct_apcf) { back = 1; }
4004 #endif
4005 	  back = 1;
4006 	}
4007       } else {
4008         if (0 != acct_apcf) { back = 1; }
4009 	else { decision = 3; }
4010       }
4011     }
4012     }
4013     }
4014     }
4015     }
4016     }
4017     /* LOG: Test result */
4018     log_1_no_header((0 != back) ? 134 : 135);
4019   }
4020   return back;
4021 }
4022 
4023 
4024 
4025 /**	Retrieve integer value from variable list.
4026 	@param	iptr	Address of variable to set.
4027 	@param	var	SNMP variable containing the value.
4028 	@return	1 on success, 0 on error.
4029 */
4030 static
4031 int
get_int(int * iptr,struct variable_list * var)4032 get_int(int *iptr, struct variable_list *var)
4033 {
4034   char		 bu[64];		/* Buffer for numeric values as text */
4035   const char	*endptr	= NULL;		/* First unprocessable character */
4036   long		 l;			/* long value */
4037   int		 i;			/* int value */
4038   int		 back	= 0;
4039 
4040   switch (var->type) {
4041     case ASN_OCTET_STR : {
4042       if ((var->val_len > 0) && (var->val_len < sizeof(bu))) {
4043         dk4mem_cpy(bu, (void *)((var->val).string), var->val_len, NULL);
4044 	bu[var->val_len] = '\0';
4045 	if (0 != dk4ma_input_c8_dec_int(&i, bu, &endptr, 1, NULL)) {
4046 	  *iptr = i;
4047 	  back = 1;
4048 	}
4049       }
4050     } break;
4051     case ASN_TIMETICKS :
4052     case ASN_GAUGE :
4053     case ASN_COUNTER :
4054     case ASN_INTEGER : {
4055       l = *((var->val).integer);
4056       *iptr = (int)l;
4057       back = 1;
4058     } break;
4059   }
4060 
4061   return back;
4062 }
4063 
4064 
4065 
4066 /**	Retrieve unsigned long value from variable list.
4067 	@param	ulptr	Address of variable to set.
4068 	@param	var	SNMP variable containing the value.
4069 	@return	1 on success, 0 on error.
4070 */
4071 static
4072 int
get_ul(unsigned long * ulptr,struct variable_list * var)4073 get_ul(unsigned long *ulptr, struct variable_list *var)
4074 {
4075   unsigned long	 ul	= 0UL;		/* Result variable */
4076   long		 l;			/* long value */
4077   int		 back	= 0;
4078 
4079   switch (var->type) {
4080     case ASN_OCTET_STR : {
4081       if (0 < var->val_len) {
4082         ul |=
4083 	((((unsigned long)(((var->val).string)[0])) << 24) & 0xFF000000UL);
4084 	back = 1;
4085       }
4086       if (1 < var->val_len) {
4087         ul |=
4088 	((((unsigned long)(((var->val).string)[1])) << 16) & 0x00FF0000UL);
4089       }
4090       if (2 < var->val_len) {
4091         ul |=
4092 	((((unsigned long)(((var->val).string)[2])) <<  8) & 0x0000FF00UL);
4093       }
4094       if (3 < var->val_len) {
4095         ul |=
4096 	((((unsigned long)(((var->val).string)[3]))      ) & 0x000000FFUL);
4097       }
4098       if (0 != back) {
4099         *ulptr = ul;
4100       }
4101     } break;
4102     case ASN_TIMETICKS :
4103     case ASN_GAUGE :
4104     case ASN_COUNTER :
4105     case ASN_INTEGER : {
4106       l = *((var->val).integer);
4107       if (0L <= l) {
4108         *ulptr = (unsigned long)l;
4109         back = 1;
4110       }
4111     } break;
4112   }
4113 
4114   return back;
4115 }
4116 
4117 
4118 
4119 /**	Check whether a buffer contains non-ASCII characters.
4120 	@param	ptr	Buffer address.
4121 	@param	i	Buffer size.
4122 	@return	1 if non-ASCII found, 0 otherwise.
4123 */
4124 static
4125 int
contains_non_ascii(const char * ptr,size_t i)4126 contains_non_ascii(const char *ptr, size_t i)
4127 {
4128   int		 back	= 0;
4129 
4130   while ((0 == back) && (0 < i)) {
4131     if (0x7F < (unsigned char)(*(ptr++))) {
4132       back = 1;
4133     }
4134     i--;
4135   }
4136   return back;
4137 }
4138 
4139 
4140 
4141 /**	Replace all non-ascii characters by question marks.
4142 */
4143 static
4144 void
no_non_ascii(char * str)4145 no_non_ascii(char *str)
4146 {
4147   unsigned char	uc;
4148   while ('\0' != *str) {
4149     uc = (unsigned char)(*str);
4150     if ((0x20 > uc) || (0x7E < uc)) {
4151       *str = '?';
4152     }
4153     str++;
4154   }
4155 }
4156 
4157 
4158 
4159 
4160 /**	Check two OIDs for equality.
4161 	@param	pl	Left OID.
4162 	@param	szl	Left OID size.
4163 	@param	pr	Right OID.
4164 	@param	szr	Right OID size.
4165 	@return	1 for equal OIDs, 0 otherwise.
4166 */
4167 static
4168 int
oids_equal(const oid * pl,size_t szl,const oid * pr,size_t szr)4169 oids_equal(const oid *pl, size_t szl, const oid *pr, size_t szr)
4170 {
4171 #if VERSION_BEFORE_20160206
4172   size_t	 i;		/* Index of current sub-id to compare */
4173 #endif
4174   int		 back	= 0;
4175   if ((szl == szr) && (0 < szl)) {
4176 #if VERSION_BEFORE_20160206
4177     back = 1;
4178     for (i = 0; ((i < szl) && (1 == back)); i++) {
4179       if (pl[i] != pr[i]) {
4180         back = 0;
4181       }
4182     }
4183 #else
4184     /*	No check for overflow necessary, max 4 * 128.  */
4185     if (0 == dk4mem_cmp(pl, pr, (szl * sizeof(oid)), NULL)) {
4186       back = 1;
4187     }
4188 #endif
4189   }
4190   return back;
4191 }
4192 
4193 
4194 /**	Find OID index.
4195 	@param	oid	Pointer to OID to check.
4196 	@param	sz	OID size.
4197 	@return	0 for hrDeviceStatus, 1 for hrPrinterStatus,
4198 	2 for page counter, 3 for hrPrinterDetectedErrorState,
4199 	4 for status text,
4200 	-1 otherwise.
4201 */
4202 static
4203 int
oid_index(oid * p,size_t sz)4204 oid_index(oid *p, size_t sz)
4205 {
4206   int		 back	= -1;
4207 
4208   if (0 != oids_equal(p, sz, oid_ds, sz_oid_ds)) {
4209     back = 0;
4210   } else {
4211     if (0 != oids_equal(p, sz, oid_ps, sz_oid_ps)) {
4212       back = 1;
4213     } else {
4214       if (0 != oids_equal(p, sz, oid_pc, sz_oid_pc)) {
4215         back = 2;
4216       } else {
4217         if (0 != oids_equal(p, sz, oid_pe, sz_oid_pe)) {
4218 	  back = 3;
4219 	} else {
4220 	  if (0 < sz_oid_st) {
4221 	    if (0 != oids_equal(p, sz, oid_st, sz_oid_st)) {
4222 	      back = 4;
4223 	    }
4224 	  }
4225 #if TRACE_DEBUG
4226 	  else {
4227 	  }
4228 #endif
4229 	}
4230       }
4231     }
4232   }
4233   return back;
4234 }
4235 
4236 
4237 
4238 /**	Show one active condition from hrPrinterDetectedErrorState.
4239 	@param	cond	Condition bit (checked against the found conditions).
4240 	@param	cind	Index of corresponding text in pjsnmp_kw.
4241 */
4242 static
4243 void
show_pdes(unsigned long cond,size_t cind)4244 show_pdes(unsigned long cond, size_t cind)
4245 {
4246   if (0UL != (pdes_cond & cond)) {
4247     fputs(pjsnmp_kw[((0UL != (pdes_error & cond)) ? 32 : 33)], out_file);
4248     fputs(pjsnmp_kw[cind], out_file);
4249   }
4250 }
4251 
4252 
4253 
4254 static
4255 void
show_text_containing_non_ascii(const unsigned char * ptr,size_t num)4256 show_text_containing_non_ascii(const unsigned char *ptr, size_t num)
4257 {
4258   while(0 < num--) {
4259     if (0x7F < *ptr) {
4260       fputc('?', out_file);
4261     } else {
4262       fputc(*ptr, out_file);
4263     }
4264     ptr++;
4265   }
4266 }
4267 
4268 
4269 
4270 /**	Report status if changed.
4271 	@param	found	Bitmask for found information.
4272 */
4273 static
4274 void
report_status_if_changed(void)4275 report_status_if_changed(void)
4276 {
4277   unsigned long	tcond		= 0x80000000UL;	/* Bit for one condition */
4278   int		must_report	= 0;		/* Flag: Must report change */
4279   int		i;
4280 
4281   /*	Check whether or not to report.
4282   */
4283   if (stsum != ostsum) {
4284     must_report = 1;
4285   } else {
4286     if (devst != odevst) {
4287       must_report = 1;
4288     } else {
4289       if (prist != oprist) {
4290         must_report = 1;
4291       } else {
4292         if (pdes_cond != opdes_cond) {
4293           must_report = 1;
4294         } else {
4295           if (0 < sz_stat_text) {
4296 	    if (0 != force_printable_status_text) {
4297 	      if (sz_ostat_text != sz_stat_text) {
4298 	        must_report = 1;
4299 	      } else {
4300 	        if (0 != dk4mem_cmp(stat_text,ostat_text,sz_stat_text,NULL)) {
4301 		  must_report = 1;
4302 		}
4303 	      }
4304 	    } else {
4305               if (0 == contains_non_ascii(stat_text, sz_stat_text)) {
4306                 if (sz_stat_text != sz_ostat_text) {
4307                   must_report = 1;
4308                 } else {
4309                   if (0 != dk4mem_cmp(stat_text,ostat_text,sz_stat_text,NULL)) {
4310 	            must_report = 1;
4311 	          }
4312                 }
4313               }
4314 	    }
4315           }
4316 	}
4317       }
4318     }
4319   }
4320 
4321   /*	Report if necessary.
4322   */
4323   if (0 != must_report) {
4324     fputs(pjsnmp_kw[150], out_file);
4325     (void)log_timestamp();
4326     if ((-1 < devst) && (6 > devst)) {
4327       if ((-1 < prist) && (6 > prist)) {
4328         fputs(pjsnmp_kw[7], out_file);
4329         fputs(pjsnmp_kw[11 + devst], out_file);
4330         fputs(pjsnmp_kw[8], out_file);
4331         fputs(pjsnmp_kw[17 + prist], out_file);
4332         fputs(pjsnmp_kw[0], out_file);
4333       }
4334     }
4335     fputs(pjsnmp_kw[9], out_file);
4336     for (i = 0; i < 16; i++) {
4337       if ((0 < i) && (0 == (i % 4))) { fputc('-', out_file); }
4338       fputc(((0UL != (pdes_cond & tcond)) ? '1' : '0'), out_file);
4339       tcond = tcond / 2UL;
4340     }
4341     fputs(pjsnmp_kw[0], out_file);
4342     show_pdes(PDES_ERROR_DOOR_OPEN, 38);
4343     show_pdes(PDES_ERROR_OFFLINE, 40);
4344     show_pdes(PDES_ERROR_MARKER_SUPPLY_MISSING, 44);
4345     show_pdes(PDES_ERROR_NO_TONER, 37);
4346     show_pdes(PDES_WARNING_TONER_LOW, 36);
4347     show_pdes(PDES_ERROR_INPUT_TRAY_MISSING, 42);
4348     show_pdes(PDES_WARNING_INPUT_TRAY_EMPTY, 47);
4349     show_pdes(PDES_ERROR_NO_PAPER, 35);
4350     show_pdes(PDES_WARNING_PAPER_LOW, 34);
4351     show_pdes(PDES_ERROR_OUTPUT_TRAY_MISSING, 43);
4352     show_pdes(PDES_ERROR_PAPER_JAM, 39);
4353     show_pdes(PDES_ERROR_OUTPUT_FULL, 46);
4354     show_pdes(PDES_WARNING_OUTPUT_NEAR_FULL, 45);
4355     show_pdes(PDES_WARNING_SERVICE, 41);
4356     show_pdes(PDES_WARNING_OVERDUE_PREVENT_MAINT, 48);
4357     if (0 < sz_stat_text) {
4358       if (0 != force_printable_status_text) {
4359         fputs(pjsnmp_kw[30], out_file);
4360 	show_text_containing_non_ascii((unsigned char *)stat_text,sz_stat_text);
4361 	fputs(pjsnmp_kw[31], out_file);
4362       } else {
4363         if (0 == contains_non_ascii(stat_text, sz_stat_text)) {
4364 	  fputs(pjsnmp_kw[30], out_file);
4365 	  (void)fwrite(stat_text, 1, sz_stat_text, out_file);
4366 	  fputs(pjsnmp_kw[31], out_file);
4367         }
4368       }
4369     }
4370     if ((-1 < stsum) && (7 > stsum)) {
4371       fputs(pjsnmp_kw[10], out_file);
4372       fputs(pjsnmp_kw[23 + stsum], out_file);
4373       fputs(pjsnmp_kw[0], out_file);
4374     }
4375     if (PJSNMP_ST_ERROR == stsum) {
4376       fputs(pjsnmp_kw[49], out_file);
4377     } else {
4378       if (0UL != (pdes_cond & PDES_WARNING_SERVICE)) {
4379         if (0UL == (pdes_error & PDES_WARNING_SERVICE)) {
4380 	  fputs(pjsnmp_kw[50], out_file);
4381         }
4382       }
4383     }
4384     fflush(out_file);
4385   }
4386 
4387 }
4388 
4389 
4390 
4391 /**	One SNMP data exchange.
4392 	@param	passno	0 before start, 1 during transfer, 2 at end.
4393 	@return	1 on success, 0 on error (stop printing).
4394 */
4395 static
4396 int
one_snmp_request(int passno)4397 one_snmp_request(int passno)
4398 {
4399   status_text_t			 tx;		/* Used in comparison */
4400   status_text_t			*ptx	= NULL;	/* Text node found */
4401   struct	snmp_pdu	*rq	= NULL;	/* Request */
4402   struct	snmp_pdu	*rs	= NULL;	/* Response */
4403   struct	variable_list	*vars	= NULL;	/* Response variables */
4404   int				 status	= 0;	/* SNMP result */
4405   int				 found	= 0;	/* Information from response */
4406   int				 back	= 0;
4407 
4408   if (0 != can_continue(0)) {
4409     if (NULL != snmp_sess) {
4410       pdes_cond 	= 0UL;
4411       pcnt		= 0UL;
4412       devst		= 0;
4413       prist		= 0;
4414       stsum		= PJSNMP_ST_UNREACHABLE;
4415       stat_text[0]	= '\0';
4416       sz_stat_text	= 0;
4417       rq = snmp_pdu_create(SNMP_MSG_GET);
4418       if (NULL != rq) {
4419         back = 1;
4420         snmp_add_null_var(rq, oid_ds, sz_oid_ds);
4421 	snmp_add_null_var(rq, oid_ps, sz_oid_ps);
4422 	snmp_add_null_var(rq, oid_pc, sz_oid_pc);
4423 	snmp_add_null_var(rq, oid_pe, sz_oid_pe);
4424 	if (0 < sz_oid_st) {
4425 	  snmp_add_null_var(rq, oid_st, sz_oid_st);
4426 	}
4427 	status = snmp_synch_response(snmp_sess, rq, &rs);
4428 	if (STAT_SUCCESS == status) {
4429 	  if (NULL != rs) {
4430 	    if (SNMP_ERR_NOERROR == rs->errstat) {
4431 
4432 	      /*	Obtain response elements.
4433 	      */
4434 	      stsum = PJSNMP_ST_UNKNOWN;
4435 	      vars = rs->variables;
4436 	      while (NULL != vars) {
4437 	        switch (oid_index(vars->name, vars->name_length)) {
4438 		  case 0: {
4439 		    if (0 != get_int(&devst, vars)) {
4440 		      found |= 1;
4441 		    }
4442 		  } break;
4443 		  case 1: {
4444 		    if (0 != get_int(&prist, vars)) {
4445 		      found |= 2;
4446 		    }
4447 		  } break;
4448 		  case 2: {
4449 		    if (0 != get_ul(&pcnt, vars)) {
4450 		      found |= 4;
4451 		      switch (passno) {
4452 		        case 0: {
4453 			  pc_start = pcnt;
4454 			  have_pcs = 1;
4455 			} break;
4456 			case 1: {
4457 			  /*	When aborting due to timeout in
4458 			  	error or unreachable state we use the
4459 				last page counter seen.
4460 			  */
4461 			  pc_end = pcnt;
4462 			  have_pce = 1;
4463 			} break;
4464 			case 2: {
4465 			  pc_end = pcnt;
4466 			  have_pce = 1;
4467 			} break;
4468 		      }
4469 		    }
4470 		  } break;
4471 		  case 3: {
4472 		    if (0 != get_ul(&pdes_cond, vars)) { found |= 8; }
4473 		  } break;
4474 		  case 4: {
4475 		    if (0 < vars->val_len) {
4476 		      if (sizeof(stat_text) > vars->val_len) {
4477 		        dk4mem_cpy(
4478 			  stat_text, (vars->val).string,
4479 			  vars->val_len, NULL
4480 			);
4481 			sz_stat_text = vars->val_len;
4482 		      } else {
4483 		        dk4mem_cpy(
4484 			  stat_text, (vars->val).string,
4485 			  sizeof(stat_text), NULL
4486 			);
4487 			sz_stat_text = sizeof(stat_text);
4488 		      }
4489 		      found |= 16;
4490 		    }
4491 		  } break;
4492 		}
4493 	        vars = vars->next_variable;
4494 	      }
4495 
4496 	      /*	Build summary (1): device and printer status.
4497 	      */
4498 	      if (3 == (3 & found)) {
4499 	        stsum = get_state_mapping(devst, prist);
4500 
4501 	      }
4502 
4503 	      /*	Build summary (2): printer detected error state
4504 	      */
4505 	      if (8 == (8 & found)) {
4506 	        if ((0 != pdes_always) || (PJSNMP_ST_UNKNOWN == stsum)) {
4507 		  if (0L != (pdes_error & pdes_cond)) {
4508 		    stsum = PJSNMP_ST_ERROR;
4509 		  }
4510 		}
4511 	      }
4512 
4513 	      /*	Build summary (3): status text line
4514 	      */
4515 	      if (16 == (16 & found)) {
4516 	        if ((0 != stat_always) || (PJSNMP_ST_UNKNOWN == stsum)) {
4517 		  if ((NULL != s_stn) && (NULL != i_stn)) {
4518 		    DK4_MEMRES(&tx, sizeof(tx));
4519 		    tx.text  = (unsigned char *)stat_text;
4520 		    tx.size  = sz_stat_text;
4521 		    tx.state = 0;
4522 		    tx.start = 0;
4523 		    ptx = (status_text_t *)dk4sto_it_find_like(i_stn, &tx, 1);
4524 		    if (NULL != ptx) {
4525 		      stsum = ptx->state;
4526 
4527 		    }
4528 		  }
4529 		}
4530 	      }
4531 
4532 	      /*	Build summary (4): Map unknown to busy if configured
4533 	      */
4534 	      if ((0 != unkn_busy) && (PJSNMP_ST_UNKNOWN == stsum)) {
4535 	        stsum = PJSNMP_ST_BUSY;
4536 	      }
4537 
4538 	      /*	For error state mark this page counter as print
4539 	      		job not yet finished.
4540 	      */
4541 	      switch (stsum) {
4542 	        case PJSNMP_ST_ERROR: {
4543 		  seen_printing = 0;
4544 		  if ((0 < passno) && (0UL < pcnt)) {
4545 		    pc_error = pcnt;
4546 		  }
4547 		  start_unreach = (dk4_time_t)0UL;
4548 		  if ((dk4_time_t)0UL == start_error) {
4549 		    dk4time_get(&start_error);
4550 		  }
4551 		} break;
4552 		case PJSNMP_ST_BUSY: {
4553 		  seen_printing = 1;
4554 		  start_unreach = (dk4_time_t)0UL;
4555 		  start_error   = (dk4_time_t)0UL;
4556 		} break;
4557 		case PJSNMP_ST_UNREACHABLE : {
4558 		  if ((dk4_time_t)0UL == start_unreach) {
4559 		    dk4time_get(&start_unreach);
4560 		  }
4561 		  start_error   = (dk4_time_t)0UL;
4562 		} break;
4563 		default : {
4564 		  start_unreach = (dk4_time_t)0UL;
4565 		  start_error   = (dk4_time_t)0UL;
4566 		} break;
4567 	      }
4568 
4569 	      /*	On change, print new state.
4570 	      */
4571 	      report_status_if_changed();
4572 
4573 	      /*	Save data for next comparison.
4574 	      */
4575 	      odevst = devst;
4576 	      oprist = prist;
4577 	      ostsum = stsum;
4578 	      opdes_cond = pdes_cond;
4579 	      if (0 < sz_stat_text) {
4580 	        DK4_MEMCPY(ostat_text, stat_text, sz_stat_text);
4581 	      }
4582 	      sz_ostat_text = sz_stat_text;
4583 	    }
4584 #if TRACE_DEBUG
4585 	    else {
4586 	    }
4587 #endif
4588 	  }
4589 #if TRACE_DEBUG
4590 	  else {
4591 	  }
4592 #endif
4593 	}
4594 #if TRACE_DEBUG
4595 	else {
4596 	}
4597 #endif
4598 	if (NULL != rs) {
4599 	  snmp_free_pdu(rs);
4600 	}
4601       }
4602 #if TRACE_DEBUG
4603       else {
4604       }
4605 #endif
4606     }
4607 #if TRACE_DEBUG
4608     else {
4609     }
4610 #endif
4611   }
4612 #if TRACE_DEBUG
4613   else {
4614   }
4615 #endif
4616 
4617   return back;
4618 }
4619 
4620 
4621 
4622 /**	Create accounting text line and do data exchange
4623 	with accounting system.
4624 	@param	kwind	Index of start keyword in pjsnmp_kw array.
4625 	@param	pc	Page counter value to transmit.
4626 */
4627 static
4628 void
accounting_index_and_value(size_t kwind,unsigned long pc)4629 accounting_index_and_value(size_t kwind, unsigned long pc)
4630 {
4631   char		 buf[64];			/* Buffer for number as text */
4632   const char	*jt;				/* Job title */
4633   size_t	 szbuf = sizeof(pjsnmp_buf);	/* Buffer size */
4634   size_t	 sl;
4635   int		 res;				/* Conversion result */
4636 
4637   res = dk4ma_write_c8_decimal_unsigned(
4638     buf, sizeof(buf), (dk4_um_t)pc, 0, NULL
4639   );
4640   if (0 != res) {
4641   if (0 != dk4str8_cpy_s(pjsnmp_buf, szbuf, pjsnmp_kw[kwind], NULL)) {
4642   if (0 != dk4str8_cat_s(pjsnmp_buf, szbuf, pjsnmp_kw[1], NULL)) {
4643   if (0 != dk4str8_cat_s(pjsnmp_buf, szbuf, queue_name, NULL)) {
4644   if (0 != dk4str8_cat_s(pjsnmp_buf, szbuf, pjsnmp_kw[1], NULL)) {
4645   if (0 != dk4str8_cat_s(pjsnmp_buf, szbuf, user_name, NULL)) {
4646   if (0 != dk4str8_cat_s(pjsnmp_buf, szbuf, pjsnmp_kw[1], NULL)) {
4647   if (0 != dk4str8_cat_s(pjsnmp_buf, szbuf, buf, NULL)) {
4648   if (0 != dk4str8_cat_s(pjsnmp_buf, szbuf, pjsnmp_kw[1], NULL)) {
4649   if (0 != dk4str8_cat_s(pjsnmp_buf, szbuf, job_name, NULL)) {
4650   if (0 != dk4str8_cat_s(pjsnmp_buf, szbuf, pjsnmp_kw[1], NULL)) {
4651   jt = job_title;
4652   if (NULL == jt) { jt = pjsnmp_kw[54]; }
4653   sl = strlen(pjsnmp_buf);
4654   if (0 != dk4str8_cat_s(pjsnmp_buf, szbuf, jt, NULL)) {
4655   if (0 == allow_non_ascii) { no_non_ascii(&(pjsnmp_buf[sl])); }
4656   if (0 != dk4str8_cat_s(pjsnmp_buf, szbuf, pjsnmp_kw[0], NULL)) {
4657 
4658     (void)accounting_exchange(0);
4659   }
4660   }
4661   }
4662   }
4663   }
4664   }
4665   }
4666   }
4667   }
4668   }
4669   }
4670   }
4671   }
4672 }
4673 
4674 
4675 /**	Report used pages to accounting system.
4676 */
4677 static
4678 void
report_used_pages(void)4679 report_used_pages(void)
4680 {
4681 
4682   if (0 != acct_start_end) {
4683     accounting_index_and_value(51, pc_start);
4684     accounting_index_and_value(52, pc_end);
4685   } else {
4686     accounting_index_and_value(53, (pc_end - pc_start));
4687   }
4688 
4689 }
4690 
4691 
4692 
4693 /**	Do accounting before and after print job.
4694 	@param	passno	0=before print job, 1=after print job.
4695 	@return	1 on success, 0 on error.
4696 */
4697 static
4698 int
do_accounting(int passno)4699 do_accounting(int passno)
4700 {
4701   static
4702   char		buf[8*sizeof(dk4_um_t)];		/* Number as text */
4703   struct timeval	to;				/* Timeout for select */
4704   dk4_time_t	start_idle	= (dk4_time_t)0UL;	/* Start idle/standby */
4705   dk4_time_t	current_time	= (dk4_time_t)0UL;	/* Current time */
4706   dk4_time_t	timeout_time	= (dk4_time_t)0UL;	/* Timeout reached */
4707   int			res	= 0;			/* Conversion result */
4708   int		 	back	= 0;
4709   int		 	cc	= 1;	/* Flag: Can continue */
4710   int			uncoi	= 0;	/* Flag: Unconditional  idle reported */
4711   int			cto	= 0;	/* Flag: Must check timeout */
4712 
4713   if (NULL != snmp_sess) {
4714     /*	In the loop retrieve printer status via SNMP,
4715 	finish if printer is idle or in standby state.
4716     */
4717     log_1_no_header((size_t)(145+passno));
4718     do {
4719       if (0 != can_continue(0)) {
4720         if (0 != one_snmp_request((0 == passno) ? 0 : 2)) {
4721 
4722 
4723 	  /*	In idle or standby we can retrieve the page counter
4724 	  	if the page counter was changed or the printer was seen
4725 		printing.
4726 	  */
4727 	  switch (stsum) {
4728 	    case PJSNMP_ST_IDLE : case PJSNMP_ST_STANDBY : {
4729 	      back = 1; cc = 0;
4730 	      cto = 0;
4731 	      if (1 == passno) {
4732 		if ((0 == seen_printing) && (0 < print_timeout)) {
4733 		  cto = 1;
4734 		} else {
4735 		  if ((0UL != pc_error) && (1 == have_pce)) {
4736 		    if ((pc_end == pc_error)&&((dk4_um_t)0UL < print_timeout)) {
4737 		      cto = 1;
4738 		    }
4739 		  }
4740 		}
4741 		if (0 != cto) {
4742 		  dk4time_get(&current_time);
4743 		  if ((dk4_time_t)0UL < start_idle) {
4744 		    if ((start_idle+(dk4_time_t)print_timeout) > current_time) {
4745 		      back = 0; cc = 1;
4746 		    }
4747 		  } else {
4748 		    start_idle = current_time;
4749 		    back = 0; cc = 1;
4750 		    if (0 == uncoi) {
4751 		      uncoi = 1;
4752 		      res = dk4ma_write_c8_decimal_unsigned(
4753 		        buf, sizeof(buf), print_timeout, 0, NULL
4754 		      );
4755 		      log_timestamp();
4756 		      fputs(pjsnmp_kw[162], out_file);
4757 		      if (0 != res) {
4758 		        fputs(buf, out_file);
4759 			fputs(pjsnmp_kw[163], out_file);
4760 		      }
4761 		      fputs(pjsnmp_kw[164], out_file);
4762 		      fflush(out_file);
4763 		    }
4764 		  }
4765 		}
4766 	      }
4767 	    } break;
4768 	    case PJSNMP_ST_UNREACHABLE : {
4769 	      start_idle  = (dk4_time_t)0UL;	/* not idle */
4770 	      uncoi = 0;
4771 	      /*	If printer is unreachable we abort after timeout.
4772 	      */
4773 	      if (((0 == passno) && ((dk4_um_t)0UL != unto_start))
4774 	          || ((1 == passno) && ((dk4_um_t)0UL != unto_end))
4775 	      )
4776 	      {
4777 	        if ((dk4_time_t)0UL < start_unreach) {
4778 	          dk4time_get(&current_time);
4779 		  timeout_time =
4780 		  start_unreach
4781 		  + (dk4_time_t)((0 == passno) ? unto_start : unto_end);
4782 		  if (current_time > timeout_time) {
4783 		    cc = 0;
4784 		    /* ERROR: Timeout while printer unreachable */
4785 		    log_1_no_header(136);
4786 		  }
4787 	        } else {
4788 	          dk4time_get(&start_unreach);
4789 	        }
4790 	      }
4791 	    } break;
4792 	    case PJSNMP_ST_ERROR : {
4793 	      start_idle    = (dk4_time_t)0UL;	/* not idle */
4794 	      uncoi = 0;
4795 	      if (
4796 	        ((0 == passno) && ((dk4_um_t)0UL < erto_start))
4797 		|| ((1 == passno) && ((dk4_um_t)0UL < erto_end))
4798 	      )
4799 	      {
4800 	        if ((dk4_time_t)0UL < start_error) {
4801 		  dk4time_get(&current_time);
4802 		  timeout_time =
4803 		  start_error
4804 		  + (dk4_time_t)((0 == passno) ? erto_start : erto_end);
4805 		  if (current_time > timeout_time) {
4806 		    cc = 0;
4807 		    /* ERROR: Timeout while printer in error state */
4808 		    log_1_no_header(168);
4809 		    if (0 == passno) {
4810 		      back = 0;		/* Do not print */
4811 		    }
4812 		  }
4813 		} else {
4814 		  dk4time_get(&start_error);
4815 		}
4816 	      }
4817 	    } break;
4818 	    default: {
4819 	      start_idle    = (dk4_time_t)0UL;	/* not idle */
4820 	      uncoi = 0;
4821 	    } break;
4822 	  }
4823 
4824 	  /*	Decrease cpu and network load from polling
4825 	  */
4826 	  if (1 == cc) {
4827 	    if (0 != can_continue(0)) {
4828 	      if (PJSNMP_ST_UNREACHABLE == stsum) {
4829 	        sleep(1);
4830 	      } else {
4831 	        to.tv_sec  = 0L;
4832 		to.tv_usec = 250000L;
4833 		(void)select(0, NULL, NULL, NULL, &to);
4834 	      }
4835 	    } else {
4836 	      cc = -1;
4837 	    }
4838 	  }
4839 
4840 	} else {
4841 	  cc = -1;
4842 	}
4843       } else {
4844         cc = -1;
4845       }
4846     } while(1 == cc);
4847     fputs(pjsnmp_kw[150], out_file);
4848     if (((0 == passno)&&(0 != have_pcs))||((1 == passno)&&(0 != have_pce))) {
4849 
4850       res = dk4ma_write_c8_decimal_unsigned(buf, sizeof(buf), pcnt, 0, NULL);
4851       if (0 != res) {
4852 
4853         log_3_no_header((size_t)(147+passno), 0, buf);
4854 
4855       }
4856 
4857     } else {
4858 
4859       log_1_no_header(149);
4860 
4861     }
4862 
4863     /*	Save page counter at start to page counter unusable for
4864 	print job finished.
4865     */
4866     if (0 == passno) {
4867       if (0 != have_pcs) {
4868         pc_error = pc_start;
4869       }
4870     }
4871     /*	After successful page counting at job end, report to
4872 	accounting system.
4873     */
4874     if (1 == passno) {
4875       if ((0 != have_pcs) && (0 != have_pce)) {
4876         if (pc_end > pc_start) {
4877           /* Report number of used pages to accounting system */
4878 	  report_used_pages();
4879 	}
4880       }
4881     }
4882   } else {
4883     if (0 != snmp_igfs) {
4884       back = 1;
4885     }
4886   }
4887   return back;
4888 }
4889 
4890 
4891 
4892 /**	Transfer data to printer.
4893 	@return	1 on success, 0 on error.
4894 */
4895 static
4896 int
data_transfer(void)4897 data_transfer(void)
4898 {
4899   fd_set		 wfds;		/* Writable files set */
4900   fd_set		 rfds;		/* Readable files set */
4901   struct timeval	 to;		/* Timeout for select */
4902   char			*wrptr;		/* Pointer to data to write */
4903   dk4_time_t		 unwriteable;	/* Socket started to be unwriteable */
4904   dk4_time_t		 current;	/* Current time */
4905   dk4_time_t		 tots;		/* Timestamp when timeout is reached */
4906   size_t		 rdb;		/* Number of bytes read from stdin */
4907   size_t		 remaining;	/* Remaining bytes to write to socket */
4908   size_t		 wrb;		/* Bytes currently written to socket */
4909   dk4_socket_t		 sock;		/* Network socket to printer */
4910   int			 back	= 0;
4911   int			 cc	= 1;	/* Flag: Can continue */
4912   int			 ccwr;		/* Flag: Can continue writing */
4913   int			 res;		/* Number conversion result */
4914   int			 writable;	/* Flag: Socket is writeable */
4915 
4916   unwriteable = (dk4_time_t)0UL;
4917   if ((NULL != host_name) && (0 < host_port)) {
4918     sock = dk4socket_c8_tcp_client_host_port(
4919       host_name, host_port, local_port, 0L, 0L, NULL
4920     );
4921     if (INVALID_SOCKET != sock) {
4922       exval = LPRNG_EXIT_SUCCESS;
4923       dk4time_get(&t2);
4924       back = 1;
4925       log_1_no_header(151);
4926       do {
4927         if (0 != can_continue(0)) {
4928 	  rdb = fread(pjsnmp_buf, 1, sizeof(pjsnmp_buf), stdin);
4929 	  if (0 < rdb) {
4930 	    wrptr     = pjsnmp_buf;
4931 	    remaining = rdb;
4932 	    ccwr = 1;
4933 	    do {
4934 	      if (0 != can_continue(0)) {
4935 	        writable = 0;
4936 		FD_ZERO(&wfds);
4937 		FD_SET(sock,&wfds);
4938 		if (0 != read_responses) {
4939 		  FD_ZERO(&rfds);
4940 		  FD_SET(sock,&rfds);
4941 		}
4942 		to.tv_sec = 0L;
4943 		to.tv_usec = 250000L;
4944 		if (0 != read_responses) {
4945 		  res = select((sock + 1), &rfds, &wfds, NULL, &to);
4946 		} else {
4947 		  res = select((sock + 1), NULL, &wfds, NULL, &to);
4948 		}
4949 		if (0 < res) {
4950 		  if (FD_ISSET(sock,&wfds)) {
4951 		    writable = 1;
4952 		    unwriteable = (dk4_time_t)0UL;
4953 		  } else {
4954 		    if (0 != unwt_print) {
4955 		      dk4time_get(&current);
4956 		      if ((dk4_time_t)0UL != unwriteable) {
4957 		        tots = unwriteable + (dk4_time_t)unwt_print;
4958 			if (current > tots) {
4959 			  cc = ccwr = -1;
4960 			  /* ERROR: Timeout, socket unwriteable */
4961 			  log_1_no_header(137);
4962 			}
4963 		      } else {
4964 		        unwriteable = current;
4965 		      }
4966 		    }
4967 		  }
4968 		  if (0 != read_responses) {
4969 		    if (FD_ISSET(sock,&rfds)) {
4970 		      wrb = sizeof(dummy_text);
4971 		      (void)dk4socket_recv(sock,dummy_text,&wrb,0,0L,0L,NULL);
4972 		    }
4973 		  }
4974 		}
4975 		if (0 != can_continue(0)) {
4976 		  if ((0 == writable) || (0 != check_trans)) {
4977 		    if (0 != one_snmp_request(1)) {
4978 		      switch (stsum) {
4979 		        case PJSNMP_ST_UNREACHABLE : {
4980 			  if ((dk4_um_t)0UL < unto_print) {
4981 			    if ((dk4_time_t)0UL < start_unreach) {
4982 			      tots = start_unreach + (dk4_time_t)unto_print;
4983 			      dk4time_get(&current);
4984 			      if (current > tots) {
4985 			        cc = ccwr = -1;
4986 			        /* ERROR: Timeout, printer start_unreach */
4987 			        log_1_no_header(136);
4988 			      }
4989 			    } else {
4990 			      dk4time_get(&start_unreach);
4991 			    }
4992 			  }
4993 			} break;
4994 			case PJSNMP_ST_ERROR : {
4995 			  if ((dk4_um_t)0UL < erto_print) {
4996 			    if ((dk4_time_t)0UL < start_error) {
4997 			      tots = start_error + (dk4_time_t)erto_print;
4998 			      dk4time_get(&current);
4999 			      if (current > tots) {
5000 			        cc = ccwr = -1;
5001 				/* ERROR: Timeout, printer start_unreach */
5002 				log_1_no_header(168);
5003 			      }
5004 			    } else {
5005 			      dk4time_get(&start_error);
5006 			    }
5007 			  }
5008 			} break;
5009 		      }
5010 		    }
5011 		  }
5012 		  if (0 != can_continue(0)) {
5013 	            wrb = remaining;
5014 		    res = dk4socket_send(sock, wrptr, &wrb, 0, 0L, 0L, NULL);
5015 		    switch (res) {
5016 		      case DK4_SOCKET_RESULT_SUCCESS:
5017 		      case DK4_SOCKET_RESULT_IN_PROGRESS :
5018 		      {
5019 		        if (0 < wrb) {
5020 			  bytes_trans = dk4ma_um_add(bytes_trans,wrb,&er_bytes);
5021 		          if (wrb < remaining) {
5022 		            remaining = remaining - wrb;
5023 			    wrptr = &(wrptr[wrb]);
5024 		          } else {
5025 		            remaining = 0;
5026 			    ccwr = 0;
5027 		          }
5028 		        }
5029 		      } break;
5030 		      default: {
5031 		        /* ERROR: Failed to send data */
5032 			log_1_no_header(138);
5033 		        ccwr = -1; cc = -1; back = 0;
5034 		      } break;
5035 		    }
5036 		  } else {
5037 		    ccwr = -1; cc = -1; back = 0;
5038 		  }
5039 		} else {
5040 		  ccwr = -1; cc = -1; back = 0;
5041 		}
5042 	      } else {
5043 	        ccwr = -1; cc = -1; back = 0;
5044 	      }
5045 	    } while (1 == ccwr);
5046 	  } else {
5047 	    have_eof = 1;
5048 	    cc = 0;
5049 	    if (0 != ferror(stdin)) {
5050 	      /* ERROR: Failed to read from standard input */
5051 	      log_1_no_header(139);
5052 	    }
5053 	  }
5054 	} else {
5055 	  cc = -1;
5056 	  back = 0;
5057 	}
5058       } while (1 == cc);
5059       log_1_no_header((0 == cc) ? 152 : 153);
5060       if (0 == cc) {
5061         if (0 != host_ordr) {
5062 	  res = dk4socket_shutdown(sock, DK4_SOCKET_SHUT_WRITE, NULL);
5063 	  if (DK4_SOCKET_RESULT_SUCCESS == res) {
5064 	    cc = 1;
5065 	    do {
5066 	      if (0 != can_continue(0)) {
5067 	        wrb = sizeof(pjsnmp_buf);
5068 		res = dk4socket_recv(sock, pjsnmp_buf, &wrb, 0, 0L, 0L, NULL);
5069 		switch (res) {
5070 		  case DK4_SOCKET_RESULT_SUCCESS: {
5071 		    if (0 == wrb) {
5072 		      cc = 0;
5073 		    }
5074 		  } break;
5075 		  default: {
5076 		    cc = -1;
5077 		  } break;
5078 		}
5079 	      } else {
5080 	        cc = -1;
5081 		back = 0;
5082 	      }
5083 	    } while (1 == cc);
5084 	  }
5085 	}
5086       }
5087       dk4socket_close(sock, NULL);
5088       dk4time_get(&t3);
5089     } else {
5090       /* ERROR: Failed to connect */
5091       log_1_no_header(140);
5092     }
5093   } else {
5094   }
5095 
5096   return back;
5097 }
5098 
5099 
5100 
5101 /**	Write one line of final statistics.
5102 	@param	b	Text containing a number.
5103 	@param	max	Maximum number width.
5104 	@param	i1	Index in pjsnmp_kw of text before number.
5105 	@param	i2	Index in pjsnmp_kw of text after number.
5106 */
5107 static
5108 void
final_stat_line(const char * b,size_t max,size_t i1,size_t i2)5109 final_stat_line(const char *b, size_t max, size_t i1, size_t i2)
5110 {
5111   size_t	sl;		/* String length of number */
5112 
5113   sl = strlen(b);
5114   fputs(pjsnmp_kw[i1], out_file);
5115   while (sl++ < max) { fputc(' ', out_file); }
5116   fputs(b, out_file);
5117   fputs(pjsnmp_kw[i2], out_file);
5118 }
5119 
5120 
5121 
5122 /**	Issue final statistics.
5123 */
5124 static
5125 void
final_statistics(void)5126 final_statistics(void)
5127 {
5128   char		b1[64];		/* Number of bytes */
5129   char		b2[64];		/* Transfer time */
5130   char		b3[64];		/* Processing time */
5131   char		b4[64];		/* Number of pages */
5132   size_t	max;		/* Maximum of all sizes */
5133   size_t	sl;		/* Current size */
5134   int		res;		/* Conversion result */
5135   int		found	= 0;	/* Information found */
5136 
5137   /*	Initialize buffers.
5138   */
5139   b1[0] = '\0'; b2[0] = '\0'; b3[0] = '\0'; b4[0] = '\0';
5140 
5141   /*	Convert numbers to strings.
5142   */
5143   if (DK4_E_NONE == er_bytes.ec) {
5144     res = dk4ma_write_c8_decimal_unsigned(
5145       b1, sizeof(b1), (dk4_um_t)bytes_trans, 0, NULL
5146     );
5147     if (0 == res) { b1[0] = '\0'; }
5148     else { found |= 1; }
5149   }
5150   if (((dk4_time_t)0UL != t2) && ((dk4_time_t)0UL != t3)) {
5151     res = dk4ma_write_c8_decimal_unsigned(
5152       b2, sizeof(b2), (dk4_um_t)(t3 - t2), 0, NULL
5153     );
5154     if (0 == res) { b2[0] = '\0'; }
5155     else { found |= 2; }
5156   }
5157   res = dk4ma_write_c8_decimal_unsigned(
5158     b3, sizeof(b3), (dk4_um_t)(t4 - t1), 0, NULL
5159   );
5160   if (0 == res) { b3[0] = '\0'; }
5161   else { found |= 4; }
5162   if ((0 != have_pcs) && (0 != have_pce)) {
5163     res = dk4ma_write_c8_decimal_unsigned(
5164       b4, sizeof(b4), (dk4_um_t)(pc_end - pc_start), 0, NULL
5165     );
5166     if (0 == res) { b4[0] = '\0'; }
5167     else { found |= 8; }
5168   }
5169 
5170   /*	Find maximum string length.
5171   */
5172   max = 0;
5173   if (0 != (1 & found)) {
5174     max = sl = strlen(b1);
5175   }
5176   if (0 != (2 & found)) {
5177     sl = strlen(b2);
5178     if (sl > max) max = sl;
5179   }
5180   if (0 != (4 & found)) {
5181     sl = strlen(b3);
5182     if (sl > max) max = sl;
5183   }
5184   if (0 != (8 & found)) {
5185     sl = strlen(b4);
5186     if (sl > max) max = sl;
5187   }
5188 
5189   /*	Write texts.
5190   */
5191   fputs(pjsnmp_kw[55], out_file);
5192   (void)log_timestamp();
5193   if (0 != (1 & found)) {
5194     final_stat_line(b1, max, 56, 60);
5195   }
5196   if (0 != (2 & found)) {
5197     final_stat_line(b2, max, 57, 61);
5198   }
5199   if (0 != (4 & found)) {
5200     final_stat_line(b3, max, 58, 61);
5201   }
5202   if (0 != (8 & found)) {
5203     final_stat_line(b4, max, 59, 0);
5204   }
5205   if (0 != found) {
5206     fflush(out_file);
5207   }
5208 }
5209 
5210 
5211 
5212 /**	Initialization at startup.
5213 */
5214 static
5215 void
initialize_at_startup(void)5216 initialize_at_startup(void)
5217 {
5218   stat_text[0] = '\0';	sz_stat_text = 0;
5219   ostat_text[0] = '\0';	sz_ostat_text = 0;
5220   dk4error_init(&er_bytes);
5221 }
5222 
5223 
5224 
5225 static
5226 void
report_at_job_start(int argc,char * argv[])5227 report_at_job_start(int argc, char *argv[])
5228 {
5229   int		 found	= 0;
5230   char		*ptr;
5231   if (0 != verbose) {
5232     int i;
5233     fputs(pjsnmp_kw[169], out_file);
5234     for (i = 1; i < argc; i++) {
5235       fputs(argv[i], out_file);
5236       fputc('\n', out_file);
5237     }
5238     fflush(out_file);
5239   } else {
5240     if (NULL != user_name) {
5241       fputs(user_name, out_file);
5242       found = 1;
5243     }
5244     if (NULL != queue_name) {
5245       if (0 != found) { fputc(' ', out_file); }
5246       fputs(queue_name, out_file);
5247       found = 1;
5248     }
5249     if (NULL != job_name) {
5250       if (0 != found) { fputc(' ', out_file); }
5251       fputs(job_name, out_file);
5252       found = 1;
5253     }
5254     if (0 != found) { fputc('\n', out_file); }
5255     if (NULL != job_title) {
5256       ptr = job_title;
5257       while ('\0' != *ptr) {
5258         if (0x80 > ((unsigned char)(*ptr))) {
5259 	  fputc(*ptr, out_file);
5260 	} else {
5261 	  fputc('?', out_file);
5262 	}
5263         ptr++;
5264       }
5265       fputc('\n', out_file);
5266       found = 1;
5267     }
5268     if (0 != found) {
5269       fflush(out_file);
5270     }
5271   }
5272 }
5273 
5274 
5275 
5276 
5277 #endif
5278 /* if DK4_HAVE_LIBNETSNMP && ((DK4_HAVE_SIGACTION) || (DK4_HAVE_SIGSET)) */
5279 
5280 
5281 
5282 /**	Main program.
5283 	@param	argc	Number of command line arguments.
5284 	@param	argv	Command line arguments array.
5285 	@return	Exit status code, one from LPRNG_EXIT_xxx.
5286 */
5287 int
main(int argc,char * argv[])5288 main(int argc, char *argv[])
5289 {
5290 #if DK4_HAVE_LIBNETSNMP && ((DK4_HAVE_SIGACTION) || (DK4_HAVE_SIGSET))
5291 
5292   /* +++++ All libraries available */
5293 
5294 #if DK4_HAVE_SIGACTION
5295 #ifdef SIGPIPE
5296   struct sigaction	opipe;		/* Old disposition for SIGPIPE */
5297   struct sigaction	npipe;		/* New disposition for SIGPIPE */
5298 #endif
5299   struct sigaction	oint;		/* Old disposition for SIGINT */
5300   struct sigaction	nint;		/* New disposition for SIGINT */
5301   struct sigaction	oterm;		/* Old disposition for SIGTERM */
5302   struct sigaction	nterm;		/* New disposition for SIGTERM */
5303 #else
5304 #ifdef SIGPIPE
5305   dk4_sig_handler_t	*opipe	= NULL;	/* Old disposition for SIGPIPE */
5306 #endif
5307   dk4_sig_handler_t	*oterm	= NULL;	/* Old disposition for SIGTERM */
5308   dk4_sig_handler_t	*oint	= NULL;	/* Old disposition for SIGINT */
5309 #endif
5310 
5311 #if DK4_HAVE_SIGACTION
5312 #ifdef SIGPIPE
5313   int			set_pipe = 0;	/* Flag: Disposition SIGPIPE changed */
5314 #endif
5315   int			set_int	 = 0;	/* Flag: Disposition SIGINT changed */
5316   int			set_term = 0;	/* Flag: Disposition SIGTERM changed */
5317   int			sig_i_f	 = 0;	/* Flag: Handler installation failed */
5318   int			sig_r_f	 = 0;	/* Flag: Handler restoration failed */
5319 #endif
5320   int			sockinit = 0;	/* Flag: Socket subsys initialized */
5321 
5322 
5323 
5324 
5325   /*	Initialize output file.
5326   */
5327   out_file = stderr;
5328   dk4time_get(&t1);
5329 
5330   /*	Copy default OID for status text.
5331   */
5332   DK4_MEMCPY(oid_st, oid_dst, by_oid_dst);
5333   sz_oid_st = sz_oid_dst;
5334   by_oid_st = sz_oid_st * sizeof(oid);
5335 
5336   /*	Process command line arguments, open log file.
5337   */
5338   if (0 == process_command_line_arguments(argc, argv))	{ goto finished; }
5339 
5340   /*	Set up signal handlers.
5341   */
5342 #if DK4_HAVE_SIGACTION
5343 #ifdef SIGPIPE
5344   DK4_MEMRES(&npipe, sizeof(npipe));
5345   npipe.sa_handler = sig_handler_pipe;
5346   npipe.sa_flags = 0;
5347   if (0 != sigemptyset(&npipe.sa_mask))		{ sig_i_f = 1; goto finished; }
5348   if (0 != sigaddset(&npipe.sa_mask, SIGPIPE))	{ sig_i_f = 1; goto finished; }
5349   if (0 != sigaction(SIGPIPE, &npipe, &opipe))	{ sig_i_f = 1; goto finished; }
5350   set_pipe = 1;
5351 #endif
5352   DK4_MEMRES(&nterm, sizeof(nterm));
5353   nterm.sa_handler = sig_handler_term;
5354   nterm.sa_flags = 0;
5355   if (0 != sigemptyset(&nterm.sa_mask))		{ sig_i_f = 1; goto finished; }
5356   if (0 != sigaddset(&nterm.sa_mask, SIGTERM))	{ sig_i_f = 1; goto finished; }
5357   if (0 != sigaction(SIGTERM, &nterm, &oterm))	{ sig_i_f = 1; goto finished; }
5358   set_term = 1;
5359   DK4_MEMRES(&nint, sizeof(nint));
5360   nint.sa_handler = sig_handler_int;
5361   nint.sa_flags = 0;
5362   if (0 != sigemptyset(&nint.sa_mask))		{ sig_i_f = 1; goto finished; }
5363   if (0 != sigaddset(&nint.sa_mask, SIGINT))	{ sig_i_f = 1; goto finished; }
5364   if (0 != sigaction(SIGINT, &nint, &oint))	{ sig_i_f = 1; goto finished; }
5365   set_int = 1;
5366 #else
5367 #ifdef SIGPIPE
5368   opipe = sigset(SIGPIPE, sig_handler_pipe);
5369 #endif
5370   oint  = sigset(SIGINT,  sig_handler_int);
5371   oterm = sigset(SIGTERM, sig_handler_term);
5372 #endif
5373 
5374   /*	Process remaining setup (PRINTCAP_ENTRY, model file).
5375   */
5376   if (0 == process_setup())		{ goto finished; }
5377 
5378   /*	Header files for job in log output.
5379   */
5380   report_at_job_start(argc, argv);
5381 
5382   /*	Initialize socket subsystem.
5383   */
5384   if (DK4_SOCKET_RESULT_SUCCESS != dk4socket_up(NULL)) {
5385     log_1_no_header(170);
5386     goto finished;
5387   }
5388   sockinit = 1;
5389 
5390   /*	Check users permission to print.
5391   */
5392   if (0 == check_permission())		{ goto finished; }
5393 
5394   /*	Establish SNMP session.
5395   */
5396   if (0 == attempt_snmp_session())	{ goto finished; }
5397 
5398   /*	Initialization.
5399   */
5400   initialize_at_startup();
5401 
5402   /*	Accounting before job.
5403   */
5404   if (0 == do_accounting(0))		{ goto finished; }
5405 
5406   /*	Data transfer.
5407   */
5408   if (0 == data_transfer())		{ goto finished; }
5409 
5410   /*	Accounting after job.
5411   */
5412   if (0 == do_accounting(1))		{ goto finished; }
5413 
5414   /*	Cleanup
5415 	-------
5416   */
5417   finished:
5418 
5419   /*	Clean up SNMP session.
5420   */
5421   if (NULL != snmp_sess)	{ snmp_close(snmp_sess); }
5422 
5423   /*	Eat up data from standard input.
5424   */
5425   eatup_input();
5426 
5427   /*	release socket subsystem.
5428   */
5429   if (0 != sockinit)		{ (void)dk4socket_down(NULL); }
5430 
5431   /*	Release status text nodes, if any.
5432   */
5433   relase_status_text_nodes();
5434 
5435   /*	Release dynamically allocated printcap entry copy.
5436   */
5437   dk4mem_release(printcap_entry);
5438 
5439   /*	Restore signal handlers
5440   */
5441 #if DK4_HAVE_SIGACTION
5442   if (0 != sig_i_f) {
5443     /* ERROR: Failed to set up signal handlers */
5444     log_1_no_header(141);
5445   }
5446   if (0 != set_int) {
5447     if (0 != sigaction(SIGINT, &oint, NULL))	{ sig_r_f = 1; }
5448   }
5449   if (0 != set_term) {
5450     if (0 != sigaction(SIGTERM, &oterm, NULL))	{ sig_r_f = 1; }
5451   }
5452 #ifdef SIGPIPE
5453   if (0 != set_pipe) {
5454     if (0 != sigaction(SIGPIPE, &opipe, NULL))	{ sig_r_f = 1; }
5455   }
5456 #endif
5457   if (0 != sig_r_f) {
5458     /* ERROR: Failed to restore signal handlers */
5459     log_1_no_header(142);
5460   }
5461 #else
5462   if (NULL != oterm)	{ sigset(SIGTERM, oterm); }
5463   if (NULL != oint )	{ sigset(SIGINT,  oint ); }
5464 #ifdef SIGPIPE
5465   if (NULL != opipe)	{ sigset(SIGPIPE, opipe); }
5466 #endif
5467 #endif
5468 
5469   /*	Final log message, close log file
5470   */
5471   dk4time_get(&t4);
5472   if (2 > decision) { final_statistics(); }
5473   if (NULL != stt_file)	{ fclose(stt_file); }
5474   out_file = stderr;
5475 
5476 
5477 
5478 
5479   /* ----- All libraries available */
5480 
5481 #else
5482 /* if DK4_HAVE_LIBNETSNMP && ((DK4_HAVE_SIGACTION) || (DK4_HAVE_SIGSET)) */
5483   /* +++++ Missing libraries */
5484 #if !DK4_HAVE_LIBNETSNMP
5485   fputs("ERROR: Missing Net-SNMP support!\n", stderr);
5486 #endif
5487 #if !((DK4_HAVE_SIGACTION) || (DK4_HAVE_SIGSET))
5488   fputs("ERROR: Missing sigaction()/sigset() support!\n", stderr);
5489 #endif
5490   fflush(stderr);
5491   /* ----- Missing libraries */
5492 #endif
5493 /* if DK4_HAVE_LIBNETSNMP && ((DK4_HAVE_SIGACTION) || (DK4_HAVE_SIGSET)) */
5494   exit(exval); return exval;
5495 }
5496 
5497 
5498 /*
5499 
5500 2016-02-26	Added dk4socket_up() and dk4socket_down().
5501 
5502 */
5503