/* WARNING: This file was generated by dkct. Changes you make here will be lost if dkct is run again! You should modify the original source and run dkct on it. Original source: pjsnmp.ctr */ /* Copyright (C) 2012-2013, Dirk Krause Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above opyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @file pjsnmp.c The pjsnmp module. */ #line 207 "pjsnmp.ctr" #include "dk3conf.h" #include "dk3types.h" #if DK3_CHAR_SIZE == 1 #if DK3_HAVE_SIGSET #if DK3_HAVE_LIBNETSNMP #include "dk3all.h" #include #include #include #include "printqd.h" #include "pjsnmp.h" #line 225 "pjsnmp.ctr" /** Constant keywords used by the module, not localized. */ static char const * const pjsnmp_kw[] = { /* 0 */ "dkt-3", /* 1 */ "pjsnmp.str", /* 2 */ "PRINTCAP_ENTRY", /* 3 */ "acct-check", /* 4 */ "jobstart", /* 5 */ " ", /* 6 */ "\n", /* 7 */ "'", /* 8 */ "'-P", /* 9 */ "'-n", /* 10 */ "pjsnmp", /* 11 */ "public", /* 12 */ "w", /* 13 */ "a", /* 14 */ "filestart", /* 15 */ "fileend", /* 16 */ "acct-start", /* 17 */ "acct-end", /* 18 */ "%lu", /* 19 */ "'-p", /* 20 */ "'-A", /* 21 */ "'-J", /* 22 */ "wb", /* 23 */ "rb", /* 24 */ "%d", /* 25 */ "%u", /* 26 */ "pjsnmp-%lu.dat", /* 27 */ "pjsnmp-%lu.log", /* 28 */ "# %04d-%02d-%02d %02d:%02d:%02d\n", NULL #line 349 "pjsnmp.ctr" }; /** Expected responses from accounting check. */ static char const * const pjsnmp_achk_responses[] = { /* 0 */ "ACCEPT", /* 1 */ "REMOVE", /* 2 */ "HOLD", NULL #line 361 "pjsnmp.ctr" }; /** Keys in printcap entry. */ static char const * const pjsnmp_printcap_entries[] = { /* 0 */ "pjsnmpaf", /* 1 */ "pjsnmpachk", /* 2 */ "pjsnmphost", /* 3 */ "pjsnmpport", /* 4 */ "pjsnmpvers", /* 5 */ "pjsnmpcomm", /* 6 */ "pjsnmpacst", /* 7 */ "pjsnmpordr", /* 8 */ "pjsnmpscdt", /* 9 */ "pjsnmpigsf", /* 10 */ "pjsnmppdes", /* 11 */ "pjsnmppoid", /* 12 */ "pjsnmpresp", NULL #line 395 "pjsnmp.ctr" }; /** Localized message texts. The texts here are used as defaults if the localized message texts are not found. */ static char const * const pjsnmp_loc[] = { /* 0 */ "Printer ready.", /* 1 */ "Printer warming up.", /* 2 */ "Printing.", /* 3 */ "Waiting for printer to start printing.", /* 4 */ "ERROR ON PRINTER, INVERVENTION REQUIRED! (OUT OF PAPER, PAPER JAM...)", /* 5 */ "UNKNOWN PRINTER STATE. IF IN STANDBY, PLEASE WAKE UP MANUALLY.", /* 6 */ "PRINTER DOES NOT RESPOND! PLEASE POWER-ON PRINTER!", /* 7 */ "ERROR: Failed to create SNMP request!", /* 8 */ "ERROR: Invalid SNMP response from printer!", /* 9 */ "SNMP response: ", /* 10 */ "device=0, ", /* 11 */ "device=unknown (1), ", /* 12 */ "device=running (2), ", /* 13 */ "device=warning (3), ", /* 14 */ "device=testing (4), ", /* 15 */ "device=down (5), ", /* 16 */ "printer=0.", /* 17 */ "printer=other (1).", /* 18 */ "printer=unknown (2).", /* 19 */ "printer=idle (3).", /* 20 */ "printer=printing (4).", /* 21 */ "printer=warmup (5).", /* 22 */ "PRINTER ERROR CONDITION: OUT OF PAPER!", /* 23 */ "Printer condition resolved: Paper now available.", /* 24 */ "Printer warning condition: Paper low.", /* 25 */ "Printer condition resolved: No longer paper low.", /* 26 */ "PRINTER ERROR CONDITION: OUT OF TONER!", /* 27 */ "Printer condition solved: Toner available.", /* 28 */ "Printer warning condition: Toner low.", /* 29 */ "Printer condition resolved: No longer toner low.", /* 30 */ "PRINTER ERROR CONDITION: OUTPUT TRAY FULL!", /* 31 */ "Error condition resolved: Output tray no longer full.", /* 32 */ "Printer warning condition: Output tray nearly full!", /* 33 */ "Error condition resolved: Output tray no longer nearly full.", /* 34 */ "PRINTER ERROR CONDITION: DOOR OPEN!", /* 35 */ "Error condition resolved: Door now closed.", /* 36 */ "PRINTER ERROR CONDITION: PAPER JAM!", /* 37 */ "Error condition resolved: No longer paper jam.", /* 38 */ "PRINTER ERROR CONDITION: OFFLINE FOR SOME REASON!", /* 39 */ "Error condition resolved: No longer offline.", /* 40 */ "PRINTER ERROR CONDITION: SERVICE REQUESTED!", /* 41 */ "Error condition resolved: Service no longer requested.", /* 42 */ "PRINTER ERROR CONDITION: INPUT TRAY MISSING!", /* 43 */ "Error condition resolved: Input tray now available.", /* 44 */ "PRINTER ERROR CONDITION: OUTPUT TRAY MISSING!", /* 45 */ "Error condition resolved: Output tray now available.", /* 46 */ "PRINTER ERROR CONDITION: MARKER SUPPLY MISSING!", /* 47 */ "Error condition resolved: Marker supply now available.", /* 48 */ "PRINTER ERROR CONDITION: INPUT TRAY EMPTY!", /* 49 */ "Error condition resolved: Input tray no longer empty.", /* 50 */ "PRINTER ERROR CONDITION: OVERDUE PREVENTIVE MAINTENANCE!", /* 51 */ "Error condition resolved: No longer overdue preventive maintenance.", /* 52 */ "Error: Configuration entry \"", /* 53 */ "\" needs an argument!", /* 54 */ "Print job finished, errors occured!", /* 55 */ "Print job finished successfully.", /* 56 */ "Print job finished successfully, ", /* 57 */ " page(s).", /* 58 */ "Print job cancelled by signal!", /* 59 */ "ERROR: PRINTCAP_ENTRY environment variable not found!", /* 60 */ "ERROR: Insufficient memory!", /* 61 */ "ERROR: Missing host name for printer (not configured)!", /* 62 */ "ERROR: Missing port number for printer (not configured)!", /* 63 */ "ERROR: Illegal accounting style in configuration: \"", /* 64 */ "\"!", /* 65 */ "ERROR: Illegal SNMP version in configuration: \"", /* 66 */ "\"!", /* 67 */ "ERROR: Illegal port number in configuration (not a number): \"", /* 68 */ "\"!", /* 69 */ "ERROR: Illegal port number in configuration (overflow): \"", /* 70 */ "\"!", /* 71 */ "ERROR: Failed to save standard input to temporary file!", /* 72 */ "ERROR: Failed to open SNMP session!", /* 73 */ "Warning: Failed to open SNMP session!", /* 74 */ "ERROR: Failed to open temporary data file!", /* 75 */ "ERROR: Failed to open printer connection!", /* 76 */ "ERROR: Attempt to send data failed!", /* 77 */ "ERROR: Failed to create SNMP request PDU! Resources shortage!", /* 78 */ "ERROR: Accounting request grows too large!", /* 79 */ "ERROR: Failed to find user name for current print job!", /* 80 */ "ERROR: Failed to find queue name for current print job!", /* 81 */ "ERROR: Accounting file is not a UNIX domain socket!", /* 82 */ "ERROR: No permission to use this printer!", /* 83 */ "ERROR: Failed to connect to accounting socket!", /* 84 */ "ERROR: Failed to send accounting data to socket!", /* 85 */ "ERROR: Failed to shut down accounting socket!", /* 86 */ "Page counter at job start: ", /* 87 */ "Page counter at job end: ", /* 88 */ "Printer reponse:", NULL #line 756 "pjsnmp.ctr" }; /** SNMP versions handled by pjsnmp. */ static char const * const pjsnmp_snmp_versions[] = { "1", "2c", "2p", "3", NULL }; /** Accounting styles supported by pjsnmp. */ static char const * const pjsnmp_accounting_styles[] = { "printqd", "lprng", NULL }; /** OID for device status. */ static oid pjsnmp_oid_ds[MAX_OID_LEN] = { (oid)1, (oid)3, (oid)6, (oid)1, (oid)2, (oid)1, (oid)25, (oid)3, (oid)2, (oid)1, (oid)5, (oid)1 }; /** Size of device status OID. */ static size_t const pjsnmp_sz_oid_ds = 12; /** OID for printer status. */ static oid pjsnmp_oid_ps[MAX_OID_LEN] = { (oid)1, (oid)3, (oid)6, (oid)1, (oid)2, (oid)1, (oid)25, (oid)3, (oid)5, (oid)1, (oid)1, (oid)1 }; /** Size of printer status OID. */ static size_t const pjsnmp_sz_oid_ps = 12; /** OID for pagecount value. */ static oid pjsnmp_oid_pc[MAX_OID_LEN] = { (oid)1, (oid)3, (oid)6, (oid)1, (oid)2, (oid)1, (oid)43, (oid)10, (oid)2, (oid)1, (oid)4, (oid)1, (oid)1 }; /** Size of page counter OID. */ static size_t const pjsnmp_sz_oid_pc = 13; /** Printer error OID. */ static oid pjsnmp_oid_pe[MAX_OID_LEN] = { (oid)1, (oid)3, (oid)6, (oid)1, (oid)2, (oid)1, (oid)25, (oid)3, (oid)5, (oid)1, (oid)2, (oid)1 }; /** Size of printer error OID. */ static size_t const pjsnmp_sz_oid_pe = 12; /** Bits within a bit starting on the left side. */ static unsigned char const pjsnmp_bits[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; /** Error conditions to report as warning only (from hrPrinterDetectedErrorState). */ static unsigned long const pjsnmp_warning_only = DK3_SNMP_PRINTER_ERROR_LOW_PAPER | DK3_SNMP_PRINTER_ERROR_LOW_TONER | DK3_SNMP_PRINTER_ERROR_OUTPUT_NEAR ; /** Flag: SIGINT signal was found. */ static DK3_VOLATILE dk3_sig_atomic_t pjsnmp_sigint_received = 0; /** Handler for signal SIGINT. @param signo Signal number. */ static void pjsnmp_sigint_handler(int signo) { pjsnmp_sigint_received = 1; } /** Flag: SIGTERM signal was found. */ static DK3_VOLATILE dk3_sig_atomic_t pjsnmp_sigterm_received = 0; /** Handler for signal SIGTERM. @param signo Signal number. */ static void pjsnmp_sigterm_handler(int signo) { pjsnmp_sigterm_received = 1; } /** Flag: SIGPIPE signal was found. */ static DK3_VOLATILE dk3_sig_atomic_t pjsnmp_sigpipe_received = 0; /** Handler for signal SIGPIPE. @param signo Signal number. */ static void pjsnmp_sigpipe_handler(int signo) { pjsnmp_sigpipe_received = 1; } /** Log a message consisting of multiple parts. @param job Job structure. @param msg Message texts array. @param nmsg Size of array. */ static void pjsnmp_log_multi(pjsnmp_job_t *job, char const * const *msg, size_t nmsg) { FILE *fipo; char const * const *ptr; struct tm *tm; size_t i; time_t ct; if(job->sf) { fipo = dk3sf_fopen_app(job->sf, pjsnmp_kw[(job->hl) ? 13 : 12 ], job->app); if(fipo) { time(&ct); if(ct != job->tl) { tm = localtime(&ct); if(tm) { job->tl = ct; fprintf( fipo, pjsnmp_kw[28], (1900 + tm->tm_year), (1 + tm->tm_mon), tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec ); } } ptr = msg; for(i = 0; i < nmsg; i++) { fputs(*(ptr++), fipo); } fputc('\n', fipo); fclose(fipo); job->hl = 1; } } } /** Log message consisting of 1 part. @param job Job structure. @param m1 Message part 1. */ static void pjsnmp_log_1(pjsnmp_job_t *job, char const *m1) { char const *msg[2]; msg[0] = m1; msg[1] = NULL; pjsnmp_log_multi(job, msg, 1); } /** Log message consisting of 2 parts. @param job Job structure. @param m1 Message part 1. @param m2 Message part 2. */ static void pjsnmp_log_2(pjsnmp_job_t *job, char const *m1, char const *m2) { char const *msg[3]; msg[0] = m1; msg[1] = m2; msg[2] = NULL; pjsnmp_log_multi(job, msg, 2); } /** Log message consisting of 3 parts. @param job Job structure. @param m1 Message part 1. @param m2 Message part 2. @param m3 Message part 3. */ static void pjsnmp_log_3(pjsnmp_job_t *job, char const *m1, char const *m2, char const *m3) { char const *msg[4]; msg[0] = m1; msg[1] = m2; msg[2] = m3; msg[3] = NULL; pjsnmp_log_multi(job, msg, 3); } /** Check whether or not we can continue. On signal or unrecoverable errors we give up. @param job Job structure. @param fe Flag: Take fe component into account. @return 1 to continue normally, 0 to exit. */ static int pjsnmp_cc(pjsnmp_job_t *job, int fe) { int back = 1; #line 991 "pjsnmp.ctr" if(pjsnmp_sigterm_received) { #line 992 "pjsnmp.ctr" back = 0; } else { if(pjsnmp_sigint_received) { #line 995 "pjsnmp.ctr" back = 0; } else { if(job) { if((fe) && (job->fe)) { #line 999 "pjsnmp.ctr" back = 0; } } } } #line 1005 "pjsnmp.ctr" return back; } /** Initialize printer state structure. @param s Structure to initialize. */ static void pjsnmp_state_init(pjsnmp_printer_state_t *s) { dk3mem_res((void *)s, sizeof(pjsnmp_printer_state_t)); s->pc = 0UL; s->ec = 0UL; s->ds = 0; s->ps = 0; s->st = 0; } /** Eat up input on errors, so no SIGPIPE signal is sent to LPRng. */ static void pjsnmp_eat_input(pjsnmp_job_t *job) { char bu[4096]; size_t sz; #line 1032 "pjsnmp.ctr" do { sz = dk3sf_read_app(0, bu, sizeof(bu), NULL); } while((sz > 0) && (pjsnmp_cc(job,0))); #line 1036 "pjsnmp.ctr" } /** Initialize job structure. @param job Job structure to initialize. */ static void pjsnmp_job_init(pjsnmp_job_t *job) { #line 1048 "pjsnmp.ctr" dk3mem_res((void *)job, sizeof(pjsnmp_job_t)); job->ss = NULL; job->un = NULL; job->qn = NULL; job->jn = NULL; job->jt = NULL; job->app = NULL; job->lm = NULL; job->hn = NULL; job->af = NULL; job->sc = NULL; job->tf = NULL; job->sl = NULL; job->ti = (time_t)0UL; job->tl = (time_t)0UL; job->pc = 0UL; job->sf = NULL; job->ex = PJSNMP_EXIT_FAIL; job->ac = 0; job->as = 0; job->sv = 0; job->od = 0; job->fe = 0; job->pn = 9100; job->ct = 0; job->is = 0; job->wp = 0; job->hl = 0; job->pdes = 1; job->poid = 1; job->repr = 0; #line 1080 "pjsnmp.ctr" } /** Clean up job structure. @param job Job structure to clean up. */ static void pjsnmp_job_cleanup(pjsnmp_job_t *job) { #line 1092 "pjsnmp.ctr" if(job->sl) { #line 1093 "pjsnmp.ctr" dk3sf_c8_remove_file_app(job->sl, job->app); dk3_release(job->sl) } if(job->tf) { #line 1097 "pjsnmp.ctr" dk3sf_c8_remove_file_app(job->tf, job->app); dk3_release(job->tf) } if(job->app) { #line 1101 "pjsnmp.ctr" dk3app_close(job->app); job->app = NULL; } #line 1103 "pjsnmp.ctr" } /** Check two OIDs for equality. @param o1 Left OID. @param sz1 Left OID size. @param o2 Right OID. @param sz2 Right OID size. @return 1 if the OIDs are equal, 0 otherwise. */ static int pjsnmp_oids_equal(oid const *o1, size_t sz1, oid const *o2, size_t sz2) { oid const *p1; oid const *p2; size_t i; int back = 0; #line 1123 "pjsnmp.ctr" if(sz1 == sz2) { back = 1; p1 = o1; p2 = o2; for(i = 0; ((i < sz1) && (back)); i++) { if(*(p1++) != *(p2++)) { back = 0; } } } #line 1132 "pjsnmp.ctr" return back; } /** Apply command line arguments to job structure. @param job Job structure. */ static void pjsnmp_apply_command_line_arguments(pjsnmp_job_t *job) { char const *upper[26]; /* Upper case option arguments. */ char const *lower[26]; /* Lower case option arguments. */ char const * const *xargv; /* Command line arguments array. */ char const *ptr; /* Current argument. */ int i; /* Current argument index. */ int xargc; /* Number of command line arguments. */ #line 1151 "pjsnmp.ctr" for(i = 0; i < 26; i++) { upper[i] = NULL; lower[i] = NULL; } xargc = dk3app_get_argc(job->app); xargv = dk3app_get_argv(job->app); for(i = 1; i < xargc; i++) { ptr = xargv[i]; #line 1156 "pjsnmp.ctr" if(ptr[0] == '-') { if(('a' <= ptr[1]) && ('z' >= ptr[1])) { lower[ptr[1] - 'a'] = &(ptr[2]); } else { if(('A' <= ptr[1]) && ('Z' >= ptr[1])) { upper[ptr[1] - 'A'] = &(ptr[2]); } } } } job->un = lower['n' - 'a']; if(!(job->un)) { job->un = upper['L' - 'A']; } job->qn = upper['P' - 'A']; if(!(job->qn)) { job->qn = upper['Q' - 'A']; } job->jn = upper[0]; if(!(job->jn)) { job->jn = lower['j' - 'a']; } if(!(job->jn)) { job->jn = lower['t' - 'a']; } if(!(job->jn)) { job->jn = upper['D' - 'A']; } job->jt = upper['J' - 'A']; if(!(job->jt)) { job->jt = lower['f' - 'a']; } if(!(job->jt)) { job->jt = upper['N' - 'A']; } if(!(job->jt)) { job->jt = job->jn; } job->sf = lower['s' - 'a']; #line 1180 "pjsnmp.ctr" #line 1181 "pjsnmp.ctr" #line 1182 "pjsnmp.ctr" #line 1183 "pjsnmp.ctr" #line 1184 "pjsnmp.ctr" #line 1185 "pjsnmp.ctr" } /** Read standard input to temporary file. @param job Job structure. @return 1 on success, 0 on error. */ static int pjsnmp_read_standard_input(pjsnmp_job_t *job) { char bu[4096]; /* Buffer. */ FILE *fipo; /* Temporary file to write. */ size_t rb; /* Number of bytes read. */ int back = 0; #line 1202 "pjsnmp.ctr" fipo = dk3sf_fopen_app(job->tf, pjsnmp_kw[22], job->app); if(fipo) { #line 1204 "pjsnmp.ctr" back = 1; do { rb = dk3sf_read_app(0, (void *)bu, sizeof(bu), job->app); if(0 < rb) { #line 1208 "pjsnmp.ctr" if((back) && (pjsnmp_cc(job, 0))) { if(!dk3sf_fwrite_app(bu, 1, rb, fipo, job->app)) { #line 1210 "pjsnmp.ctr" back = 0; } } } } while((0 < rb) && (pjsnmp_cc(job, 0))); if(!dk3sf_fclose_fn_app(fipo, job->tf, job->app)) { #line 1216 "pjsnmp.ctr" back = 0; } } else { #line 1219 "pjsnmp.ctr" pjsnmp_eat_input(job); } #line 1221 "pjsnmp.ctr" return back; } /** Check whether the accounting file exists and is a socket. @param job Job structure. @return 1 if the accounting file is a UNIX domain socket, 0 otherwise. */ static int pjsnmp_is_socket(pjsnmp_job_t *job) { struct stat stb; int back = 0; #line 1238 "pjsnmp.ctr" if(0 == stat(job->af, &stb)) { if(((stb.st_mode) & S_IFMT) == S_IFSOCK) { back = 1; } } #line 1243 "pjsnmp.ctr" return back; } /** Run accounting dialog with server socket. @param job Job structure. @param rq Request to send to server. @param rs Response buffer. @param szrs Size of response buffer. @return 1 on success, 0 on error. */ static int pjsnmp_accounting_dialog( pjsnmp_job_t *job, char const *rq, char *rs, size_t szrs ) { char bu[PQD_OUTPUT_BUFFER_SIZE]; /* Response buffer. */ size_t sl; /* Request string length. */ dk3_socket_t sock; /* Socket. */ int wb; /* Bytes written/read. */ int back = 0; #line 1270 "pjsnmp.ctr" if(rs) { *rs = '\0'; } sl = strlen(rq); sock = dk3socket_un_stream_client(job->af, 0L, 0L, NULL, job->app); if(INVALID_SOCKET != sock) { #line 1274 "pjsnmp.ctr" wb = dk3socket_send(sock, rq, sl, 0L, 0L, NULL, job->app); if(wb == (int)sl) { #line 1276 "pjsnmp.ctr" if(dk3socket_shutdown(sock, DK3_TCPIP_SHUTDOWN_WRITE, NULL, job->app)) { if(!(rs)) back = 1; do { wb = dk3socket_recv(sock, bu, (sizeof(bu)-1), 0L, 0L, NULL, job->app); if((rs) && (back == 0) && (wb > 0)) { bu[wb] = '\0'; strcpy(rs, bu); back = 1; } } while((wb > 0) && (pjsnmp_cc(job,0))); } else { /* ERROR: Failed to shut down accounting socket! */ pjsnmp_log_1(job, (job->lm)[85]); } } else { #line 1291 "pjsnmp.ctr" /* ERROR: Failed to send accounting data to socket! */ pjsnmp_log_1(job, (job->lm)[84]); } dk3socket_close(sock, NULL, job->app); } else { #line 1296 "pjsnmp.ctr" /* ERROR: Failed to open accounting socket! */ pjsnmp_log_1(job, (job->lm)[83]); } #line 1299 "pjsnmp.ctr" return back; } /** Construct jobstart request. @param job Job structure. @param rq Request buffer. @param szrq Size of request buffer. @return 1 on success, 0 on error. */ static int pjsnmp_construct_achk_request(pjsnmp_job_t *job, char *rq, size_t szrq) { size_t sl; int back = 0; #line 1317 "pjsnmp.ctr" if(rq) *rq = '\0'; sl = strlen(pjsnmp_kw[(job->as) ? 4 : 3]); sl += strlen(job->un); sl += strlen(job->qn); sl += 4; if(job->as) { sl += 8; } if(sl < szrq) { #line 1324 "pjsnmp.ctr" back = 1; strcpy(rq, pjsnmp_kw[(job->as) ? 4 : 3]); strcat(rq, pjsnmp_kw[5]); if(job->as) { strcat(rq, pjsnmp_kw[8]); } strcat(rq, job->qn); if(job->as) { strcat(rq, pjsnmp_kw[7]); } strcat(rq, pjsnmp_kw[5]); if(job->as) { strcat(rq, pjsnmp_kw[9]); } strcat(rq, job->un); if(job->as) { strcat(rq, pjsnmp_kw[7]); } strcat(rq, pjsnmp_kw[6]); } else { #line 1344 "pjsnmp.ctr" } #line 1345 "pjsnmp.ctr" return back; } /** Check whether the user is allowed to print on the queue. @param job Job structure. @return 1 if printing is allowed, 0 otherwise. */ static int pjsnmp_achk(pjsnmp_job_t *job) { char rq[PQD_INPUT_BUFFER_SIZE]; /* Request buffer. */ char rs[PQD_OUTPUT_BUFFER_SIZE]; /* Response buffer. */ int back = 1; #line 1362 "pjsnmp.ctr" if((job->af) && (job->ac)) { #line 1363 "pjsnmp.ctr" back = 0; if(job->un) { #line 1365 "pjsnmp.ctr" if(job->qn) { #line 1366 "pjsnmp.ctr" if(pjsnmp_is_socket(job)) { #line 1367 "pjsnmp.ctr" if(pjsnmp_construct_achk_request(job, rq, sizeof(rq))) { #line 1368 "pjsnmp.ctr" if(pjsnmp_accounting_dialog(job, rq, rs, sizeof(rs))) { #line 1369 "pjsnmp.ctr" dk3str_c8_delnl(rs); dk3str_c8_normalize(rs, NULL, ' '); switch(dk3str_c8_array_index(pjsnmp_achk_responses, rs, 0)) { case 0: { #line 1372 "pjsnmp.ctr" back = 1; } break; case 1: { #line 1375 "pjsnmp.ctr" job->ex = PJSNMP_EXIT_REMOVE; /* ERROR: Printing not allowed! */ pjsnmp_log_1(job, (job->lm)[82]); } break; case 2: { #line 1380 "pjsnmp.ctr" job->ex = PJSNMP_EXIT_HOLD; /* ERROR: Printing not allowed! */ pjsnmp_log_1(job, (job->lm)[82]); } break; } } else { #line 1386 "pjsnmp.ctr" } } else { #line 1388 "pjsnmp.ctr" /* ERROR: Printer or user name too long! */ pjsnmp_log_1(job, (job->lm)[78]); } } else { #line 1392 "pjsnmp.ctr" /* ERROR: Accounting file not a socket! */ pjsnmp_log_1(job, (job->lm)[81]); } } else { #line 1396 "pjsnmp.ctr" /* ERROR: Queue name for printer unknown! */ pjsnmp_log_1(job, (job->lm)[80]); } } else { #line 1400 "pjsnmp.ctr" /* ERROR: User name for print job unknown! */ pjsnmp_log_1(job, (job->lm)[79]); } } #line 1404 "pjsnmp.ctr" return back; } /** Open SNMP session. @param job Job structure. */ static void pjsnmp_open_session(pjsnmp_job_t *job) { #line 1417 "pjsnmp.ctr" snmp_sess_init(&(job->st)); (job->st).version = SNMP_VERSION_2c; switch(job->sv) { case DK3_SNMP_VERSION_1: { (job->st).version = SNMP_VERSION_1; } break; case DK3_SNMP_VERSION_2P: { (job->st).version = SNMP_VERSION_2p; } break; case DK3_SNMP_VERSION_3: { (job->st).version = SNMP_VERSION_3; } break; } (job->st).peername = job->hn; (job->st).community = (unsigned char *)(job->sc); if(!((job->st).community)) { (job->st).community = (unsigned char *)(pjsnmp_kw[11]); } (job->st).community_len = strlen((char *)((job->st).community)); job->ss = snmp_open(&(job->st)); #line 1432 "pjsnmp.ctr" } #line 1437 "pjsnmp.ctr" #line 1438 "pjsnmp.ctr" #line 1439 "pjsnmp.ctr" #line 1440 "pjsnmp.ctr" #line 1441 "pjsnmp.ctr" #line 1442 "pjsnmp.ctr" #line 1443 "pjsnmp.ctr" #line 1444 "pjsnmp.ctr" #line 1445 "pjsnmp.ctr" #line 1446 "pjsnmp.ctr" #line 1447 "pjsnmp.ctr" #line 1448 "pjsnmp.ctr" #line 1449 "pjsnmp.ctr" #line 1450 "pjsnmp.ctr" /** Retrieve int value from SNMP variable. @param job Job structure. @param dp Destination pointer. @param v SNMP variable to process. @return 1 on success, 0 on error. */ static int pjsnmp_get_int( pjsnmp_job_t *job, int *dp, struct variable_list *v ) { char bu[512]; /* Buffer for private copy. */ int back = 0; #line 1470 "pjsnmp.ctr" switch(v->type) { case ASN_OCTET_STR: { if((v->val_len >= 0) && (v->val_len < sizeof(bu))) { dk3mem_cpy((void *)bu, (void *)((v->val).string), v->val_len); bu[v->val_len] = '\0'; if(1 == sscanf(bu, pjsnmp_kw[24], dp)) { back = 1; } } } break; case ASN_TIMETICKS: case ASN_GAUGE: case ASN_COUNTER: case ASN_INTEGER: { *dp = (int)(*(v->val).integer); back = 1; } break; } #line 1491 "pjsnmp.ctr" return back; } /** Retrieve unsigned long value from SNMP variable. @param job Job structure. @param dp Destination pointer. @param v SNMP variable to process. @return 1 on success, 0 on error. */ static int pjsnmp_get_ul( pjsnmp_job_t *job, unsigned long *dp, struct variable_list *v ) { char bu[512]; /* Buffer for private copy. */ int back = 0; #line 1513 "pjsnmp.ctr" switch(v->type) { case ASN_OCTET_STR: { if((v->val_len >= 0) && (v->val_len < sizeof(bu))) { dk3mem_cpy((void *)bu, (void *)((v->val).string), v->val_len); bu[v->val_len] = '\0'; if(1 == sscanf(bu, pjsnmp_kw[18], dp)) { back = 1; } } } break; case ASN_TIMETICKS: case ASN_GAUGE: case ASN_COUNTER: case ASN_INTEGER: { *dp = (unsigned long)(*(v->val).integer); back = 1; } break; } #line 1534 "pjsnmp.ctr" return back; } /** Convert printer error condition from octets to unsigned long. @param job Job structure. @param dp Destination pointer. @param v Variable to use. @return 1 on success, 0 on error. */ static int pjsnmp_get_bytes_inverted( pjsnmp_job_t *job, unsigned long *dp, struct variable_list *v ) { unsigned char *ucp; /* Current byte pointer. */ unsigned long v1; /* Bit to set. */ unsigned long value = 0UL; size_t i; /* Current byte index. */ size_t j; /* Bit in byte. */ int back = 0; #line 1560 "pjsnmp.ctr" switch(v->type) { case ASN_OCTET_STR: { back = 1; v1 = 1UL; ucp = (v->val).string; for(i = 0; i < v->val_len; i++) { if(i < sizeof(unsigned long)) { for(j = 0; j < 8; j++) { if((*ucp) & (pjsnmp_bits[j])) { value |= v1; } v1 = v1 * 2UL; } } else { back = 0; } ucp++; } *dp = value; #line 1579 "pjsnmp.ctr" } break; } #line 1581 "pjsnmp.ctr" return back; } /** Check whether device and printer status indicate printer is printing. @param ds Device status from SNMP request. @param ps Printer status from SNMP request. @return 1 if printer is printing, 0 otherwise. */ static int pjsnmp_is_printing(int ds, int ps) { int back = 0; if(PJSNMP_PRINTER_PRINTING == ps) { switch(ds) { case PJSNMP_DEVICE_RUNNING: case PJSNMP_DEVICE_WARNING: { back = 1; } break; } } #line 1603 "pjsnmp.ctr" return back; } /** Check whether device and printer status indicate printer is ready. @param ds Device status from SNMP response. @param ps Printer status from SNMP response. @return 1 if printer is ready, 0 otherwise. */ static int pjsnmp_is_ready(int ds, int ps) { int back = 0; if(PJSNMP_PRINTER_IDLE == ps) { switch(ds) { case PJSNMP_DEVICE_RUNNING: case PJSNMP_DEVICE_WARNING: { back = 1; } break; } } #line 1626 "pjsnmp.ctr" return back; } /** Check whether hrDeviceStatus and hrPrinterStatus indicate warmup. @param ds Device status. @param ps Printer status. @return 1 for warmup, 0 for other state. */ int pjsnmp_is_warming_up(int ds, int ps) { int back = 0; if(PJSNMP_PRINTER_WARMUP == ps) { switch(ds) { case PJSNMP_DEVICE_DOWN: case PJSNMP_DEVICE_WARNING: case PJSNMP_DEVICE_RUNNING: case PJSNMP_DEVICE_TESTING: { back = 1; } break; } } return back; } /** Check whether printer is in standby mode. @param job Job structure. @param ds Device status from SNMP request. @param ps Printer status from SNMP request. @param ec Error conditions from SNMP. @return 1 if printer is in standby, 0 otherwise. */ static int pjsnmp_is_standby(pjsnmp_job_t *job, int ds, int ps, unsigned long ec) { int back = 0; /* H. Edlund suggests the combination device=running/printer=other as sure to retrieve the pagecount in "Design and Implementation of Accounting and Status Notification for the LPRng Print Spooler" as this combintation indicates the standby state of the printer. On my printer this combination also occurs if the paper tray is opened or the toner door is open. May be we need to check other conditions additionally. */ #if 0 if(PJSNMP_DEVICE_RUNNING == ds) { if(PJSNMP_PRINTER_OTHER == ps) { back = 1; } } #endif if(PJSNMP_PRINTER_OTHER == ps) { switch(ds) { case PJSNMP_DEVICE_RUNNING: case PJSNMP_DEVICE_WARNING: { if(job->poid) { if(!(ec & (~(pjsnmp_warning_only)))) { back = 1; } } } break; } } #line 1701 "pjsnmp.ctr" return back; } /** Set summary for current device and printer state. @param job Job structure. @param stage Processing stage (0=start, 1=in job, 2=end). */ static void pjsnmp_set_summary_state(pjsnmp_job_t *job, int stage) { time_t ct; /* Current time. */ #line 1717 "pjsnmp.ctr" if(pjsnmp_is_ready((job->cs).ds, (job->cs).ps)) { (job->cs).st = PJSNMP_STATE_READY; } else { if(pjsnmp_is_printing((job->cs).ds, (job->cs).ps)) { (job->cs).st = PJSNMP_STATE_PRINTING; switch(stage) { case 1: case 2: { job->wp = 1; } break; } } else { if(pjsnmp_is_standby(job, (job->cs).ds, (job->cs).ps, (job->cs).ec)) { (job->cs).st = PJSNMP_STATE_READY; } else { if(pjsnmp_is_warming_up((job->cs).ds, (job->cs).ps)) { (job->cs).st = PJSNMP_STATE_WARMUP; } else { if(PJSNMP_DEVICE_DOWN == (job->cs).ds) { (job->cs).st = PJSNMP_STATE_ERROR; } else { (job->cs).st = PJSNMP_STATE_OTHER; } } } } } /* For the end of job the page count should be higher than at the beginning of the job. We wait 15 seconds for start of printing, otherwise it might be a 0 pages print job or something the printer does not understand. */ if(PJSNMP_STATE_READY == (job->cs).st) { if(2 == stage) { if(!(job->wp)) { if(job->pc == (job->cs).pc) { time(&ct); if(ct < (job->ti + (time_t)15)) { (job->cs).st = PJSNMP_STATE_WAIT_START; } } } } } #line 1762 "pjsnmp.ctr" } /** Apply SNMP response to current state in job. @param job job structure. @param rs SNMP response PDU. @param stage Processing stage (0=start, 1=in job, 2=end). @return 1 if all components were found, 0 otherwise. */ static int pjsnmp_apply_response(pjsnmp_job_t *job, struct snmp_pdu *rs, int stage) { struct variable_list *v; int have = 0; int back = 0; #line 1780 "pjsnmp.ctr" v = rs->variables; while(v) { #line 1782 "pjsnmp.ctr" if(pjsnmp_oids_equal(v->name,v->name_length,pjsnmp_oid_ds,pjsnmp_sz_oid_ds)) { #line 1784 "pjsnmp.ctr" if(pjsnmp_get_int(job, &((job->cs).ds), v)) { have |= 1; #line 1786 "pjsnmp.ctr" } } if(pjsnmp_oids_equal(v->name,v->name_length,pjsnmp_oid_ps,pjsnmp_sz_oid_ps)) { #line 1790 "pjsnmp.ctr" if(pjsnmp_get_int(job, &((job->cs).ps), v)) { have |= 2; #line 1792 "pjsnmp.ctr" } } if(pjsnmp_oids_equal(v->name,v->name_length,pjsnmp_oid_pc,pjsnmp_sz_oid_pc)) { #line 1796 "pjsnmp.ctr" if(pjsnmp_get_ul(job, &((job->cs).pc), v)) { have |= 4; #line 1798 "pjsnmp.ctr" } } if(pjsnmp_oids_equal(v->name,v->name_length,pjsnmp_oid_pe,pjsnmp_sz_oid_pe)) { #line 1802 "pjsnmp.ctr" if(pjsnmp_get_bytes_inverted(job, &((job->cs).ec), v)) { have |= 8; #line 1804 "pjsnmp.ctr" } } v = v->next_variable; } if(7 == (have & 7)) { back = 1; pjsnmp_set_summary_state(job, stage); } #line 1812 "pjsnmp.ctr" return back; } /** Retrieve information from printer using SNMP. Report state if changed and error conditions if changed. @param job Job structure. @param stage Processing stage (0=start, 1=in job, 2=end). @return 1 if the program can continue normally, 0 if there was no response or an error in the response, -1 for serious problems (failed to create request PDU). */ static int pjsnmp_run_snmp_request(pjsnmp_job_t *job, int stage) { struct snmp_pdu *rq; /* Request. */ struct snmp_pdu *rs; /* Response. */ int status; /* Status from SNMP request. */ int back = 0; #line 1834 "pjsnmp.ctr" pjsnmp_state_init(&(job->cs)); (job->cs).st = PJSNMP_STATE_UNREACHABLE; rq = snmp_pdu_create(SNMP_MSG_GET); rs = NULL; if(rq) { #line 1839 "pjsnmp.ctr" snmp_add_null_var(rq, pjsnmp_oid_ds, pjsnmp_sz_oid_ds); snmp_add_null_var(rq, pjsnmp_oid_ps, pjsnmp_sz_oid_ps); snmp_add_null_var(rq, pjsnmp_oid_pc, pjsnmp_sz_oid_pc); if(job->pdes) { snmp_add_null_var(rq, pjsnmp_oid_pe, pjsnmp_sz_oid_pe); } status = snmp_synch_response(job->ss, rq, &rs); if(STAT_SUCCESS == status) { #line 1847 "pjsnmp.ctr" if(rs) { #line 1848 "pjsnmp.ctr" if(SNMP_ERR_NOERROR == rs->errstat) { #line 1849 "pjsnmp.ctr" (job->cs).st = PJSNMP_STATE_OTHER; back = pjsnmp_apply_response(job, rs, stage); } else { #line 1852 "pjsnmp.ctr" /* ERROR in response */ (job->cs).st = PJSNMP_STATE_ERROR_IN_RESPONSE; } snmp_free_pdu(rs); rs = NULL; } else { #line 1857 "pjsnmp.ctr" /* ERROR: No response! */ (job->cs).st = PJSNMP_STATE_UNREACHABLE; } } else { #line 1861 "pjsnmp.ctr" /* ERROR: No response! */ (job->cs).st = PJSNMP_STATE_UNREACHABLE; } } else { #line 1865 "pjsnmp.ctr" back = -1; (job->cs).st = PJSNMP_STATE_REQUEST_FAILED; job->fe = 1; } #line 1869 "pjsnmp.ctr" return back; } /** Report current printer state. @param job Job structure. */ static void pjsnmp_report_printer_state(pjsnmp_job_t *job) { #line 1882 "pjsnmp.ctr" switch((job->cs).st) { case PJSNMP_STATE_UNREACHABLE: { pjsnmp_log_1(job, (job->lm)[6]); } break; case PJSNMP_STATE_REQUEST_FAILED: { pjsnmp_log_1(job, (job->lm)[7]); } break; case PJSNMP_STATE_ERROR_IN_RESPONSE: { pjsnmp_log_1(job, (job->lm)[8]); } break; case PJSNMP_STATE_READY: { pjsnmp_log_1(job, (job->lm)[0]); } break; case PJSNMP_STATE_PRINTING: { pjsnmp_log_1(job, (job->lm)[2]); } break; case PJSNMP_STATE_WARMUP: { pjsnmp_log_1(job, (job->lm)[1]); } break; case PJSNMP_STATE_WAIT_START: { pjsnmp_log_1(job, (job->lm)[3]); } break; case PJSNMP_STATE_ERROR: { pjsnmp_log_1(job, (job->lm)[4]); } break; case PJSNMP_STATE_OTHER: { pjsnmp_log_1(job, (job->lm)[5]); } break; } #line 1911 "pjsnmp.ctr" } /** Report device status and printer status. @param job job structure. */ static void pjsnmp_report_device_printer_status(pjsnmp_job_t *job) { (job->cs).ds = PJSNMP_IN_RANGE(0,5,(job->cs).ds); (job->cs).ps = PJSNMP_IN_RANGE(0,5,(job->cs).ps); pjsnmp_log_3( job, (job->lm)[9], (job->lm)[10 + (job->cs).ds], (job->lm)[16 + (job->cs).ps] ); } /** Detect and report change in an error condition. @param job Job structure. @param ce Current error conditions. @param oe Old (previous) error conditions. @param c1 One condition to check. @param c1_on Index of text to print if condition changed to true. @param c1_off Index of text to print if condition changed to false. */ static void pjsnmp_rdec_one_condition( pjsnmp_job_t *job, unsigned long ce, unsigned long oe, unsigned long c1, size_t c1_on, size_t c1_off ) { if(ce & c1) { if(!(oe & c1)) { pjsnmp_log_1(job, (job->lm)[c1_on]); } } else { if(oe & c1) { pjsnmp_log_1(job, (job->lm)[c1_off]); } } } /** Detect and report change in two related error conditions. @param job Job structure. @param ce Current error conditions. @param oe Old (previous) error conditions. @param c1 Higher priorized condition to check. @param c2 Lower priorized condition to check. @param c1_on Index of text to print if c1 changed to true. @param c1_off Index of text to print if c1 changed to false. @param c2_on Text of print if c1=false and c2 changed to true. @param c2_off Text to print if c1=false and c2 changed to false. */ static void pjsnmp_rdec_two_conditions( pjsnmp_job_t *job, unsigned long ce, unsigned long oe, unsigned long c1, unsigned long c2, size_t c1_on, size_t c1_off, size_t c2_on, size_t c2_off ) { if(ce & c1) { if(!(oe & c1)) { /* Report c1_on */ pjsnmp_log_1(job, (job->lm)[c1_on]); } } else { if(ce & c2) { if(!(oe & c2)) { /* Report c2_on */ pjsnmp_log_1(job, (job->lm)[c2_on]); } } else { if(oe & c1) { /* Report c1_off */ pjsnmp_log_1(job, (job->lm)[c1_off]); } else { if(oe & c2) { /* Report c2_off */ pjsnmp_log_1(job, (job->lm)[c2_off]); } } } } } /** Report error condition indicated in hrPrinterDetectedErrorState. @param job Job structure. */ static void pjsnmp_report_detected_error_condition(pjsnmp_job_t *job) { unsigned long oe; /* Old (previous) error conditions. */ unsigned long ce; /* Current error conditions. */ oe = (job->os).ec; ce = (job->cs).ec; pjsnmp_rdec_two_conditions( job, ce, oe, DK3_SNMP_PRINTER_ERROR_NO_PAPER, DK3_SNMP_PRINTER_ERROR_LOW_PAPER, 22, 23, 24, 25 ); pjsnmp_rdec_one_condition( job, ce, oe, DK3_SNMP_PRINTER_ERROR_INPUT_EMPTY, 48, 49 ); pjsnmp_rdec_two_conditions( job, ce, oe, DK3_SNMP_PRINTER_ERROR_NO_TONER, DK3_SNMP_PRINTER_ERROR_LOW_TONER, 26, 27, 28, 29 ); pjsnmp_rdec_two_conditions( job, ce, oe, DK3_SNMP_PRINTER_ERROR_OUTPUT_FULL, DK3_SNMP_PRINTER_ERROR_OUTPUT_NEAR, 30, 31, 32, 33 ); pjsnmp_rdec_one_condition( job, ce, oe, DK3_SNMP_PRINTER_ERROR_JAMMED, 36, 37 ); pjsnmp_rdec_one_condition( job, ce, oe, DK3_SNMP_PRINTER_ERROR_DOOR_OPEN, 34, 35 ); pjsnmp_rdec_one_condition( job, ce, oe, DK3_SNMP_PRINTER_ERROR_OFFLINE, 38, 39 ); pjsnmp_rdec_one_condition( job, ce, oe, DK3_SNMP_PRINTER_ERROR_SERVICE_NEEDED, 40, 41 ); pjsnmp_rdec_one_condition( job, ce, oe, DK3_SNMP_PRINTER_ERROR_INPUT_TRAY, 42, 43 ); pjsnmp_rdec_one_condition( job, ce, oe, DK3_SNMP_PRINTER_ERROR_OUTPUT_TRAY, 44, 45 ); pjsnmp_rdec_one_condition( job, ce, oe, DK3_SNMP_PRINTER_ERROR_MARKER_SUPPLY, 46, 47 ); pjsnmp_rdec_one_condition( job, ce, oe, DK3_SNMP_PRINTER_ERROR_MAINTENANCE, 50, 51 ); } /** Run SNMP request and report the results to status file if necessary. @param job Job structure. @param stage Processing stage (0=start, 1=in job, 2=end). @return 1 on success, 0 for no response or error in response, -1 for serious problem (failed to create request PDU). */ static int pjsnmp_run_request_and_report(pjsnmp_job_t *job, int stage) { int back = 0; #line 2090 "pjsnmp.ctr" back = pjsnmp_run_snmp_request(job, stage); if((1 == back) || (0 == back)) { /* Compare against old state, report changes if any. */ if(((job->cs).ds != (job->os).ds) || ((job->cs).ps != (job->os).ps)) { pjsnmp_report_device_printer_status(job); } if((job->cs).ec != (job->os).ec) { pjsnmp_report_detected_error_condition(job); } if((job->cs).st != (job->os).st) { pjsnmp_report_printer_state(job); } /* This passes current state is the old state in the next pass. */ dk3mem_cpy( (void *)(&(job->os)), (void *)(&(job->cs)), sizeof(pjsnmp_printer_state_t) ); } #line 2111 "pjsnmp.ctr" return back; } /** Construct accounting request. @param job Job structure. @param stage Processing stage, 0=start, 2=end. @param rq Destination buffer for request. @param szrq Size of rq. @return 1 on success, 0 on error. */ static int pjsnmp_construct_accounting_request( pjsnmp_job_t *job, int stage, char *rq, size_t szrq ) { char bu[32]; char *corpos; char const *kw1; size_t sl; int back = 0; corpos = NULL; if(job->as) { /* LPRng */ kw1 = pjsnmp_kw[(stage) ? 15 : 14]; } else { /* printqd */ kw1 = pjsnmp_kw[(stage) ? 17 : 16]; } sprintf(bu, pjsnmp_kw[18], (job->cs).pc); if((job->qn) && (job->un) && (job->jn) && (job->jt)) { sl = strlen(kw1); sl += strlen(job->qn); sl += strlen(job->un); sl += strlen(bu); sl += strlen(job->jn); sl += strlen(job->jt); sl += 7; if(job->as) { sl += 20; } if(sl < szrq) { strcpy(rq, kw1); strcat(rq, pjsnmp_kw[5]); if(1 == job->as) { strcat(rq, pjsnmp_kw[8]); } strcat(rq, job->qn); if(1 == job->as) { strcat(rq, pjsnmp_kw[7]); } strcat(rq, pjsnmp_kw[5]); if(1 == job->as) { strcat(rq, pjsnmp_kw[9]); } strcat(rq, job->un); if(1 == job->as) { strcat(rq, pjsnmp_kw[7]); } strcat(rq, pjsnmp_kw[5]); if(1 == job->as) { strcat(rq, pjsnmp_kw[19]); } strcat(rq, bu); if(1 == job->as) { strcat(rq, pjsnmp_kw[7]); } strcat(rq, pjsnmp_kw[5]); if(1 == job->as) { strcat(rq, pjsnmp_kw[20]); } strcat(rq, job->jn); if(1 == job->as) { strcat(rq, pjsnmp_kw[7]); } strcat(rq, pjsnmp_kw[5]); if(1 == job->as) { strcat(rq, pjsnmp_kw[21]); corpos = rq; while(*corpos) { corpos++; } } strcat(rq, job->jt); if(1 == job->as) { while(*corpos) { switch(*corpos) { case '\'': case ' ': case '\t': { *corpos = '_'; } break; case '\\': { *corpos = '/'; } break; } corpos++; } strcat(rq, pjsnmp_kw[7]); } strcat(rq, pjsnmp_kw[6]); back = 1; } } return back; } /** Pass page counter value to accounting system. @param job Job structure. @param stage Processing stage, 0=start, 2=end. */ static void pjsnmp_send_pagecount_to_accounting(pjsnmp_job_t *job, int stage) { char rq[PQD_INPUT_BUFFER_SIZE]; FILE *fipo; if(job->af) { if(pjsnmp_construct_accounting_request(job, stage, rq, sizeof(rq))) { if(pjsnmp_is_socket(job)) { #line 2220 "pjsnmp.ctr" (void)pjsnmp_accounting_dialog(job, rq, NULL, 0); } else { #line 2222 "pjsnmp.ctr" fipo = dk3sf_fopen_app(job->af, pjsnmp_kw[13], job->app); if(fipo) { fputs(rq, fipo); fclose(fipo); } } } else { /* ERROR: Accounting request grows too long! */ pjsnmp_log_1(job, (job->lm)[78]); } } } /** Retrieve page count before and after job, report to accounting system. @param job Job structure. @param stage Processing state (0=start, 1=in job, 2=end). */ static void pjsnmp_process_pagecount(pjsnmp_job_t *job, int stage) { char bu[32]; int cc = 1; int success = 0; int res; #line 2251 "pjsnmp.ctr" if(job->ss) { while((0 == success) && (cc) && (pjsnmp_cc(job,1))) { #line 2253 "pjsnmp.ctr" res = pjsnmp_run_request_and_report(job, stage); #line 2254 "pjsnmp.ctr" switch(res) { case 1: { #line 2256 "pjsnmp.ctr" switch((job->cs).st) { case PJSNMP_STATE_READY: { success = 1; cc = 0; } break; case PJSNMP_STATE_REQUEST_FAILED: { cc = 0; job->fe = 1; /* ERROR: Resources shortage, giving up! */ pjsnmp_log_1(job, (job->lm)[77]); } break; } } break; case 0: { #line 2269 "pjsnmp.ctr" } break; case -1: { #line 2271 "pjsnmp.ctr" cc = 0; /* ERROR: Resources shortage, giving up! */ pjsnmp_log_1(job, (job->lm)[77]); job->fe = 1; } break; } /* When not yet done, wait a second to avoid 100 percent CPU usage. */ if((0 == success) && (cc) && (pjsnmp_cc(job,1)) && (!(job->fe))) { sleep(1); } #line 2283 "pjsnmp.ctr" } if(success) { /* Report page count to accounting system. */ pjsnmp_send_pagecount_to_accounting(job, stage); sprintf(bu, pjsnmp_kw[18], (job->cs).pc); switch(stage) { case 0: { pjsnmp_log_2(job, (job->lm)[86], bu); } break; case 2: { pjsnmp_log_2(job, (job->lm)[87], bu); } break; } } } else { } #line 2299 "pjsnmp.ctr" } /** Open temporary file and network connection, transfer data. @param job Job structure. */ static void pjsnmp_process_data(pjsnmp_job_t *job) { char bu[1460]; /* Buffer. */ fd_set rfds; /* File descriptor set for response. */ fd_set wfds; /* File descriptor set for select. */ struct timeval to; /* Timeout for select. */ FILE *fipo; /* Input file. */ dk3_socket_t sock; /* Socket for printer connection. */ size_t rb; /* Number of bytes read. */ int cc; /* Flag: Can continue. */ int wb; /* Number of bytes sent. */ int cw; /* Flag: Can write. */ int res; /* Shutdown result. */ int se; /* Flag: Error during socket ops. */ #line 2323 "pjsnmp.ctr" se = 0; fipo = dk3sf_fopen_app(job->tf, pjsnmp_kw[23], job->app); if(fipo) { #line 2326 "pjsnmp.ctr" sock = dk3socket_open_net_stream_client( job->hn, job->pn, 0, 0L, 0L, NULL, job->app ); if(INVALID_SOCKET != sock) { #line 2330 "pjsnmp.ctr" /* Socket opened successfully, transfer data now. */ job->ex = PJSNMP_EXIT_SUCCESS; cc = 1; while((cc) && (pjsnmp_cc(job,0))) { cc = 0; rb = dk3sf_fread_app((void *)bu, 1, sizeof(bu), fipo, job->app); if(rb > 0) { #line 2339 "pjsnmp.ctr" /* We have data to send. */ cc = 1; /* Check whether socket is ready to send. If not ready to send, run an SNMP status check on printer. */ if((job->ct) && (job->ss)) { #line 2348 "pjsnmp.ctr" cw = 0; while((cc) && (!(cw)) && (pjsnmp_cc(job,0))) { FD_ZERO(&wfds); FD_SET(sock,&wfds); to.tv_sec = 0L; to.tv_usec = 0L; if(0 < select((sock+1), NULL, &wfds, NULL, &to)) { #line 2355 "pjsnmp.ctr" if(FD_ISSET(sock,&wfds)) { #line 2356 "pjsnmp.ctr" cw = 1; #line 2357 "pjsnmp.ctr" } else { #line 2358 "pjsnmp.ctr" } } else { #line 2360 "pjsnmp.ctr" } if(!(cw)) { #line 2362 "pjsnmp.ctr" (void)pjsnmp_run_request_and_report(job, 1); } } } /* Send data to printer. */ if((cc) && (pjsnmp_cc(job, 0))) { #line 2370 "pjsnmp.ctr" wb = dk3socket_send(sock, (void *)bu, rb, 0L, 0L, NULL, job->app); if(wb != (int)rb) { #line 2372 "pjsnmp.ctr" cc = 0; se = 1; /* ERROR While sending data! */ pjsnmp_log_1(job, (job->lm)[76]); job->ex = PJSNMP_EXIT_REMOVE; } } /* Check for response from printer. */ FD_ZERO(&rfds); FD_SET(sock,&rfds); to.tv_sec = 0L; to.tv_usec = 0L; if(0 < select((sock + 1), &rfds, NULL, NULL, &to)) { if(FD_ISSET(sock,&rfds)) { int oldmode; oldmode = fcntl(sock, F_GETFL); fcntl(sock, F_SETFL, (oldmode | O_NONBLOCK)); rb = dk3socket_recv( sock, (void *)bu, sizeof(bu), 0L, 0L, NULL, job->app ); if(rb > 0) { if(job->repr) { /* Write printer response to status file. */ if(job->sf) { fipo = dk3sf_fopen_app( job->sf, pjsnmp_kw[(job->hl) ? 13 : 12 ], job->app ); if(fipo) { fputs((job->lm)[88], fipo); fputc('\n', fipo); (void)dk3sf_fwrite_app(bu, 1, (size_t)rb, fipo, job->app); if('\n' != bu[rb - 1]) { fputc('\n', fipo); } job->hl = 1; fclose(fipo); } } } } fcntl(sock, F_SETFL, oldmode); } } } else { #line 2418 "pjsnmp.ctr" } } /* Orderly release if configured to do so. */ if((!(se)) && (job->od) && (pjsnmp_cc(job, 0))) { res = dk3socket_shutdown(sock,DK3_TCPIP_SHUTDOWN_WRITE,NULL,job->app); if(res) { cc = 1; while((cc) && (pjsnmp_cc(job, 0))) { cc = 0; wb = dk3socket_recv(sock, bu, sizeof(bu), 0L, 0L, NULL, job->app); if(wb > 0) { cc = 1; } } } } /* Close socket. */ dk3socket_close(sock, NULL, job->app); } else { #line 2441 "pjsnmp.ctr" /* ERROR: Failed to connect to printer! */ pjsnmp_log_1(job, (job->lm)[75]); } fclose(fipo); } else { #line 2446 "pjsnmp.ctr" /* ERROR: Failed to open file! */ pjsnmp_log_1(job, (job->lm)[74]); } #line 2449 "pjsnmp.ctr" } /** Do pagecount at job start, transfer data, and do pagecount at job end. @param job Job structure. */ static void pjsnmp_pagecount_transfer_pagecount(pjsnmp_job_t *job) { time_t ct; #line 2463 "pjsnmp.ctr" pjsnmp_state_init(&(job->os)); pjsnmp_state_init(&(job->cs)); /* Retrieve page count before job. */ #line 2468 "pjsnmp.ctr" pjsnmp_process_pagecount(job, 0); #line 2469 "pjsnmp.ctr" job->pc = (job->cs).pc; #line 2470 "pjsnmp.ctr" if(pjsnmp_cc(job,0)) { #line 2471 "pjsnmp.ctr" /* Transfer print data. */ pjsnmp_process_data(job); #line 2475 "pjsnmp.ctr" if(pjsnmp_cc(job,0)) { #line 2476 "pjsnmp.ctr" /* Keep start time for beginning of page count 2. */ time(&ct); job->ti = ct; /* Retrieve page count after job. */ pjsnmp_process_pagecount(job, 2); #line 2484 "pjsnmp.ctr" } } #line 2487 "pjsnmp.ctr" } /** Continue after signal handlers are set. @param job Job structure. */ static void pjsnmp_continue_with_signal_handlers(pjsnmp_job_t *job) { #if DK3_HAVE_NETSNMP_ENABLE_FILELOG netsnmp_log_handler *logh = NULL; /* Log handler. */ #endif #line 2502 "pjsnmp.ctr" if(pjsnmp_read_standard_input(job)) { pjsnmp_apply_command_line_arguments(job); if(pjsnmp_achk(job)) { #if Dk3_HAVE_NETSNMP_ENABLE_FILELOG logh = netsnmp_register_loghandler(NETSNMP_LOGHANDLER_FILE, 5); if(logh) { logh->pri_max = 5; logh->token = job->sl; netsnmp_enable_filelog(logh, 0); } #endif init_snmp(pjsnmp_kw[10]); pjsnmp_open_session(job); if((job->ss) || (job->is)) { if(!(job->ss)) { /* WARNING: Failed to open SNMP session! */ pjsnmp_log_1(job, (job->lm)[73]); } pjsnmp_pagecount_transfer_pagecount(job); if(job->ss) { snmp_close(job->ss); job->ss = NULL; } } else { /* ERROR: Failed to open SNMP session! */ pjsnmp_log_1(job, (job->lm)[72]); } #if DK3_HAVE_NETSNMP_ENABLE_FILELOG if(logh) { snmp_disable_filelog(); netsnmp_remove_loghandler(logh); logh->token = NULL; free(logh); } #endif } } else { /* ERROR: Failed to save standard input to file! */ pjsnmp_log_1(job, (job->lm)[71]); } #line 2541 "pjsnmp.ctr" } /** Find file names for temporary files. @param job Job structure. */ static void pjsnmp_find_file_names(pjsnmp_job_t *job) { char bu[DK3_MAX_PATH]; sprintf(bu, pjsnmp_kw[26], (unsigned long)getpid()); job->tf = dk3str_c8_dup_app(bu, job->app); sprintf(bu, pjsnmp_kw[27], (unsigned long)getpid()); job->sl = dk3str_c8_dup_app(bu, job->app); #line 2558 "pjsnmp.ctr" } /** Run after environment variable is applied. @param job Job structure. */ static void pjsnmp_run_with_applied_environment(pjsnmp_job_t *job) { dk3_signal_disp_t disp_int; dk3_signal_disp_t disp_term; dk3_signal_disp_t disp_pipe; #line 2573 "pjsnmp.ctr" pjsnmp_find_file_names(job); if((job->tf) && (job->sl)) { #line 2575 "pjsnmp.ctr" /* Save signal dispositions. */ disp_int = sigset(SIGINT, pjsnmp_sigint_handler); disp_term = sigset(SIGTERM, pjsnmp_sigterm_handler); disp_pipe = sigset(SIGPIPE, pjsnmp_sigpipe_handler); /* Continue processing. */ pjsnmp_continue_with_signal_handlers(job); /* Remove temporary files. */ if(job->sl) { dk3sf_c8_remove_file_app(job->sl, job->app); } if(job->tf) { dk3sf_c8_remove_file_app(job->tf, job->app); } /* Restore signal dispositions. */ if(disp_pipe) { sigset(SIGPIPE, disp_pipe); } if(disp_term) { sigset(SIGTERM, disp_term); } if(disp_int) { sigset(SIGINT, disp_int); } } else { #line 2597 "pjsnmp.ctr" /* ERROR: Memory */ pjsnmp_log_1(job, (job->lm)[60]); pjsnmp_eat_input(job); } #line 2601 "pjsnmp.ctr" } /** Error messages for :pjsnmpxxxx configuration entries without value. @param job Job structure. @param kwi Keyword index in pjsnmp_printcap_entries. */ static void pjsnmp_config_entry_needs_value(pjsnmp_job_t *job, size_t kwi) { /* ERROR: Configuration keyword ... needs value! */ pjsnmp_log_3(job, (job->lm)[52], pjsnmp_printcap_entries[kwi], (job->lm)[53]); } /** Apply one configuration entry. @param job Job structure. @param pc Current key. @param pv Current value, may be NULL. @param in Flag: Inverse entry. @return 1 on success, 0 on error. */ static int pjsnmp_apply_configuration_entry( pjsnmp_job_t *job, char *pc, char *pv, int in ) { int back = 1; #line 2637 "pjsnmp.ctr" switch(dk3str_array_index(pjsnmp_printcap_entries,pc,0)) { case 0: { /* af */ if(pv) { job->af = pv; } else { pjsnmp_config_entry_needs_value(job, 0); back = 0; } } break; case 1: { /* achk */ job->ac = ((in) ? 0 : 1); } break; case 2: { /* host */ if(pv) { job->hn = pv; } else { pjsnmp_config_entry_needs_value(job, 2); back = 0; } } break; case 3: { /* port */ if(pv) { unsigned u; if(1 == sscanf(pv, pjsnmp_kw[25], &u)) { job->pn = (unsigned short)u; if((unsigned)(job->pn) != u) { /* ERROR: Numeric overflow! */ pjsnmp_log_3(job, (job->lm)[69], pv, (job->lm) [70]); back = 0; } } else { /* ERROR: Not a number! */ pjsnmp_log_3(job, (job->lm)[67], pv, (job->lm) [68]); back = 0; } } else { pjsnmp_config_entry_needs_value(job, 3); back = 0; } } break; case 4: { #line 2675 "pjsnmp.ctr" if(pv) { job->sv = dk3str_array_index(pjsnmp_snmp_versions, pv, 0); #line 2677 "pjsnmp.ctr" if(-1 < job->sv) { #line 2678 "pjsnmp.ctr" job->sv += 1; } else { #line 2680 "pjsnmp.ctr" job->sv = 0; /* ERROR: Illegal SNMP version! */ pjsnmp_log_3(job, (job->lm)[65], pv, (job->lm)[66]); back= 0; } } else { pjsnmp_config_entry_needs_value(job, 4); back = 0; } } break; case 5: { /* comm */ if(pv) { job->sc = pv; } else { pjsnmp_config_entry_needs_value(job, 5); back = 0; } } break; case 6: { #line 2697 "pjsnmp.ctr" job->as = dk3str_array_index(pjsnmp_accounting_styles, pv, 0); #line 2698 "pjsnmp.ctr" if(0 > job->as) { job->as = 0; /* ERROR: Illegal accounting style! */ pjsnmp_log_3(job, (job->lm)[63], pv, (job->lm)[64]); back = 0; } } break; case 7: { /* ordr */ job->od = ((in) ? 0 : 1); } break; case 8: { /* check during transfer */ job->ct = ((in) ? 0 : 1); } break; case 9: { /* ignore SNMP failure */ job->is = ((in) ? 0 : 1); } break; case 10: { /* Printer detected error state */ job->pdes = ((in) ? 0 : 1); } break; case 11: { /* Warning/Running + Other indicates standby. */ job->poid = ((in) ? 0 : 1); } break; case 12: { /* Report response. */ job->repr = ((in) ? 0 : 1); } break; } #line 2724 "pjsnmp.ctr" return back; } /** Configure job from environment entry. @param job Job structure. @param pcep PRINTCAP_ENTRY environment entry. @return 1 on success, 0 on error. */ static int pjsnmp_configure_from_environment(pjsnmp_job_t *job, char *pcep) { char *pc; /* Current string. */ char *pn; /* Next string. */ char *pv; /* Value in current string. */ int in; /* Flag: Inverse entry. */ int back = 1; #line 2744 "pjsnmp.ctr" pc = dk3str_c8_chr(pcep, ':'); if(pc) { *(pc++) = '\0'; pc = dk3str_c8_start(pc, NULL); } while(pc) { in = 0; pn = dk3str_c8_chr(pc, ':'); if(pn) { *(pn++) = '\0'; pn = dk3str_c8_start(pn, NULL); } dk3str_c8_delnl(pc); pv = dk3str_c8_chr(pc, '='); if(pv) { *(pv++) = '\0'; pv = dk3str_c8_start(pv, NULL); if(pv) { dk3str_c8_delnl(pv); dk3str_c8_normalize(pv, NULL, ' '); } } else { pv = dk3str_c8_chr(pc, '@'); if(pv) { *pv = '\0'; in = 1; } } if(!pjsnmp_apply_configuration_entry(job, pc, pv, in)) { back = 0; } pc = pn; } #line 2768 "pjsnmp.ctr" return back; } /** Run with a given environment entry for configuration. @param job Job structure. @param pcep PRINTCAP_ENTRY environment entry. */ static void pjsnmp_run_with_environment(pjsnmp_job_t *job, char *pcep) { #line 2782 "pjsnmp.ctr" if(pjsnmp_configure_from_environment(job, pcep)) { #line 2783 "pjsnmp.ctr" if(job->hn) { #line 2784 "pjsnmp.ctr" if(job->pn) { #line 2785 "pjsnmp.ctr" pjsnmp_run_with_applied_environment(job); } else { #line 2787 "pjsnmp.ctr" /* ERROR: Missing port number! */ pjsnmp_log_1(job, (job->lm)[62]); pjsnmp_eat_input(job); } } else { #line 2792 "pjsnmp.ctr" /* ERROR: Missing host name! */ pjsnmp_log_1(job, (job->lm)[61]); pjsnmp_eat_input(job); } } else { #line 2797 "pjsnmp.ctr" pjsnmp_eat_input(job); } #line 2799 "pjsnmp.ctr" } /** Program entry point. @param argc Number of command line arguments. @param argv Command line arguments array. @return 0 on success, any other value indicates an error. */ DK3_MAIN { pjsnmp_job_t job; /* Job structure. */ char bu[32]; /* Buffer to print number of pages. */ char *pcep; /* Copy of PRINTCAP_ENTRY env. */ int exval; /* Exit status code. */ #line 2815 "pjsnmp.ctr" #line 2816 "pjsnmp.ctr" #if DK3_HAVE_TZSET tzset(); #endif pjsnmp_job_init(&job); job.app = dk3app_open_silent(argc,(dkChar const * const *)argv,pjsnmp_kw[0]); if(job.app) { #line 2822 "pjsnmp.ctr" job.lm = dk3app_messages(job.app, pjsnmp_kw[1], pjsnmp_loc); pcep = getenv(pjsnmp_kw[2]); if(pcep) { #line 2825 "pjsnmp.ctr" pcep = dk3str_dup_app(pcep, job.app); if(pcep) { #line 2827 "pjsnmp.ctr" pjsnmp_run_with_environment(&job, pcep); dk3_delete(pcep); } else { #line 2830 "pjsnmp.ctr" /* ERROR: Memory */ pjsnmp_log_1(&job, (job.lm)[60]); pjsnmp_eat_input(&job); } } else { #line 2835 "pjsnmp.ctr" /* ERROR: Printcap entry not found! */ pjsnmp_log_1(&job, (job.lm)[59]); pjsnmp_eat_input(&job); } if((pjsnmp_sigterm_received) || (pjsnmp_sigint_received)) { /* SUMMARY: Job cancelled by signal! */ pjsnmp_log_1(&job, (job.lm)[58]); } else { if(PJSNMP_EXIT_SUCCESS == job.ex) { if(job.cs.pc > job.pc) { /* SUMMARY: Job finished successfully, xxx pages. */ sprintf(bu, pjsnmp_kw[18], (job.cs.pc - job.pc)); pjsnmp_log_3(&job, (job.lm)[56], bu, (job.lm)[57]); } else { /* SUMMARY: Job finished successfully. */ pjsnmp_log_1(&job, (job.lm)[55]); } } else { /* SUMMARY: Errors occured during print jobs. */ pjsnmp_log_1(&job, (job.lm)[54]); } } } else { #line 2858 "pjsnmp.ctr" /* ERROR: Memory */ fputs("pjsnmp: ERROR: Not enough memory!\n", stderr); fflush(stderr); pjsnmp_eat_input(&job); } exval = job.ex; pjsnmp_job_cleanup(&job); #line 2866 "pjsnmp.ctr" #line 2867 "pjsnmp.ctr" exit(exval); return exval; } #else /* ERROR: No libnetsnmp */ int main(int argc, char *argv[] ) { printf("No net-snmp!\n"); } #endif #else /* ERROR: No sigset */ int main(int argc, char *argv[] ) { printf("No sigset()!\n"); } #endif #else /* Incorrect character size. */ int main(int argc, char *argv[] ) { printf("Incorrect character size %d!\n", (int)DK3_CHAR_SIZE); } #endif