/*
	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: printqda.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 printqda.c The printqda module.
*/


#line 29 "printqda.ctr"

#include "printqd.h"
#include "printqda.h"





#line 36 "printqda.ctr"


/**	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[] = {
/* 0 */
"printqda",

/* 1 */
"dkt-3",

/* 2 */
" ",

/* 3 */
"acct-check",

/* 4 */
"acct-start",

/* 5 */
"acct-end",

/* 6 */
"printqdc",

NULL


#line 85 "printqda.ctr"
};



/**	Localized message texts used by the program.
*/
static char const * const	pqda_loc[] = {
/* 0 */
"printqda.str",

/* 1 */
"Option was already set: \"",

/* 2 */
"\"!",

/* 3 */
"Option not started by a character: \"",

/* 4 */
"\"!",

/* 5 */
"Empty option: \"",

/* 6 */
"\"!",

/* 7 */
"Syntax error in request!",

/* 8 */
"Syntax error, string not finalized!",

/* 9 */
"Request contents too long!",

/* 10 */
"Incomplete request! Missing one from:\nuser name, printer name, page count, job name, or job title!",

/* 11 */
"Too few arguments in request!",

/* 12 */
"Incomplete request, missing either user or printer name!",

/* 13 */
"Illegal control sub-request: \"",

/* 14 */
"\"!",

/* 15 */
"Connection failed, skipping all remaining input!",

/* 16 */
"Name of system configuration directory too long:\n\"",

/* 17 */
"\"!",

/* 18 */
"Failed to find system configuration directory!",

/* 19 */
"Only printqda can process control requests, not printqdc!",

NULL


#line 159 "printqda.ctr"
};



/**	Request types (first word in request line).
*/
static char const * const	pqda_request_types[] = {
/* 0 */
"info",

/* 1 */
"acct-check",

/* 2 */
"acct-start",

/* 3 */
"acct-end",

/* 4 */
"jobstart",

/* 5 */
"filestart",

/* 6 */
"fileend",

/* 7 */
"jobend",

/* 8 */
"control",

NULL


#line 177 "printqda.ctr"
};



/**	Possible responses to LPRng jobstart requests.
*/
static char const * const	pqda_decisions[] = {
/* 0 */
"ACCEPT",

/* 1 */
"REMOVE",

/* 2 */
"HOLD",

NULL


#line 189 "printqda.ctr"
};



/**	Subrequests of control request.
*/
static char const * const	pqda_control_sub_requests[] = {
/* 0 */
"r$eset",

/* 1 */
"a$dd",

/* 2 */
"d$atabase-cleanup",

NULL


#line 201 "printqda.ctr"
};




/**	Initialize job structure.
	@param	job	Job structure to initialize.
*/
static
void
pqda_job_init(pqda_job_t *job)
{
  

#line 214 "printqda.ctr"
  dk3mem_res((void *)job, sizeof(pqda_job_t));
  job->app = NULL;
  job->lmsg = NULL;
  job->cmsg = NULL;
  job->exval = 3;	

#line 219 "printqda.ctr"
  job->fadm = 0;	

#line 220 "printqda.ctr"
  job->fcerr = 0;
  job->up = NULL;
  job->lo = NULL;
  

#line 224 "printqda.ctr"
}



/**	Clean up job structure before exiting program.
	@param	job	Job structure to clean up.
*/
static
void
pqda_job_cleanup(pqda_job_t *job)
{
  

#line 236 "printqda.ctr"
  if(job->app) {
    dk3app_close(job->app); job->app = NULL;
  } 

#line 239 "printqda.ctr"
}



/**	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. */
  

#line 257 "printqda.ctr"
  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'; } 

#line 268 "printqda.ctr"
      if(0 == strcmp(p1, pqda_c8_kw[0])) {
        job->fadm = 1;	

#line 270 "printqda.ctr"
      }
    }
  } 

#line 273 "printqda.ctr"
}



/**	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;
  

#line 289 "printqda.ctr"
  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;
    }
  } 

#line 310 "printqda.ctr"
  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;
  

#line 326 "printqda.ctr"
  if(('a' <= kc) && ('z' >= kc)) {
    back = (job->lo)[kc - 'a'];
  } else {
    if(('A' <= kc) && ('Z' >= kc)) {
      back = (job->up)[kc - 'A'];
    }
  } 

#line 333 "printqda.ctr"
  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. */
  

#line 354 "printqda.ctr"
  for(i = 0; i < 26; i++) { (job->up)[i] = NULL; (job->lo)[i] = NULL; }
  st = 0;
  ptr = p2;
  ps = NULL;
  while(*ptr) {	

#line 359 "printqda.ctr"
    switch(st) {
      case 0: {		/* in space before a string. */
        if('\'' == *ptr) {
	  st = 1;
	  ps = ptr;
	}
      } break;
      case 1: {		/* in string. */
        switch(*ptr) {
	  case '\'': {	

#line 369 "printqda.ctr"
	    *ptr = '\0';
	    st = 0;
	    if(ps) {	

#line 372 "printqda.ctr"
	      ps++;
	      if('-' == ps[0]) {
	        if('\0' != ps[1]) {
		  if(!pqda_lprng_set_option(job, ps[1], &(ps[2]))) {
		    back = 0;	

#line 377 "printqda.ctr"
		    if(job->fadm) {
		      /* ERROR: Not a character */
		      dk3app_log_3(job->app, DK3_LL_ERROR, job->lmsg, 3, 4, ps);
		    }
		  }
		} else {	

#line 383 "printqda.ctr"
		  back = 0;
		  if(job->fadm) {
		    /* ERROR in string, empty option */
		    dk3app_log_3(job->app, DK3_LL_ERROR, job->lmsg, 5, 6, ps);
		  }
		}
	      }
	    } else {	

#line 391 "printqda.ctr"
	      back = 0;
	      if(job->fadm) {
	        /* ERROR in input! */
		dk3app_log_1(job->app, DK3_LL_ERROR, job->lmsg, 7);
	      }
	    }
	  } break;
	  case '\\': {	

#line 399 "printqda.ctr"
	    st = 2;
	  } break;
	}
      } break;
      case 2: {		/* in string, backslash found. */
        st = 1;
      } break;
    }
    ptr++;
  }
  if(0 != st) {		

#line 410 "printqda.ctr"
    back = 0;
    if(job->fadm) {
      /* ERROR: Incorrect input! */
      dk3app_log_1(job->app, DK3_LL_ERROR, job->lmsg, 8);
    }
  } 

#line 416 "printqda.ctr"
  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;
  

#line 439 "printqda.ctr"
  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);
    }
  } 

#line 481 "printqda.ctr"
  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;
  

#line 511 "printqda.ctr"
  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;	

#line 624 "printqda.ctr"
      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
  

#line 642 "printqda.ctr"
  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;
  

#line 661 "printqda.ctr"
  ib3[0] = '\0';
  switch(act) {
    case 0: {	

#line 664 "printqda.ctr"
      back = 1;
    } break;
    case 1: {	

#line 667 "printqda.ctr"
      back = 1;
    } break;
    case 4: {	

#line 670 "printqda.ctr"
      back = 1;
    } break;
  }
  if(back) {
    strcpy(ib3, ib2);
    dk3str_c8_delnl(ib3);
    if(!(strlen(ib3) > 0)) {
      back = 0;
    }
  }
  

#line 681 "printqda.ctr"
  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. */
  

#line 705 "printqda.ctr"
  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)) {	

#line 748 "printqda.ctr"
		        switch(dk3str_c8_array_index(pqda_decisions, ib3, 0)) {
			  case 1: {
			    job->exval = 3;	

#line 751 "printqda.ctr"
			  } break;
			  case 2: {
			    job->exval = 6;	

#line 754 "printqda.ctr"
			  } break;
			}
		      } else {		

#line 757 "printqda.ctr"
		      }
		    }
		  }
		}
	      }
	      dk3socket_close(sock, NULL, NULL); sock = INVALID_SOCKET;
	    } else {
	      job->fcerr = 1;
	      job->exval = 1;		

#line 766 "printqda.ctr"
	      /* 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 {	

#line 778 "printqda.ctr"
	  }
	}
      }
    }
  }
  

#line 784 "printqda.ctr"
}



/**	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;
  

#line 798 "printqda.ctr"
  res = pqdconf_read(
    &(job->cfg),
    cfgfilename,
    ((job->fadm) ? PQD_PROGRAM_TYPE_ADMIN : PQD_PROGRAM_TYPE_MULTIPLEXOR),
    job->app, job->cmsg
  );
  if(res) {			

#line 805 "printqda.ctr"
    res = pqdconf_check(
      &(job->cfg),
      ((job->fadm) ? PQD_PROGRAM_TYPE_ADMIN : PQD_PROGRAM_TYPE_MULTIPLEXOR),
      job->app, job->cmsg
    );
    if(res) {			

#line 811 "printqda.ctr"
      

#line 812 "printqda.ctr"
      job->exval = 0;	

#line 813 "printqda.ctr"
      pqda_process_input(job);
    } else {			

#line 815 "printqda.ctr"
      /* ERROR: Check failed! */
    }
  } else {			

#line 818 "printqda.ctr"
    /* ERROR: Failed to read configuration! */
  }
  pqdconf_cleanup(&(job->cfg));
  

#line 822 "printqda.ctr"
}



/**	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. */
  

#line 836 "printqda.ctr"
  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
    }
  } 

#line 879 "printqda.ctr"
}



/**	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. */
  

#line 893 "printqda.ctr"
  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);
  }
  

#line 903 "printqda.ctr"
}



/**	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. */
  

#line 925 "printqda.ctr"
  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! */
  } 

#line 935 "printqda.ctr"
}
#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. */
  

#line 953 "printqda.ctr"
  

#line 954 "printqda.ctr"
  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);
  

#line 998 "printqda.ctr"
  

#line 999 "printqda.ctr"
  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

