summaryrefslogtreecommitdiff
path: root/support/dktools/printqda.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/printqda.ctr
Initial commit
Diffstat (limited to 'support/dktools/printqda.ctr')
-rw-r--r--support/dktools/printqda.ctr1038
1 files changed, 1038 insertions, 0 deletions
diff --git a/support/dktools/printqda.ctr b/support/dktools/printqda.ctr
new file mode 100644
index 0000000000..0e33a91351
--- /dev/null
+++ b/support/dktools/printqda.ctr
@@ -0,0 +1,1038 @@
+%% options
+
+copyright owner = Dirk Krause
+copyright year = 2012-xxxx
+license = bsd
+
+
+
+%% header
+
+
+/** Printqda job structure.
+*/
+typedef struct {
+ pqd_conf_t cfg; /**< Configuration. */
+ dk3_app_t *app; /**< Application structure. */
+ char const * const *lmsg; /**< Localized message texts. */
+ char const * const *cmsg; /**< Localized messages for config. */
+ char **up; /**< Uppercase option arguments. */
+ char **lo; /**< Lowercase option arguments. */
+ int exval; /**< Exit status code. */
+ int fadm; /**< Flag: Running as printqda. */
+ int fcerr; /**< Flag: Connection error occured. */
+} pqda_job_t;
+
+
+
+%% module
+
+#include "printqd.h"
+#include "printqda.h"
+
+
+
+$!trace-include
+
+
+/** If this is defined to 1, each original request / daemon
+ request pair is reported to stdout.
+*/
+#define PRINTQDA_DEBUG 0
+
+#if DK3_CHAR_SIZE == 1
+#if DK3_HAVE_STRUCT_SOCKADDR_UN
+
+
+/** Configuration file name relative to sysconf directory.
+*/
+static char const pqda_conffile[] = { PQD_CONFFILE };
+
+
+/** Constant non-localized keywords used by the module.
+*/
+static char const * const pqda_c8_kw[] = {
+$!string-table
+#
+# 0 Program name when running as administrator.
+#
+printqda
+#
+# 1 Program group name.
+#
+dktools
+#
+# 2 Space to separate arguments in line
+#
+
+#
+# 3 Request keyword
+#
+acct-check
+#
+# 4 Request keyword
+#
+acct-start
+#
+# 5 Request keyword
+#
+acct-end
+#
+# 6 Program running as multiplexor
+#
+printqdc
+$!end
+};
+
+
+
+/** Localized message texts used by the program.
+*/
+static char const * const pqda_loc[] = {
+$!string-table
+#
+# 0 Name of localized message texts file.
+#
+printqda.str
+#
+# 1 2 Option was already set!
+#
+Option was already set: "
+"!
+#
+# 3 4 Option not started by a character!
+#
+Option not started by a character: "
+"!
+#
+# 5 6 Empty option!
+#
+Empty option: "
+"!
+#
+# 7 Syntax error in request!
+#
+Syntax error in request!
+#
+# 8 Syntax error, string not finalized!
+#
+Syntax error, string not finalized!
+#
+# 9 Request contents too long!
+#
+Request contents too long!
+#
+# 10 Incomplete request!
+#
+Incomplete request! Missing one from:\nuser name, printer name, page count, job name, or job title!
+#
+# 11 Too few arguments in request!
+#
+Too few arguments in request!
+#
+# 12 Incomplete request!
+#
+Incomplete request, missing either user or printer name!
+#
+# 13 14 Illegal control sub-request!
+#
+Illegal control sub-request: "
+"!
+#
+# 15
+#
+Connection failed, skipping all remaining input!
+#
+# 16 17
+#
+Name of system configuration directory too long:\n"
+"!
+#
+# 18
+#
+Failed to find system configuration directory!
+#
+# 19
+#
+Only printqda can process control requests, not printqdc!
+$!end
+};
+
+
+
+/** Request types (first word in request line).
+*/
+static char const * const pqda_request_types[] = {
+$!string-table
+info
+acct-check
+acct-start
+acct-end
+jobstart
+filestart
+fileend
+jobend
+control
+$!end
+};
+
+
+
+/** Possible responses to LPRng jobstart requests.
+*/
+static char const * const pqda_decisions[] = {
+$!string-table
+ACCEPT
+REMOVE
+HOLD
+$!end
+};
+
+
+
+/** Subrequests of control request.
+*/
+static char const * const pqda_control_sub_requests[] = {
+$!string-table
+r$eset
+a$dd
+d$atabase-cleanup
+$!end
+};
+
+
+
+
+/** Initialize job structure.
+ @param job Job structure to initialize.
+*/
+static
+void
+pqda_job_init(pqda_job_t *job)
+{
+ $? "+ pqda_job_init"
+ dk3mem_res((void *)job, sizeof(pqda_job_t));
+ job->app = NULL;
+ job->lmsg = NULL;
+ job->cmsg = NULL;
+ job->exval = 3; $? ". exval = 3"
+ job->fadm = 0; $? ". fadm = 0"
+ job->fcerr = 0;
+ job->up = NULL;
+ job->lo = NULL;
+ $? "- pqda_job_init"
+}
+
+
+
+/** Clean up job structure before exiting program.
+ @param job Job structure to clean up.
+*/
+static
+void
+pqda_job_cleanup(pqda_job_t *job)
+{
+ $? "+ pqda_job_cleanup"
+ if(job->app) {
+ dk3app_close(job->app); job->app = NULL;
+ } $? "- pqda_job_cleanup"
+}
+
+
+
+/** Check whether the program is run as administration program printqda
+ or as multiplexor printqdc.
+ The result is stored in fadm.
+ @param job Job structure.
+ @param exename Name of the executable file running.
+*/
+static
+void
+pqda_check_admin(pqda_job_t *job, char const *exename)
+{
+ char bu[DK3_MAX_PATH]; /* Buffer for modification. */
+ char *p1; /* Start of program name. */
+ char *p2; /* File name suffix. */
+ $? "+ pqda_check_admin"
+ if(exename) {
+ if(strlen(exename) < sizeof(bu)) {
+ strcpy(bu, exename);
+ p1 = dk3str_rchr(bu, '/');
+ if(p1) {
+ p1++;
+ } else {
+ p1 = bu;
+ }
+ p2 = dk3str_rchr(p1, '.');
+ if(p2) { *p2 = '\0'; } $? ". \"%!8s\"==\"%!8s\"", p1, pqda_c8_kw[0]
+ if(0 == strcmp(p1, pqda_c8_kw[0])) {
+ job->fadm = 1; $? ". fadm = 1"
+ }
+ }
+ } $? "- pqda_check_admin %d", job->fadm
+}
+
+
+
+/** Store an LPRng option.
+ @param job Job structure.
+ @param kc Key character.
+ @param v Value to store.
+ @return 1 on success, 0 on error.
+*/
+static
+int
+pqda_lprng_set_option(pqda_job_t *job, char kc, char *v)
+{
+ int back = 0;
+ $? "+ pqda_lprng_set_option %!8c \"%!8s\"", kc, TR_8STR(v)
+ if(('a' <= kc) && ('z' >= kc)) {
+ if((job->lo)[kc - 'a']) {
+ if(job->fadm) {
+ /* WARNING: Option set twice! */
+ dk3app_log_3(job->app, DK3_LL_WARNING, job->lmsg, 1, 2, v);
+ }
+ }
+ (job->lo)[kc - 'a'] = v;
+ back = 1;
+ } else {
+ if(('A' <= kc) && ('Z' >= kc)) {
+ if((job->up)[kc - 'A']) {
+ if(job->fadm) {
+ /* WARNING: Option set twice! */
+ dk3app_log_3(job->app, DK3_LL_WARNING, job->lmsg, 1, 2, v);
+ }
+ }
+ (job->up)[kc - 'A'] = v;
+ back = 1;
+ }
+ } $? "- pqda_lprng_set_option %d", back
+ return back;
+}
+
+
+
+/** Retrieve one LPRng option.
+ @param job Job structure.
+ @param kc Key character.
+ @return Pointer to option value if defined, NULL otherwise.
+*/
+static
+char *
+pqda_lprng_get_option(pqda_job_t *job, char kc)
+{
+ char *back = NULL;
+ $? "+ pqda_lprng_get_option %!8c", kc
+ if(('a' <= kc) && ('z' >= kc)) {
+ back = (job->lo)[kc - 'a'];
+ } else {
+ if(('A' <= kc) && ('Z' >= kc)) {
+ back = (job->up)[kc - 'A'];
+ }
+ } $? "- pqda_lprng_get_option \"%!8s\"", TR_8STR(back)
+ return back;
+}
+
+
+
+
+/** Retrieve LPRng specific options.
+ @param job Job structure.
+ @param p2 String containing the options.
+ @return 1 on success, 0 on error.
+*/
+static
+int
+pqda_lprng_options(pqda_job_t *job, char *p2)
+{
+ char *ptr; /* Current character to process. */
+ char *ps; /* Start of current string. */
+ int back = 1;
+ int i; /* Traverse all up and lo pointers. */
+ int st; /* Current reader state. */
+ $? "+ pqda_lprng_options \"%!8s\"", p2
+ for(i = 0; i < 26; i++) { (job->up)[i] = NULL; (job->lo)[i] = NULL; }
+ st = 0;
+ ptr = p2;
+ ps = NULL;
+ while(*ptr) { $? ". st = %d c = %!8c", st, *ptr
+ switch(st) {
+ case 0: { /* in space before a string. */
+ if('\'' == *ptr) {
+ st = 1;
+ ps = ptr;
+ }
+ } break;
+ case 1: { /* in string. */
+ switch(*ptr) {
+ case '\'': { $? ". string end"
+ *ptr = '\0';
+ st = 0;
+ if(ps) { $? ". ps"
+ ps++;
+ if('-' == ps[0]) {
+ if('\0' != ps[1]) {
+ if(!pqda_lprng_set_option(job, ps[1], &(ps[2]))) {
+ back = 0; $? "! failed to save"
+ if(job->fadm) {
+ /* ERROR: Not a character */
+ dk3app_log_3(job->app, DK3_LL_ERROR, job->lmsg, 3, 4, ps);
+ }
+ }
+ } else { $? "! error in string"
+ back = 0;
+ if(job->fadm) {
+ /* ERROR in string, empty option */
+ dk3app_log_3(job->app, DK3_LL_ERROR, job->lmsg, 5, 6, ps);
+ }
+ }
+ }
+ } else { $? "! ps"
+ back = 0;
+ if(job->fadm) {
+ /* ERROR in input! */
+ dk3app_log_1(job->app, DK3_LL_ERROR, job->lmsg, 7);
+ }
+ }
+ } break;
+ case '\\': { $? ". backslash"
+ st = 2;
+ } break;
+ }
+ } break;
+ case 2: { /* in string, backslash found. */
+ st = 1;
+ } break;
+ }
+ ptr++;
+ }
+ if(0 != st) { $? "! wrong state"
+ back = 0;
+ if(job->fadm) {
+ /* ERROR: Incorrect input! */
+ dk3app_log_1(job->app, DK3_LL_ERROR, job->lmsg, 8);
+ }
+ } $? "- pqda_lprng_options %d", back
+ return back;
+}
+
+
+
+/** Convert a filestart/fileend request.
+ @param job Job structure.
+ @param rq First request word.
+ @param ib3 Input buffer 3 to use for response.
+ @return 1 on success, 0 on error.
+*/
+static
+int
+pqda_file_startend(pqda_job_t *job, char const *rq, char *ib3)
+{
+ char *pn; /* Printer name. */
+ char *un; /* User name. */
+ char *pc; /* Pagecount value as text. */
+ char *jn; /* Print job name. */
+ char *jt; /* Print job title. */
+ size_t sz; /* Size of converted request. */
+ int back = 0;
+ $? "+ pqda_file_startend"
+ un = NULL; pn = NULL; pc = NULL; jn = NULL; jt = NULL;
+ un = pqda_lprng_get_option(job, 'n');
+ pn = pqda_lprng_get_option(job, 'P');
+ pc = pqda_lprng_get_option(job, 'p');
+ jt = pqda_lprng_get_option(job, 'J');
+ jn = pqda_lprng_get_option(job, 'A');
+ if(!(jn)) { jn = pqda_lprng_get_option(job, 'D'); }
+ if(!(jn)) { jn = pn; }
+ if(!(jt)) { jt = jn; }
+ if((un) && (pn) && (pc) && (jt) && (jn)) {
+ sz = 5 * strlen(pqda_c8_kw[2]);
+ sz += strlen(rq);
+ sz += strlen(un);
+ sz += strlen(pn);
+ sz += strlen(pc);
+ sz += strlen(jt);
+ sz += strlen(jn);
+ if(PQD_INPUT_BUFFER_SIZE > sz) {
+ strcpy(ib3, rq);
+ strcat(ib3, pqda_c8_kw[2]);
+ strcat(ib3, pn);
+ strcat(ib3, pqda_c8_kw[2]);
+ strcat(ib3, un);
+ strcat(ib3, pqda_c8_kw[2]);
+ strcat(ib3, pc);
+ strcat(ib3, pqda_c8_kw[2]);
+ strcat(ib3, jn);
+ strcat(ib3, pqda_c8_kw[2]);
+ strcat(ib3, jt);
+ back = 1;
+ } else {
+ if(job->fadm) {
+ /* ERROR: Request contents too long! */
+ dk3app_log_1(job->app, DK3_LL_ERROR, job->lmsg, 9);
+ }
+ }
+ } else {
+ if(job->fadm) {
+ /* ERROR: Incomplete jobstart/jobend request! */
+ dk3app_log_1(job->app, DK3_LL_ERROR, job->lmsg, 10);
+ }
+ } $? "- pqda_file_startend %d", back
+ return back;
+}
+
+
+
+/** Prepare input for printqd.
+ @param job Job structure.
+ @param ib1 Original request, unmodified.
+ @param ib3 Input buffer for printqd, our destination.
+ @param p2 Arguments to original request, writable copy.
+ @param act Request type.
+*/
+static
+int
+pqda_daemon_input(
+ pqda_job_t *job,
+ char *ib1,
+ char *ib3,
+ char *p2,
+ int act
+)
+{
+ char *parts[16]; /* Splitted request string. */
+ char *un; /* User name. */
+ char *pn; /* Printer name. */
+ size_t na; /* Number of elements in nparts. */
+ size_t sz; /* String length of result string. */
+ int res; /* Operation result. */
+ int back = 0;
+ $? "+ pqda_daemon_input \"%!8s\"", p2
+ if((act < 8) || (job->fadm)) { /* control requests only printqda. */
+ un = NULL;
+ pn = NULL;
+ switch(act) {
+ case 0: { /* info */
+ na = dk3str_c8_explode(parts, 15, p2, NULL);
+ if(2 <= na) {
+ back = 1;
+ } else {
+ if(job->fadm) {
+ /* ERROR: Too few arguments in request! */
+ dk3app_log_1(job->app, DK3_LL_ERROR, job->lmsg, 11);
+ }
+ }
+ } break;
+ case 1: { /* acct-check */
+ na = dk3str_c8_explode(parts, 15, p2, NULL);
+ if(2 <= na) {
+ back = 1;
+ } else {
+ if(job->fadm) {
+ /* ERROR: Too few arguments in request! */
+ dk3app_log_1(job->app, DK3_LL_ERROR, job->lmsg, 11);
+ }
+ }
+ } break;
+ case 2: { /* acct-start */
+ na = dk3str_c8_explode(parts, 15, p2, NULL);
+ if(5 <= na) {
+ back = 1;
+ } else {
+ if(job->fadm) {
+ /* ERROR: Too few arguments in request! */
+ dk3app_log_1(job->app, DK3_LL_ERROR, job->lmsg, 11);
+ }
+ }
+ } break;
+ case 3: { /* acct-end */
+ na = dk3str_c8_explode(parts, 15, p2, NULL);
+ if(5 <= na) {
+ back = 1;
+ } else {
+ if(job->fadm) {
+ /* ERROR: Too few arguments in request */
+ dk3app_log_1(job->app, DK3_LL_ERROR, job->lmsg, 11);
+ }
+ }
+ } break;
+ case 4: { /* jobstart */
+ if(pqda_lprng_options(job, p2)) {
+ un = pqda_lprng_get_option(job, 'n');
+ pn = pqda_lprng_get_option(job, 'P');
+ if((un) && (pn)) {
+ sz = strlen(pqda_c8_kw[3]);
+ sz += 2 * strlen(pqda_c8_kw[2]);
+ sz += strlen(un);
+ sz += strlen(pn);
+ if(sz < PQD_INPUT_BUFFER_SIZE) {
+ strcpy(ib3, pqda_c8_kw[3]);
+ strcat(ib3, pqda_c8_kw[2]);
+ strcat(ib3, pn);
+ strcat(ib3, pqda_c8_kw[2]);
+ strcat(ib3, un);
+ back = 1;
+ } else {
+ if(job->fadm) {
+ /* ERROR: Request data too long! */
+ dk3app_log_1(job->app, DK3_LL_ERROR, job->lmsg, 9);
+ }
+ }
+ } else {
+ if(job->fadm) {
+ /* ERROR: Incomplete information in request! */
+ dk3app_log_1(job->app, DK3_LL_ERROR, job->lmsg, 12);
+ }
+ }
+ }
+ } break;
+ case 5: { /* filestart */
+ if(pqda_lprng_options(job, p2)) {
+ back = pqda_file_startend(job, pqda_c8_kw[4], ib3);
+ }
+ } break;
+ case 6: { /* fileend */
+ if(pqda_lprng_options(job, p2)) {
+ back = pqda_file_startend(job, pqda_c8_kw[5], ib3);
+ }
+ } break;
+ case 7: { /* jobend */
+ /* Nothing to do, we ignore this request. */
+ } break;
+ case 8: { /* control */
+ na = dk3str_c8_explode(parts, 15, p2, NULL);
+ if(na > 0) {
+ res = dk3str_array_abbr(pqda_control_sub_requests, parts[0], '$', 0);
+ if(-1 < res) {
+ back = 1;
+ } else {
+ if(job->fadm) {
+ /* ERROR: Too few arguments in request! */
+ dk3app_log_3(job->app, DK3_LL_ERROR, job->lmsg, 13, 14, parts[0]);
+ }
+ }
+ } else {
+ if(job->fadm) {
+ dk3app_log_1(job->app, DK3_LL_ERROR, job->lmsg, 11);
+ }
+ }
+ } break;
+ }
+ } else {
+ if((8 == act) && (!(job->fadm))) {
+ job->exval = 1; $? ". exval = 1"
+ dk3app_log_1(job->app, DK3_LL_ERROR, job->lmsg, 19);
+#if DK3_HAVE_SYSLOG
+ openlog(pqda_c8_kw[6], LOG_PID, LOG_LPR);
+ syslog(LOG_ERR, "Attempt to send control request to printqdc!");
+ closelog();
+#endif
+ }
+ }
+#if PRINTQDA_DEBUG
+ if(back) {
+ printf("%s\n%s\n", ib1, ib3);
+ } else {
+ if(7 != act) {
+ printf("!!! FAILED %s\n", ib1);
+ }
+ }
+#endif
+ $? "- pqda_daemon_input %d ib3 = \"%!8s\"", back, ib3
+ return back;
+}
+
+
+
+/** Convert daemon response to this programs response.
+ @param job Job structure.
+ @param ib3 Destination buffer.
+ @param ib2 Daemon response.
+ @param act Request type.
+ @return 1 if we must write output to standard output,
+ 0 otherwise.
+*/
+static
+int
+pqda_daemon_output(pqda_job_t *job, char *ib3, char *ib2, int act)
+{
+ int back = 0;
+ $? "+ pqda_daemon_output"
+ ib3[0] = '\0';
+ switch(act) {
+ case 0: { $? ". info"
+ back = 1;
+ } break;
+ case 1: { $? ". acct-check"
+ back = 1;
+ } break;
+ case 4: { $? ". jobstart"
+ back = 1;
+ } break;
+ }
+ if(back) {
+ strcpy(ib3, ib2);
+ dk3str_c8_delnl(ib3);
+ if(!(strlen(ib3) > 0)) {
+ back = 0;
+ }
+ }
+ $? "- pqda_daemon_output %d", back
+ return back;
+}
+
+
+
+/** Process all input lines found on standard input.
+ @param job Job structure
+*/
+static
+void
+pqda_process_input(pqda_job_t *job)
+{
+ char ib1[PQD_INPUT_BUFFER_SIZE]; /* Original input. */
+ char ib2[PQD_INPUT_BUFFER_SIZE]; /* Copy for test. */
+ char ib3[PQD_INPUT_BUFFER_SIZE]; /* Daemon input. */
+ char *p1; /* Request keyword. */
+ char *p2; /* Request arguments. */
+ dk3_socket_t sock; /* Socket to daemon. */
+ size_t sz; /* Request size. */
+ int act; /* Action to take. */
+ int bw; /* Bytes written. */
+ int first; /* Flag: First resp. */
+ int res; /* Shutdown result. */
+ $? "+ pqda_process_input"
+ while(fgets(ib1, sizeof(ib1), stdin)) {
+ if(!(job->fcerr)) {
+ dk3str_c8_delnl(ib1);
+ strcpy(ib2, ib1);
+ p1 = dk3str_c8_start(ib2, NULL);
+ if(p1) {
+ if(*p1 != '#') {
+ p2 = dk3str_c8_next(p1, NULL);
+ act = dk3str_c8_array_index(pqda_request_types, p1, 0);
+ strcpy(ib3, ib1);
+ if(pqda_daemon_input(job, ib1, ib3, p2, act)) {
+ sz = strlen(ib3);
+ sock = dk3socket_un_stream_client(
+ (job->cfg).usn, 0L, 0L, NULL, job->app
+ );
+ if(INVALID_SOCKET != sock) {
+ bw = dk3socket_send(sock, ib3, sz, 0L, 0L, NULL, job->app);
+ if(bw >= 0) {
+ res = dk3socket_shutdown(
+ sock, DK3_TCPIP_SHUTDOWN_WRITE, NULL, job->app
+ );
+ if(res) {
+ first = 1;
+ ib2[0] = '\0';
+ do {
+ bw = dk3socket_recv(
+ sock, ib3, (sizeof(ib3) - 1), 0L, 0L, NULL, job->app
+ );
+ if(bw > 0) {
+ if(first) {
+ first = 0;
+ ib3[((size_t)bw < sizeof(ib3)) ? bw : (sizeof(ib3) - 1)]
+ = '\0';
+ strcpy(ib2, ib3);
+ }
+ }
+ } while(bw > 0);
+ if(!(first)) {
+ if(pqda_daemon_output(job, ib3, ib2, act)) {
+ fputs(ib3, stdout);
+ fputc('\n', stdout);
+ fflush(stdout);
+ if(!(job->fadm)) { $? ". check \"%!8s\"", ib3
+ switch(dk3str_c8_array_index(pqda_decisions, ib3, 0)) {
+ case 1: {
+ job->exval = 3; $? ". exval = 3"
+ } break;
+ case 2: {
+ job->exval = 6; $? ". exval = 3"
+ } break;
+ }
+ } else { $? ". feel as printqda"
+ }
+ }
+ }
+ }
+ }
+ dk3socket_close(sock, NULL, NULL);
+#if VERSION_BEFORE_20150821
+ sock = INVALID_SOCKET;
+#endif
+ } else {
+ job->fcerr = 1;
+ job->exval = 1; $? ". exval = 1"
+ /* FATAL: Connection failed, skipping all remaining input */
+ if(job->fadm) {
+ dk3app_log_1(job->app, DK3_LL_FATAL, job->lmsg, 15);
+ } else {
+#if DK3_HAVE_SYSLOG
+ openlog(pqda_c8_kw[6], LOG_PID, LOG_LPR);
+ syslog(LOG_ERR, "Failed to connect to printqd! Skipping all input!");
+ closelog();
+#endif
+ }
+ }
+ } else { $? "! pqda_daemon_input \"%!8s\"", ib1
+ }
+ }
+ }
+ }
+ }
+ $? "- pqda_process_input"
+}
+
+
+
+/** Process configuration file and run.
+ @param job Job structure.
+ @param cfgfilename Name of configuration file.
+*/
+static
+void
+pqda_run_with_config_filename(pqda_job_t *job, char const *cfgfilename)
+{
+ int res;
+ $? "+ pqda_run_with_config_filename \"%!8s\"", TR_8STR(cfgfilename)
+ res = pqdconf_read(
+ &(job->cfg),
+ cfgfilename,
+ ((job->fadm) ? PQD_PROGRAM_TYPE_ADMIN : PQD_PROGRAM_TYPE_MULTIPLEXOR),
+ job->app, job->cmsg
+ );
+ if(res) { $? ". config read ok"
+ res = pqdconf_check(
+ &(job->cfg),
+ ((job->fadm) ? PQD_PROGRAM_TYPE_ADMIN : PQD_PROGRAM_TYPE_MULTIPLEXOR),
+ job->app, job->cmsg
+ );
+ if(res) { $? ". config check ok"
+ $? ". configuration was read successfully"
+ job->exval = 0; $? ". exval = 0"
+ pqda_process_input(job);
+ } else { $? "! config check"
+ /* ERROR: Check failed! */
+ }
+ } else { $? "! config read"
+ /* ERROR: Failed to read configuration! */
+ }
+ pqdconf_cleanup(&(job->cfg));
+ $? "- pqda_run_with_config_filename"
+}
+
+
+
+/** Find configuration file name and run with it.
+ @param job Job structure.
+*/
+static
+void
+pqda_search_for_config_filename(pqda_job_t *job)
+{
+ char bu[DK3_MAX_PATH]; /* Buffer to construct file name. */
+ char const *scd; /* System configuration directory. */
+ $? "+ pqda_search_for_config_filename"
+ scd = dk3inst_get_directory(1);
+ if(scd) {
+ if(strlen(scd) < sizeof(bu)) {
+ strcpy(bu, scd);
+ if((strlen(bu) + strlen(pqda_conffile)) < sizeof(bu)) {
+ strcat(bu, pqda_conffile);
+ pqda_run_with_config_filename(job, bu);
+ } else {
+ /* ERROR: sysconfdir name too long! */
+ if(job->fadm) {
+ dk3app_log_3(job->app, DK3_LL_ERROR, job->lmsg, 16, 17, scd);
+ } else {
+#if DK3_HAVE_SYSLOG
+ openlog(pqda_c8_kw[6], LOG_PID, LOG_LPR);
+ syslog(LOG_ERR, "File name of sysconfdir too long!");
+ closelog();
+#endif
+ }
+ }
+ } else {
+ /* ERROR: sysconfdir too long! */
+ if(job->fadm) {
+ dk3app_log_3(job->app, DK3_LL_ERROR, job->lmsg, 16, 17, scd);
+ } else {
+#if DK3_HAVE_SYSLOG
+ openlog(pqda_c8_kw[6], LOG_PID, LOG_LPR);
+ syslog(LOG_ERR, "File name of sysconfdir too long!");
+ closelog();
+#endif
+ }
+ }
+ } else {
+ /* ERROR: Failed to obtain sysconfdir! */
+ if(job->fadm) {
+ dk3app_log_1(job->app, DK3_LL_ERROR, job->lmsg, 18);
+ } else {
+#if DK3_HAVE_SYSLOG
+ openlog(pqda_c8_kw[6], LOG_PID, LOG_LPR);
+ syslog(LOG_ERR, "Failed to find sysconfdir!");
+ closelog();
+#endif
+ }
+ } $? "- pqda_search_for_config_filename"
+}
+
+
+
+/** Run after allocating an application structure.
+ @param job Job structure.
+*/
+static
+void
+pqda_run_with_app(pqda_job_t *job)
+{
+ char const * const *xargv; /* Command line arguments array. */
+ int xargc; /* Number of command line arguments. */
+ $? "+ pqda_run_with_app"
+ job->lmsg = dk3app_messages(job->app, pqda_loc[0], pqda_loc);
+ job->cmsg = pqdconf_get_messages(job->app);
+ xargc = dk3app_get_argc(job->app);
+ xargv = dk3app_get_argv(job->app);
+ if((xargc > 1) && (job->fadm)) {
+ pqda_run_with_config_filename(job, xargv[1]);
+ } else {
+ pqda_search_for_config_filename(job);
+ }
+ $? "- pqda_run_with_app"
+}
+
+
+
+/** For printqdc we use a silent application now instead of a
+ daemon application. Multiple instance of printqdc may run
+ at the same time, so we should not let them write all to
+ the same log file.
+*/
+#if VERSION_BEFORE_20120526
+/** When running as daemon (no output to stderr) we need the
+ current directory.
+ @param job Job structure.
+ @param argc Number of command line arguments.
+ @param argv Command line arguments array.
+*/
+static
+void
+pqda_run_for_daemon(pqda_job_t *job, int argc, char *argv[])
+{
+ char bu[DK3_MAX_PATH]; /* Buffer for current working dir. */
+ $? "+ pqda_run_for_daemon"
+ if(dk3sf_c8_getcwd_app(bu, sizeof(bu), NULL)) {
+ job->app = dk3app_open_daemon(
+ bu, argc, (dkChar const * const *)argv, pqda_c8_kw[1]
+ );
+ if(job->app) {
+ pqda_run_with_app(job);
+ }
+ } else {
+ /* ERROR: Failed to find current directory! */
+ } $? "- pqda_run_for_daemon"
+}
+#endif
+
+
+
+/** Entry point of the program.
+ @param argc Number of command line arguments.
+ @param argv Command line arguments array.
+ @return 0 on success, any other value indicates an error.
+*/
+int
+main(int argc, char *argv[])
+{
+ pqda_job_t job; /* Job structure. */
+ char *up[26]; /* Upper case option arguments. */
+ char *lo[26]; /* Lower case option arguments. */
+ int exval; /* Exit status code. */
+ $!trace-init /tmp/printqda.deb
+ $? "+ main"
+ pqda_job_init(&job);
+ pqda_check_admin(&job, argv[0]);
+ job.up = up;
+ job.lo = lo;
+
+#if VERSION_BEFORE_20120526
+ if(job.fadm) {
+ job.app = dk3app_open_command(
+ argc, (dkChar const * const *)argv, pqda_c8_kw[1]
+ );
+ if(job.app) {
+ pqda_run_with_app(&job);
+ } else {
+ fputs("printqda: ERROR: Not enough memory (RAM/swap)!\n", stderr);
+ fflush(stderr);
+ }
+ } else {
+ pqda_run_for_daemon(&job, argc, argv);
+ }
+#endif
+ if(job.fadm) {
+ job.app = dk3app_open_command(
+ argc, (dkChar const * const *)argv, pqda_c8_kw[1]
+ );
+ } else {
+ job.app = dk3app_open_silent(
+ argc, (dkChar const * const *)argv, pqda_c8_kw[1]
+ );
+ }
+ if(job.app) {
+ pqda_run_with_app(&job);
+ } else {
+ if(job.fadm) {
+ fputs("printqda: ERROR: Not enough memory (RAM/swap)!\n", stderr);
+ fflush(stderr);
+ }
+ }
+ exval = job.exval;
+#if 0
+ /* NO, EXIT CODE MUST INDICATE ACTION TOO! */
+ if(!(job.fadm)) { exval = 0; }
+#endif
+ pqda_job_cleanup(&job);
+ $? "- main %d", exval
+ $!trace-end
+ fflush(stdout);
+ exit(exval); return exval;
+}
+
+
+
+#else
+/** Program entry point.
+ @param argc
+ @param argv
+ @return 0 on success, any other value indicates an error.
+*/
+int main(int argc, char *argv[])
+{
+ fprintf(stderr, "printqd: ERROR: No UNIX domain sockets available!\n");
+ fflush(stderr);
+ exit(1);
+}
+#endif
+#else
+/** Program entry point.
+ @param argc
+ @param argv
+ @return 0 on success, any other value indicates an error.
+*/
+int main(int argc, char *argv[])
+{
+ fprintf(
+ stderr,
+ "printqd: ERROR: This program does not support wide characters (%d)!\n",
+ DK3_CHAR_SIZE
+ );
+ fflush(stderr);
+ exit(1);
+}
+#endif
+