summaryrefslogtreecommitdiff
path: root/support/dktools/printqdc.ctr
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/dktools/printqdc.ctr
Initial commit
Diffstat (limited to 'support/dktools/printqdc.ctr')
-rw-r--r--support/dktools/printqdc.ctr1359
1 files changed, 1359 insertions, 0 deletions
diff --git a/support/dktools/printqdc.ctr b/support/dktools/printqdc.ctr
new file mode 100644
index 0000000000..35be526772
--- /dev/null
+++ b/support/dktools/printqdc.ctr
@@ -0,0 +1,1359 @@
+%% options
+
+copyright owner = Dirk Krause
+copyright year = 2016-xxxx
+license = bsd
+
+
+
+%% module
+
+#include "dk4conf.h"
+#include "dk4types.h"
+
+#include <stdio.h>
+
+#if DK4_HAVE_STDLIB_H
+#ifndef STDLIB_H_INCLUDED
+#include <stdlib.h>
+#define STDLIB_H_INCLUDED 1
+#endif
+#endif
+
+#if DK4_HAVE_UNISTD_H
+#ifndef UNISTD_H_INCLUDED
+#include <unistd.h>
+#define UNISTD_H_INCLUDED 1
+#endif
+#endif
+
+#if DK4_HAVE_PROCESS_H
+#ifndef PROCESS_H_INCLUDED
+#include <process.h>
+#define PROCESS_H_INCLUDED 1
+#endif
+#endif
+
+
+
+/** Requirements to build this program:
+ * Use 8 bit characters, so we can use the directories from dk4inst.c.
+ * Signal handling mechanism.
+*/
+#if (DK4_CHAR_SIZE == 1) && ((DK4_HAVE_SIGACTION) || (DK4_HAVE_SIGSET))
+
+
+
+#if DK4_HAVE_MATH_H
+#ifndef MATH_H_INCLUDED
+#include <math.h>
+#define MATH_H_INCLUDED 1
+#endif
+#endif
+
+#if DK4_HAVE_ERRNO_H
+#ifndef ERRNO_H_INCLUDED
+#include <errno.h>
+#define ERRNO_H_INCLUDED 1
+#endif
+#endif
+
+#if DK4_HAVE_SYS_TYPES_H
+#ifndef SYS_TYPES_H_INCLUDED
+#include <sys/types.h>
+#define SYS_TYPES_H_INCLUDED 1
+#endif
+#endif
+
+#if DK4_HAVE_IO_H
+#ifndef IO_H_INCLUDED
+#include <io.h>
+#define IO_H_INCLUDED 1
+#endif
+#endif
+
+#if DK4_HAVE_FCNTL_H
+#ifndef FCNTL_H_INCLUDED
+#include <fcntl.h>
+#define FCNTL_H_INCLUDED 1
+#endif
+#endif
+
+#if DK4_HAVE_STRING_H
+#ifndef STRING_H_INCLUDED
+#include <string.h>
+#define STRING_H_INCLUDED 1
+#endif
+#endif
+
+#include "dk4inst.h"
+#include "dk4mpl.h"
+#include "dk4mem.h"
+#include "dk4mai8ddu.h"
+#include "dk4mai8dus.h"
+#include "dk4str8.h"
+#include "dk4lprng.h"
+#include "dk4opt.h"
+#include "dk4sock.h"
+#include "dk4vers.h"
+
+
+
+$!trace-include
+
+
+
+/** Information from one LPRng accounting line.
+*/
+typedef struct {
+ char *username;
+ char *queuename;
+ char *jobtitle;
+ char *pagecount;
+} lprng_info_t;
+
+
+
+
+/** Command line options for program.
+*/
+static dk4_option_t options[] = {
+ { { dkT('i'), dkT("interactive"), DK4_OPT_ARG_NONE }, { NULL }, 0},
+ { { dkT('s'), dkT("socket"), DK4_OPT_ARG_STRING }, { NULL }, 0},
+ { { dkT('h'), dkT("host"), DK4_OPT_ARG_STRING }, { NULL }, 0},
+ { { dkT('p'), dkT("port"), DK4_OPT_ARG_UNSIGNED }, { NULL }, 0},
+ { { dkT('\0'),dkT("help"), DK4_OPT_ARG_NONE}, { NULL }, 0},
+ { { dkT('\0'),dkT("version"), DK4_OPT_ARG_NONE}, { NULL }, 0},
+ { { dkT('\0'),dkT("license"), DK4_OPT_ARG_NONE}, { NULL }, 0}
+};
+
+
+
+/** Help text.
+*/
+static const char * const help_text[] = {
+$!text
+
+Print quota daemon client
+
+printqdc [-i] [-s path] | [-h host -p port]
+
+-i Interactive mode instead of default pipe mode.
+--interactive
+
+-s path Path name for local UNIX domain socket.
+--socket=path
+
+-h host Host name of remote host.
+--host=host
+
+-p port Port number at remote host.
+--port=port
+
+--help Show this help text.
+--version Show version number.
+--license Show license information.
+
+$!end
+};
+
+
+
+/** License conditions text.
+*/
+static const char * const license_text[] = {
+$!text preprocessor
+
+This software uses code from the following projects, either directly or as
+a library:
+
+dktools Dirk Krause's tools and libraries.
+ See http://dktools.sourceforge.net/ for more information.
+
+DK tools and libraries license
+==============================
+Copyright (c) 2015-2016, Dirk Krause
+All rights reserved.
+
+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 copyright
+ 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 Dirk Krause 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.
+
+$!end
+};
+
+
+
+/** Version information.
+*/
+static const char version_text[] = { DKT_VERSION_C8 };
+
+
+
+/** Constant text keywords used by the module.
+*/
+static const char * const pqdc_kw[] = {
+$!string-table
+#
+# 0 Newline
+#
+\n
+#
+# 1 Space
+#
+
+#
+# 2 Default job name
+#
+x@x+1
+#
+# 3 Default job title
+#
+Print job
+#
+# 4
+#
+->
+#
+# 5 6
+#
+<- "
+"\n
+#
+# 7 ... 10
+#
+printqdc:
+ERROR: Port number too large!\n
+ERROR: Port number required!\n
+ERROR: Host name required!\n
+#
+# 11 ... 15
+#
+ERROR: Failed to shut down socket!\n
+ERROR: Failed to send data!\n
+ERROR: Failed to open connection to accounting system!\n
+ERROR: Failed to construct request (would be too long)!\n
+ERROR: Incomplete information to construct request!\n
+#
+# 16 ... 20
+#
+ERROR: Pagecounter not numeric!\n
+ERROR: Too few arguments for request!\n
+ERROR: Unknown command keyword!\n
+ERROR: Missing arguments!\n
+ERROR: Interrupted by signal!\n
+#
+# 21 ... 22
+#
+ERROR: Failed to install signal handlers!\n
+ERROR: Failed to restore signal handlers!\n
+#
+# 23
+#
+ERROR: Failed to initialize socket subsystem!\n
+$!end
+};
+
+
+
+/** Default socket name.
+*/
+static const char def_sock_name[] = {
+ DK4_INST_DIR_VAR "/run/printqd/printqd.sock"
+};
+
+
+
+/** Protocol keywords at start of accounting line.
+*/
+static const char * const command_names[] = {
+$!string-table
+#
+# 0 ... 5 LPRng
+#
+jobstart
+jobend
+start
+end
+filestart
+fileend
+#
+# 6 ... 11 printqd
+#
+info
+acct-check
+acct-start
+acct-end
+acct-charge
+control
+$!end
+};
+
+
+/** Responses from printqd
+*/
+static const char * const responses[] = {
+$!string-table
+ACCEPT
+HOLD
+REMOVE
+$!end
+};
+
+/** Data exchange buffer.
+*/
+static char inbuf[4096];
+
+
+/** Copy for inspection.
+*/
+static char cpbuf[sizeof(inbuf)];
+
+
+/** Host name for network connection.
+*/
+static char *host_name = NULL;
+
+
+/** Socket file name for local connection.
+*/
+static char *sock_name = NULL;
+
+
+/** Number of options.
+*/
+static size_t szoptions = sizeof(options)/sizeof(dk4_option_t);
+
+
+/** Normal exit value (when run as pipe).
+*/
+static int exval = LPRNG_EXIT_SUCCESS;
+
+
+
+/** Help (1), version (2), license (4).
+*/
+static int hvl = 0;
+
+
+
+/** Exit value for interactive mode.
+*/
+static int iexval = EXIT_FAILURE;
+
+
+/** Flag: Interactive mode (-i option).
+*/
+static int intera = 0;
+
+
+/** Flag: EOF was found.
+*/
+static int eof_found = 0;
+
+
+/** Flag: Response already found and processed.
+*/
+static int found_response = 0;
+
+
+#ifdef SIGPIPE
+/** Indicator: SIGPIPE signal received.
+*/
+static
+DK4_VOLATILE
+dk4_sig_atomic_t sig_had_pipe = 0;
+#endif
+
+
+/** Indicator: SIGINT signal received.
+*/
+static
+DK4_VOLATILE
+dk4_sig_atomic_t sig_had_int = 0;
+
+
+/** Indicator: SIGTERM signal received.
+*/
+static
+DK4_VOLATILE
+dk4_sig_atomic_t sig_had_term = 0;
+
+
+
+/** Port number for network connection.
+*/
+static unsigned short portno = 0U;
+
+
+/** Pass pointer through.
+ Use of this function is recommended by CERT C coding standard
+ to avoid optimizing out.
+ @param ptr Pointer to pass through.
+ @return The ptr argument.
+*/
+static
+DK4_VOLATILE
+dk4_sig_atomic_t *
+sig_pass_pointer(DK4_VOLATILE dk4_sig_atomic_t *ptr)
+{
+ return ptr;
+}
+
+
+#ifdef SIGPIPE
+/** Handler for SIGPIPE signal.
+ @param signo Signal number (always SIGPIPE, ignored).
+*/
+static
+void
+sig_handler_pipe(int signo)
+{
+ *sig_pass_pointer(&sig_had_pipe) = 1;
+}
+#endif
+
+
+/** Handler for SIGINT signal.
+ @param signo Signal number (always SIGINT, ignored).
+*/
+static
+void
+sig_handler_int(int signo)
+{
+ *sig_pass_pointer(&sig_had_int) = 1;
+}
+
+
+/** Handler for SIGTERM signal.
+ @param signo Signal number (always SIGTERM, ignored).
+*/
+static
+void
+sig_handler_term(int signo)
+{
+ *sig_pass_pointer(&sig_had_term) = 1;
+}
+
+
+/** Read value from volatile atomic type.
+ This function is necessary as some compilers mis-optimize
+ direct access to volatile variables (at least if you believe
+ one of the coding standards).
+ @param ap Pointer to volatile atomic variable.
+ @return Contents of the variable.
+*/
+static
+dk4_sig_atomic_t
+sig_read_atomic(DK4_VOLATILE dk4_sig_atomic_t *ap)
+{
+ return (*ap);
+}
+
+
+/** Check whether we can continue or must abort due to signal.
+ @param dopipe Flag: Check for SIGPIPE too.
+ @return 1 if we can continue, 0 otherwise.
+*/
+static
+int
+can_continue(void)
+{
+ int back = 1;
+ if (0 != sig_read_atomic(&sig_had_term)) { back = 0; }
+ if (0 != sig_read_atomic(&sig_had_int)) { back = 0; }
+ return back;
+}
+
+
+
+/** Log one-component message to stderr.
+ @param kwind Index of text in printqdc_kw array.
+*/
+static
+void
+log_1(size_t kwind)
+{
+ if (0 != intera) {
+ fputs(pqdc_kw[7], stderr);
+ fputs(pqdc_kw[kwind], stderr);
+ fflush(stderr);
+ }
+}
+
+
+/** Eat up input to avoid broken pipe in feeder.
+*/
+static
+void
+eatup_input(void)
+{
+ size_t rdb;
+ int cc = 1;
+ do {
+ if (0 != can_continue()) {
+ rdb = fread(inbuf, 1, sizeof(inbuf), stdin);
+ if (0 == rdb) {
+ cc = 0;
+ }
+ } else {
+ cc = -1;
+ }
+ } while(1 == cc);
+}
+
+
+
+/** Process command line arguments.
+ @param argc Number of command line arguments.
+ @param argv Command line arguments array.
+ @return 1 on success, 0 on error.
+*/
+static
+int
+cmd_line_args(int argc, char *argv[])
+{
+ dkChar *filenames[32];
+ size_t szfilenames = DK4_SIZEOF(filenames,DK4_PDKCHAR);
+ int back;
+ back = dk4opt_process_argv(
+ options, szoptions, argc, argv, filenames, &szfilenames,
+ 1, 0, NULL
+ );
+ if (1 == back) {
+ if (0 != options[4].found) {
+ hvl |= 1;
+ }
+ if (0 != options[5].found) {
+ hvl |= 2;
+ }
+ if (0 != options[6].found) {
+ hvl |= 4;
+ }
+ if (0 != options[0].found) {
+ intera = 1;
+ }
+ if (0 != options[1].found) {
+ sock_name = options[1].val.t;
+ }
+ if (0 != options[2].found) {
+ host_name = options[2].val.t;
+ }
+ if (0 != options[3].found) {
+ if ((dk4_um_t)0x0000FFFFUL >= options[3].val.u) {
+ portno = (unsigned short)(options[3].val.u);
+ } else {
+ back = 0;
+ /* ERROR: Port number to large! */
+ log_1(8);
+ }
+ }
+ if ((NULL != host_name) && (0 == portno)) {
+ back = 0;
+ /* ERROR: Port number required */
+ log_1(9);
+ }
+ if ((NULL == host_name) && (0 != portno)) {
+ back = 0;
+ /* ERROR: Host name required */
+ log_1(10);
+ }
+ } else {
+ if (0 != options[0].found) {
+ (void)dk4opt_process_argv(
+ options, szoptions, argc, argv, filenames, &szfilenames,
+ 1, 1, NULL
+ );
+ }
+ }
+ return back;
+}
+
+
+
+/** Data exchange with accounting system.
+ @param pres Flag: Process response, 0=no, 1=acct-check, 2=info.
+*/
+static
+void
+process_data(int pres)
+{
+ const char *ep; /* End pointer for text to number conversions */
+ char *ptr; /* Traverse data line */
+ dk4_um_t um; /* Number obtained from text */
+ size_t sl; /* Input buffer string length */
+ size_t wrb; /* Bytes we still have to write */
+ dk4_socket_t sock; /* Connection to accounting/quota daemon */
+ int res; /* Operation result */
+ int cc; /* Flag: Can continue */
+ $? "+ process_data %d", pres
+ wrb = sl = strlen(inbuf);
+ /* LOG/SHOW: Request */
+ if (0 != intera) { $? ". log at start"
+ fputs(pqdc_kw[4], stdout);
+ if (0 < sl) {
+ fputs(inbuf, stdout);
+ if (0 < sl) {
+ if ('\n' != inbuf[sl - 1]) {
+ fputc('\n', stdout);
+ }
+ } else {
+ fputc('\n', stdout);
+ }
+ }
+ fflush(stdout);
+ }
+ if ((0 < sl) && (0 != can_continue())) { $? ". rq size ok"
+ if ((NULL != host_name) && (0 < portno)) { $? ". network"
+ sock = dk4socket_c8_tcp_client_host_port(
+ host_name, portno, 0, 0L, 0L, NULL
+ );
+ } else { $? ". local"
+ sock = dk4socket_c8_unix_client(
+ ((NULL != sock_name) ? sock_name : def_sock_name), NULL
+ );
+ }
+ if (INVALID_SOCKET != sock) { $? ". sock"
+ if (0 != can_continue()) { $? ". can continue"
+ res = dk4socket_send(sock, inbuf, &wrb, 0, 0L, 0L, NULL);
+ if ((DK4_SOCKET_RESULT_SUCCESS == res) && (wrb == sl)) { $? ". send"
+ if (0 != can_continue()) { $? ". can continue"
+ res = dk4socket_shutdown(sock, DK4_SOCKET_SHUT_WRITE, NULL);
+ if (DK4_SOCKET_RESULT_SUCCESS == res) { $? ". shutdown"
+ cc = 1;
+ do {
+ if (0 != can_continue()) { $? ". can continue"
+ wrb = sizeof(inbuf);
+ res = dk4socket_recv(sock, inbuf, &wrb, 0, 0L, 0L, NULL);
+ if ((DK4_SOCKET_RESULT_SUCCESS==res)&&(0 != can_continue())) {
+ if (0 < wrb) { $? ". data"
+ if (0 != pres) { $? ". process response"
+ if (sizeof(inbuf) > wrb) {
+ inbuf[wrb] = '\0';
+ } else {
+ iexval = EXIT_FAILURE;
+ inbuf[sizeof(inbuf)-1] = '\0';
+ }
+ dk4str8_normalize(inbuf, NULL);
+ /* LOG/SHOW: Response */
+ if (0 != intera) {
+ fputs(pqdc_kw[5], stdout);
+ fputs(inbuf, stdout);
+ fputs(pqdc_kw[6], stdout);
+ fflush(stdout);
+ }
+ switch (pres) {
+ case 1: {
+ if (0 == found_response) {
+ switch (dk4str8_array_index(responses,inbuf,0)) {
+ case 1: {
+ exval = LPRNG_EXIT_HOLD;
+ } break;
+ case 2: {
+ exval = LPRNG_EXIT_REMOVE;
+ } break;
+ }
+ }
+ found_response = 1;
+ } break;
+ case 2: {
+ if (0 == found_response) {
+ um = (dk4_um_t)0UL;
+ ep = NULL;
+ ptr = dk4str8_start(inbuf, NULL);
+ if (NULL != ptr) {
+ ptr = dk4str8_next(ptr, NULL);
+ if (NULL != ptr) {
+ ptr = dk4str8_next(ptr, NULL);
+ if (NULL != ptr) {
+ ptr = dk4str8_next(ptr, NULL);
+ if (NULL != ptr) {
+ res = dk4ma_input_c8_dec_dk4_um_t(
+ &um, ptr, &ep, 1, NULL
+ );
+ if (0 == res) {
+ um = (dk4_um_t)0UL;
+ }
+ }
+ }
+ }
+ }
+ if ((dk4_um_t)0UL == um) {
+ exval = LPRNG_EXIT_REMOVE;
+ }
+ }
+ found_response = 1;
+ } break;
+ }
+ } else { $? ". ignore response"
+ }
+ } else { $? ". 0 bytes response"
+ cc = 0;
+ }
+ } else { $? "! recv"
+ iexval = EXIT_FAILURE;
+ cc = -1;
+ }
+ } else { $? "! signal"
+ cc = -1;
+ }
+ } while (1 == cc);
+ } else { $? "! shutdown"
+ iexval = EXIT_FAILURE;
+ /* ERROR: Failed to shut down socket */
+ log_1(11);
+ }
+ } else { $? "! signal"
+ }
+ } else { $? "! send"
+ iexval = EXIT_FAILURE;
+ /* ERROR: Sending data failed */
+ log_1(12);
+ }
+ } else { $? "! signal"
+ }
+ dk4socket_close(sock, NULL);
+ } else { $? "! sock"
+ iexval = EXIT_FAILURE;
+ /* ERROR: Failed to open socket */
+ log_1(13);
+ }
+ } else { $? "! rq size 0"
+ }
+ $? "- process_data"
+}
+
+
+
+/** Find final quote for current word.
+ @param str String to find quote in.
+ @param quote Quote character.
+ @return Pointer to found quote on success, NULL on error.
+*/
+static
+char *
+lprng_final_quote(char *str, char quote)
+{
+ char *back = NULL;
+ $? "+ lprng_final_quote %c %s", quote, TR_8STR(str)
+ while (('\0' != *str) && (NULL == back)) {
+ if (quote == *str) {
+ *str = '\0';
+ back = str;
+ back++;
+ back = dk4str8_start(back, NULL);
+ } else {
+ if ('\\' == *str) {
+ if ('\0' != str[1]) {
+ dk4str8_cpy_to_left(str, &(str[1]));
+ str++;
+ } else {
+ *str = '\0';
+ }
+ } else {
+ str++;
+ }
+ }
+ }
+ $? "- lprng_final_quote \"%s\"", TR_8STR(back)
+ return back;
+}
+
+
+/** Find start of next text word in LPRng accounting line.
+ @param str Current word (remaining text) in accounting line.
+ @return Pointer to next word if found, NULL on error.
+*/
+static
+char *
+lprng_next_word(char *str)
+{
+ char *back = NULL;
+ $? "+ lprng_next_word \"%s\"", TR_8STR(str)
+ switch (*str) {
+ case '\'' : {
+ back = lprng_final_quote(&(str[1]), '\'');
+ } break;
+ case '"' : {
+ back = lprng_final_quote(&(str[1]), '"');
+ } break;
+ default : {
+ back = dk4str8_next(str, NULL);
+ } break;
+ } $? "- lprng_next_word \"%s\"", TR_8STR(back)
+ return back;
+}
+
+
+
+/** Fill data structure from LPRng accounting line.
+ @param liptr Structure to fill.
+ @param textline The text line to use.
+ @return 1 on success, 0 on error.
+*/
+static
+int
+lprng_info_from_line(lprng_info_t *liptr, char *textline)
+{
+ char *next;
+ int back = 1;
+ $? "+ lprng_info_from_line \"%s\"", TR_8STR(textline)
+ DK4_MEMRES(liptr, sizeof(lprng_info_t));
+ liptr->username = NULL; liptr->queuename = NULL;
+ liptr->jobtitle = NULL; liptr->pagecount = NULL;
+ while (NULL != textline) {
+ next = lprng_next_word(textline);
+ if (('\'' == *textline) || ('"' == *textline)) {
+ textline++;
+ }
+ if ('-' == *textline) {
+ textline++;
+ switch (*textline) {
+ case 'n': {
+ liptr->username = ++textline;
+ } break;
+ case 'P': {
+ liptr->queuename = ++textline;
+ } break;
+ case 'J': {
+ liptr->jobtitle = ++textline;
+ } break;
+ case 'p': {
+ liptr->pagecount = ++textline;
+ } break;
+ }
+ } else { $? "! not a minus"
+#if 0
+ /* 2016-02-15 Simply ignore non-option text.
+ */
+ back = 0;
+ /* ERROR: No minus sign */
+#endif
+ }
+ textline = next;
+ }
+ $? "- lprng_info_from_line %d", back
+ return back;
+}
+
+
+
+/** Process one line received from LPRng.
+ @param cmd Index in command names array.
+ @param args Further arguments in line.
+*/
+static
+void
+lprng_line(int cmd, char *args)
+{
+ lprng_info_t li; /* All relevant components of line */
+ const char *ep = NULL; /* End pointer for numeric conversion */
+ const char *jt; /* Job title */
+ dk4_um_t um; /* Text to number conversion result */
+ int res; /* Operation result */
+ int ok = 0; /* Flag: Can process line */
+ $? "+ lprng_line %d \"%s\"", cmd, TR_8STR(args)
+ if (0 != lprng_info_from_line(&li, args)) {
+ switch (cmd) {
+ case 0: {
+ if ((NULL != li.username) && (NULL != li.queuename)) {
+ if (0 != dk4str8_cpy_s(inbuf,sizeof(inbuf),command_names[7], NULL)) {
+ if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),pqdc_kw[1], NULL)) {
+ if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),li.queuename, NULL)) {
+ if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),pqdc_kw[1], NULL)) {
+ if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),li.username, NULL)) {
+ if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),pqdc_kw[0], NULL)) {
+ ok = 1; $? ". new request constructed"
+ }
+ }
+ }
+ }
+ }
+ }
+ if (0 != ok) {
+ process_data(1);
+ } else { $? "! failed to construct"
+ iexval = EXIT_FAILURE;
+ /* ERROR: Failed to construct request */
+ log_1(14);
+ }
+ } else { $? "! incomplete"
+ iexval = EXIT_FAILURE;
+ /* ERROR: Incomplete information */
+ log_1(15);
+ }
+ } break;
+ default: {
+ if ((NULL != li.username) && (NULL != li.queuename)) {
+ if (NULL != li.pagecount) {
+ res = dk4ma_input_c8_dec_dk4_um_t(&um, li.pagecount, &ep, 1, NULL);
+ if (0 != res) {
+ cmd += 4;
+ if(0 !=dk4str8_cpy_s(inbuf,sizeof(inbuf),command_names[cmd],NULL))
+ {
+ if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),pqdc_kw[1], NULL)) {
+ if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),li.queuename, NULL)) {
+ if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),pqdc_kw[1], NULL)) {
+ if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),li.username, NULL)) {
+ if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),pqdc_kw[1], NULL)) {
+ if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),li.pagecount, NULL)) {
+ if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),pqdc_kw[1], NULL)) {
+ if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),pqdc_kw[2], NULL)) {
+ if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),pqdc_kw[1], NULL)) {
+ jt = li.jobtitle;
+ if (NULL == jt) { jt = pqdc_kw[3]; }
+ if (0 != dk4str8_cat_s(inbuf, sizeof(inbuf), jt, NULL)) {
+ if (0 != dk4str8_cat_s(inbuf, sizeof(inbuf), pqdc_kw[0], NULL)) {
+ ok = 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (0 != ok) { $? ". rq constructed"
+ process_data(0);
+ } else { $? "! failed to construct rq"
+ iexval = EXIT_FAILURE;
+ /* ERROR: Failed to construct request */
+ log_1(14);
+ }
+ } else { $? "! pc not numeric"
+ iexval = EXIT_FAILURE;
+ /* ERROR: Pagecounter not numeric */
+ log_1(16);
+ }
+ } else { $? "! incomplete rq"
+ iexval = EXIT_FAILURE;
+ /* ERROR: Incomplete information */
+ log_1(15);
+ }
+ } else { $? "! incomplete rq"
+ iexval = EXIT_FAILURE;
+ /* ERROR: Incomplete information */
+ log_1(15);
+ }
+ } break;
+ }
+ } else {
+ iexval = EXIT_FAILURE;
+ }
+ $? "- lprng_line"
+}
+
+
+
+/** Process one line containing printqd style data.
+ @param args Arguments text.
+ @param minargs Minimum required number of arguments.
+ @param num3 Flag: Argument 3 must be unsigned number.
+ @param pres Flag: Process response.
+*/
+static
+void
+printqd_line(char *args, size_t minargs, int num3, int pres)
+{
+ const char *ep = NULL; /* End of usable data */
+ char *next; /* Start of arguments */
+ dk4_um_t um = (dk4_um_t)0UL; /* Numeric conversion result */
+ size_t i; /* Current argument index */
+ int res; /* Operation result */
+ int errnum = 0; /* Flag: Numeric error */
+ $? "+ printqd_line"
+ dk4str8_normalize(args, NULL);
+ i = 0; $? ". line = \"%s\"", args
+ while(args) {
+ i++;
+ next = dk4str8_next(args, NULL);
+ if ((3 == i) && (0 != num3)) { $? ". check \"%s\"", args
+ res = dk4ma_input_c8_dec_dk4_um_t(&um, args, &ep, 1, NULL);
+ if (0 == res) { errnum = 1; }
+ }
+ args = next;
+ } $? ". i=%u errnum=%d", (unsigned)i, errnum
+ if ((i >= minargs) && (0 == errnum)) {
+ process_data(pres);
+ } else {
+ if (i < minargs) {
+ /* ERROR: Too few arguments */
+ log_1(17);
+ }
+ if (0 != errnum) {
+ /* ERROR: Page counter not numeric */
+ log_1(16);
+ }
+ iexval = EXIT_FAILURE;
+ }
+ $? "- printqd_line"
+}
+
+
+
+/** Process input from stdin.
+*/
+static
+void
+process_input(void)
+{
+ char *args; /* Start of arguments after command */
+ int cc; /* Flag: Can continue */
+ int res; /* Operation result for numeric conversions */
+ $? "+ process_input"
+ cc = 1;
+ do {
+ if (0 != can_continue()) { $? ". can continue"
+ if (fgets(inbuf, sizeof(inbuf), stdin)) { $? ". data"
+ dk4str8_cpy_s(cpbuf, sizeof(cpbuf), inbuf, NULL);
+ dk4str8_delnl(cpbuf);
+ if (NULL != dk4str8_start(cpbuf, NULL)) {
+ if (0 != intera) { $? ". interactive"
+ fputs(cpbuf, stdout);
+ fputc('\n', stdout);
+ fflush(stdout);
+ }
+ args = dk4str8_next(cpbuf, NULL);
+ if (NULL != args) { $? ". arguments"
+ res = dk4str8_array_index(command_names, cpbuf, 0);
+ if (0 != can_continue()) {
+ switch (res) {
+ case 0: {
+ lprng_line(res, args);
+ } break;
+ case 1: {
+ } break;
+ case 2: {
+ } break;
+ case 3: {
+ } break;
+ case 4: {
+ lprng_line(res, args);
+ } break;
+ case 5: {
+ lprng_line(res, args);
+ } break;
+ case 6: {
+ printqd_line(args, 2, 0, 2);
+ } break;
+ case 7: {
+ printqd_line(args, 2, 0, 1);
+ } break;
+ case 8: {
+ printqd_line(args, 4, 1, 0);
+ } break;
+ case 9: {
+ printqd_line(args, 4, 1, 0);
+ } break;
+ case 10: {
+ printqd_line(args, 3, 1, 0);
+ } break;
+ case 11: {
+ printqd_line(args, 1, 0, 0);
+ } break;
+ default: {
+ iexval = EXIT_FAILURE;
+ /* ERROR: Unknown keyword */
+ log_1(18);
+ } break;
+ }
+ } else {
+ cc = -1;
+ }
+ } else { $? "! no arguments"
+ /* ERROR: No arguments */
+ log_1(19);
+ iexval = EXIT_FAILURE;
+ }
+ } else { $? ". skip empty line"
+ }
+ } else { $? ". end of data"
+ eof_found = 1;
+ cc = 0;
+ }
+ } else { $? "! aborted"
+ cc = -1;
+ }
+ } while (1 == cc);
+ $? "- process_input"
+}
+
+
+
+/** Show a text paragraph on standard output.
+ @param txt Text to show.
+*/
+static
+void
+show_text(const char * const *txt)
+{
+ if (NULL != txt) {
+ while (NULL != *txt) {
+ fputs(*(txt++), stdout);
+ fputc('\n', stdout);
+ }
+ fflush(stdout);
+ }
+}
+
+
+
+/** Handle --help, --version, --license options.
+*/
+static
+void
+run_hvl(void)
+{
+ if (0 != (1 & hvl)) {
+ show_text(help_text);
+ }
+ if (0 != (2 & hvl)) {
+ fputs(version_text, stdout);
+ fputc('\n', stdout);
+ fflush(stdout);
+ }
+ if (0 != (4 & hvl)) {
+ show_text(license_text);
+ }
+}
+
+
+
+/** Main program.
+ @param argc Number of command line arguments.
+ @param argv Command line arguments array.
+ @return Exit status code.
+*/
+int
+main(int argc, char *argv[])
+{
+#ifdef DK4_HAVE_SIGACTION
+#ifdef SIGPIPE
+ struct sigaction opipe;
+ struct sigaction npipe;
+#endif
+ struct sigaction oint;
+ struct sigaction nint;
+ struct sigaction oterm;
+ struct sigaction nterm;
+#else
+#ifdef SIGPIPE
+ dk4_sig_handler_t *opipe = NULL;
+#endif
+ dk4_sig_handler_t *oterm = NULL;
+ dk4_sig_handler_t *oint = NULL;
+#endif
+#ifdef DK4_HAVE_SIGACTION
+#ifdef SIGPIPE
+ int spipe = 0;
+#endif
+ int sint = 0;
+ int sterm = 0;
+ int s_f_i = 0;
+ int s_f_r = 0;
+#endif
+ int socki = 0;
+
+ /* Set signal handlers
+ */
+#if DK4_HAVE_SIGACTION
+#ifdef SIGPIPE
+ DK4_MEMRES(&npipe, sizeof(npipe));
+ npipe.sa_handler = sig_handler_pipe;
+ npipe.sa_flags = 0;
+ if (0 != sigemptyset(&npipe.sa_mask)) {
+ s_f_i = 1;
+ goto finished;
+ }
+ if (0 != sigaddset(&npipe.sa_mask, SIGPIPE)) {
+ s_f_i = 1;
+ goto finished;
+ }
+ if (0 != sigaction(SIGPIPE, &npipe, &opipe)) {
+ s_f_i = 1;
+ goto finished;
+ }
+ spipe = 1;
+#endif
+ DK4_MEMRES(&nterm, sizeof(nterm));
+ nterm.sa_handler = sig_handler_term;
+ nterm.sa_flags = 0;
+ if (0 != sigemptyset(&nterm.sa_mask)) {
+ s_f_i = 1;
+ goto finished;
+ }
+ if (0 != sigaddset(&nterm.sa_mask, SIGTERM)) {
+ s_f_i = 1;
+ goto finished;
+ }
+ if (0 != sigaction(SIGTERM, &nterm, &oterm)) {
+ s_f_i = 1;
+ goto finished;
+ }
+ sterm = 1;
+ DK4_MEMRES(&nint, sizeof(nint));
+ nint.sa_handler = sig_handler_int;
+ nint.sa_flags = 0;
+ if (0 != sigemptyset(&nint.sa_mask)) {
+ s_f_i = 1;
+ goto finished;
+ }
+ if (0 != sigaddset(&nint.sa_mask, SIGINT)) {
+ s_f_i = 1;
+ goto finished;
+ }
+ if (0 != sigaction(SIGINT, &nint, &oint)) {
+ s_f_i = 1;
+ goto finished;
+ }
+ sint = 1;
+#else
+#ifdef SIGPIPE
+ opipe = sigset(SIGPIPE, sig_handler_pipe);
+#endif
+ oint = sigset(SIGINT, sig_handler_int);
+ oterm = sigset(SIGTERM, sig_handler_term);
+#endif
+
+ /* Start tracing
+ */
+ $!trace-init printqdc.deb
+ $? "+ main"
+
+ /* Process command line arguments
+ */
+ if (0 == cmd_line_args(argc, argv)) { goto finished; }
+
+ /* Help, version, license.
+ */
+ if (0 != hvl) {
+ run_hvl();
+ goto finished;
+ }
+
+ /* Bring socket subsystem up.
+ */
+ if (DK4_SOCKET_RESULT_SUCCESS != dk4socket_up(NULL)) {
+ /* ERROR: Failed to initialize socket subsystem */
+ log_1(23);
+ goto finished;
+ }
+ socki = 1;
+
+ iexval = EXIT_SUCCESS;
+ $? ". comman line arguments processed, going to process input"
+ process_input();
+
+ finished:
+
+ /* Eat up remaining input, if any.
+ */
+ if ((0 == hvl) && (0 == eof_found)) { eatup_input(); }
+
+ /* Log notification about abort by signal.
+ */
+ if (0 == can_continue()) {
+ /* LOG: Interrupted by signal */
+ log_1(20);
+ iexval = EXIT_FAILURE;
+ }
+
+ /* Release socket subsystem.
+ */
+ if (0 != socki) { (void)dk4socket_down(NULL); }
+
+ /* Restore signal handlers
+ */
+#if DK4_HAVE_SIGACTION
+ if (0 != s_f_i) {
+ /* ERROR: Failed to install signal handlers */
+ log_1(21);
+ iexval = EXIT_FAILURE;
+ }
+ if (0 != sint) {
+ if (0 != sigaction(SIGINT, &oint, NULL)) {
+ s_f_r = 1;
+ }
+ }
+ if (0 != sterm) {
+ if (0 != sigaction(SIGTERM, &oterm, NULL)) {
+ s_f_r = 1;
+ }
+ }
+#ifdef SIGPIPE
+ if (0 != spipe) {
+ if (0 != sigaction(SIGPIPE, &opipe, NULL)) {
+ s_f_r = 1;
+ }
+ }
+#endif
+ if (0 != s_f_r) {
+ /* ERROR: Failed to restore signal handlers */
+ log_1(22);
+ iexval = EXIT_FAILURE;
+ }
+#else
+ if (NULL != oterm) { sigset(SIGTERM, oterm); }
+ if (NULL != oint ) { sigset(SIGINT, oint ); }
+#ifdef SIGPIPE
+ if (NULL != opipe) { sigset(SIGPIPE, opipe); }
+#endif
+#endif
+
+ /* Set exit status code depending on interactive mode
+ */
+ if (0 != intera) { exval = iexval; }
+
+ /* Finish tracing
+ */
+ $? "- main %d", exval
+ $!trace-end
+
+ /* Exit
+ */
+ exit(exval); return exval;
+}
+
+#else
+/* if (DK4_CHAR_SIZE == 1) && ((DK4_HAVE_SIGACTION) || (DK4_HAVE_SIGSET)) */
+
+/** Main program.
+ @param argc Number of command line arguments.
+ @param argv Command line arguments array.
+ @return Exit status code.
+*/
+int main(int argc, char *argv[])
+{
+ fputs("printqdc: ERROR: Program can not be used on this system!\n", stderr);
+ fflush(stderr);
+ exit(EXIT_FAILURE); return EXIT_FAILURE;
+}
+
+#endif
+/* if (DK4_CHAR_SIZE == 1) && ((DK4_HAVE_SIGACTION) || (DK4_HAVE_SIGSET)) */
+