/*
Copyright (c) 2001-2010, 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 
  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 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.
*/



/**	@file	yalc.c	The yalc module used by klpr and others.
*/


/* #define DEBUG 1 */

#include <dk.h>
#include <dksf.h>
#include <dkmem.h>
#include <dkstr.h>
#include <dksignal.h>
#include <dktcpip.h>
#include <dksto.h>
#include <dkapp.h>
#include <dkwin.h>
#include <dkstream.h>
#include <dklogc.h>
#include <dkma.h>

/**	0 as long long unsigned.
*/
#if DK_HAVE_LONG_LONG_INT
#define ULLZERO 0ULL
#else
#define ULLZERO 0UL
#endif

#if DK_HAVE_STDLIB_H
#include <stdlib.h>
#endif
#if DK_HAVE_UNISTD_H
#include <unistd.h>
#endif
#if DK_HAVE_SIGNAL_H
#include <signal.h>
#endif
#if DK_HAVE_STRING_H
#include <string.h>
#endif
#if DK_HAVE_CTYPE_H
#include <ctype.h>
#endif
#if DK_HAVE_CONIO_H
#include <conio.h>
#endif
#if DK_HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#if DK_HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif


/**	Inside the yalc module.
*/
#define DK_YALC_C 1

#include "yalc.h"
#include "dktools-version.h"




#line 102 "yalc.ctr"




/**	Avoid double-free.
*/
#define DO_NOT_FREE_REQUEST_PDU 1


/**	Dot.
*/
static char str_dot[] = { "." };

/**	Equal sign.
*/
static char str_equal[] = { " = " };



/**	Default application name.
*/
static char default_appname[] = { "yanolc" };



/**	File name separator.
*/
static char fnsep[] = {
#if DK_HAVE_FEATURE_BACKSLASH
  "\\"
#else
  "/"
#endif
};



#if DK_HAVE_LONG_LONG_INT
/**	Convert long long int to text.
	@param	s	Result buffer.
	@param	ul	Value to convert.
*/
static
void
ull_to_string DK_P2(char *,s, unsigned long long,ul)
{
#if _MSC_VER >= 1100
  sprintf(s, "%I64u", ul);
#else
  sprintf(s, "%llu", ul);
#endif
}
#endif



#if DK_HAVE_LIBNETSNMP || DK_HAVE_LIBUCDSNMP

#if DK_HAVE_LIBNETSNMP
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/utilities.h>
#ifdef __cplusplus
extern "C" {
#endif
#if DK_HAVE_NETSNMP_ENABLE_FILELOG
void netsnmp_enable_filelog DK_PR((netsnmp_log_handler *, int));
#endif
#ifdef __cplusplus
};
#endif
#else
#define UCD_COMPATIBLE 1
#include <ucd-snmp/ucd-snmp-config.h>
#include <ucd-snmp/ucd-snmp-includes.h>
#include <ucd-snmp/snmp_vars.h>
#include <ucd-snmp/util_funcs.h>
#endif



/**	Printer state: Ready.
*/
#define PRINTER_STATE_NORMAL		0

/**	Printer state: Printing.
*/
#define PRINTER_STATE_BUSY		1

/**	Printer state: Warning.
*/
#define PRINTER_STATE_WARNING		2

/**	Printer state: Going offline.
*/
#define PRINTER_STATE_GO_OFFLINE	3

/**	Printer state: Offline.
*/
#define PRINTER_STATE_OFFLINE		4

/**	Printer state: Warmup.
*/
#define PRINTER_STATE_WARMUP		5

/**	Printer state: Standby.
*/
#define PRINTER_STATE_STANDBY		6

/**	Printer state: unknown.
*/
#define PRINTER_STATE_UNKNOWN		7

/**	Printer state: Self-test.
*/
#define PRINTER_STATE_TESTING		8



/**	Texts for printer states.
*/
static char *printer_state_msg[] = {
  "READY", "PRINTING", "READY/WARNING", "SHUTDOWN",
  "OFFLINE", "WARMUP", "STANDBY", "UNKNOWN-STATE",
  "TESTING"
};



/**	Check 2 OIDs for equality.
	@param	o1	Left OID.
	@param	l1	Number of elements in o1.
	@param	o2	Right OID.
	@param	l2	Number of elements in o2.
	@return	1 if both OIDs are equal, 0 otherwise.
*/
static int
oids_equal DK_P4(oid *,o1,size_t,l1,oid *,o2,size_t,l2)
{
  int back = 0;
  size_t i;
  
  if(l1 == l2) {
    back = 1;
    for(i = 0; i < l1; i++) {
      if(o1[i] != o2[i]) {
        back = 0;
      }
    }
  }
  
  return back;
}



/**	SNMP variable to inspect.
*/
typedef struct {
  /* Low number indicates high priority */
  unsigned long lineno;		/**< Line number in snmpyalc cfg file. */
  char          *oid_text;	/**< Text representation of OID. */
  oid           oid[MAX_OID_LEN];	/**< OID buffer. */
  size_t        oid_len;		/**< Number of elements used in oid. */
  int           t;	/**< Variable type: 0=unknown, 1=boolean, 2=text. */
  int           found;		/**< Flag: Value found for this variable. */
  long          long_value;	/**< Long integer found. */
  char          *string_value;	/**< String value found. */
} Yalc_Snmp_Variable;



/**	Create variable.
	@param	lineno	Line number in snmpyalc cfg file.
	@param	oidtext	Text representation of OID to inspect.
	@return	Pointer to new variable on success, NULL on error.
*/
static Yalc_Snmp_Variable *
new_ysv DK_P2(unsigned long, lineno, char *, oidtext)
{
  Yalc_Snmp_Variable *back = NULL;
  
  back = dk_new(Yalc_Snmp_Variable,1);
  if(back) {
    back->oid_text = dkstr_dup(oidtext);
    if(!(back->oid_text)) {
      dk_delete(back); back = NULL;
    }
  }
  if(back) {
    back->lineno = lineno;
    back->t = 0;
    back->found = 0;
    back->long_value = 0L;
    back->string_value = NULL;
  }
  
  return back;
}



/**	Destroy variable.
	@param	ptr	Variable to destroy.
*/
static void
delete_ysv DK_P1(Yalc_Snmp_Variable *,ptr)
{
  char *p;
  if(ptr) {
    p = ptr->oid_text;
    if(p) { dk_delete(p); ptr->oid_text = NULL; }
    p = ptr->string_value;
    if(p) { dk_delete(p); ptr->string_value = NULL; }
    ptr->lineno = 0UL; ptr->t = 0; ptr->found = 0; ptr->long_value = 0L;
    dk_delete(ptr);
  }
}



/**	Compare two variables to inspect by line number.
	@param	p1	Left variable.
	@param	p2	Right variable.
	@param	how	Comparison criteria (ignored).
	@return	Comparison result.
*/
int
compare_ysv DK_P3(void *,p1,void *,p2,int,how)
{
  int back = 0;
  Yalc_Snmp_Variable *ptr1, *ptr2;
  
  if(p1 && p2) {
    ptr1 = (Yalc_Snmp_Variable *)p1;
    ptr2 = (Yalc_Snmp_Variable *)p2;
    if(ptr1->lineno > ptr2->lineno) {
      back = 1;
    } else {
      if(ptr1->lineno < ptr2->lineno) {
        back = -1;
      }
    }
  }
  
  return back;
}



/**	Configuration keywords.
*/
static char *snmp_config_keywords[] = {
  "te$xt",
  "ty$pe",

  NULL
};



/**	Variable types.
*/
static char *snmp_type_keywords[] = {
  "b$oolean",	/* boolean */			/*  0 */
  "ib$oolean",	/* inverted boolean */		/*  1 */
  "d$isplay",	/* display string */		/*  2 */

  NULL
};



/**	Add OIDs to inspect for snmpyalc request to container.
	@param	a	Application.
	@param	st	Container with OIDs to inspect.
	@param	typename	SNMP type name.
	@return	1 on success, 0 on error.
*/
static int
fill_snmp_storage_from_stream DK_P4(dk_app_t *,app,dk_storage_t *,st,dk_stream_t *,cfgstream,char *,typename)
{
  int err, found, cc, is_this_for_me, keyno, typeno;
  unsigned long lineno;
  char il[256], *ptrstart, *p1, *p2;
  Yalc_Snmp_Variable *ysv_cur;

  
  ymp_snmp_start_config_file();
  found = err = is_this_for_me = 0; lineno = 0UL;
  cc = 1; ysv_cur = NULL;
  while(cc) {
    if(dkstream_gets(cfgstream,il,sizeof(il))) {
      lineno++;
      dkstr_delcomm(il, '#');
      ptrstart = dkstr_start(il, NULL);
      if(ptrstart) {
        if(*ptrstart == '[') {
	  ysv_cur = NULL;
	  ptrstart++;
	  dkstr_chomp(ptrstart, NULL);
	  dkstr_delcomm(ptrstart, ']');
	  
	  if(strcmp(typename,ptrstart) == 0) {
	    is_this_for_me = found = 1;
	    ymp_snmp_start_config_section();
	  } else {
	    is_this_for_me = 0;
	    ymp_snmp_end_config_section();
	  }
	} else {
	  if(is_this_for_me) {
	    if((il[0] == ' ') || (il[0] == '\t')) {	
	      if(ysv_cur) {
	        dkstr_chomp(il, NULL);
	        p1 = dkstr_chr(il, '=');
	        if(p1) {
	          *(p1++) = (char)0;
		  p1 = dkstr_start(p1, NULL);
		  if(p1) {
		    p2 = dkstr_start(il, NULL);
		    if(p2) {
		      dkstr_chomp(p2, NULL);
		      keyno = dkstr_array_abbr(
		        snmp_config_keywords,
		        p2,
		        '$',
		        0
		      ); 
		      switch(keyno) {
		        case 0: {
			  char *pa, *pb;
		          
			  pb = dkstr_dup(p1);
			  if(pb) {
			    pa = ysv_cur->string_value;
			    if(pa) { dk_delete(pa); ysv_cur->string_value = NULL; }
			    ysv_cur->string_value = pb;
			  } else {
			    
			    dkapp_err_memory(app,sizeof(char),(strlen(p1)+1));
			    cc = 0; err = 1;
			  }
		        } break;
		        case 1: {
		          
			  typeno = dkstr_array_abbr(
			    snmp_type_keywords,
			    p1,
			    '$',
			    0
			  );
			  if(typeno > -1) {
			    ysv_cur->t = (typeno + 1);
			  } else {
			    
			    yme_snmp_bad_type(p1,lineno);
			    cc = 0; err = 1;
			  }
		        } break;
		        default: {
		          
			  yme_snmp_bad_conf(p2, lineno);
			  cc = 0; err = 1;
		        } break;
		      }
		    } else {
		      
		      yme_snmp_missing_key(lineno);
		      cc = 0; err = 1;
		    }
		  } else {
		    
		    yme_snmp_missing_val(lineno);
		    cc = 0; err = 1;
		  }
	        } else {
	          
	        }
	      } else {
	        
		yme_snmp_no_var(lineno);
		cc = 0; err = 1;
	      }
	    } else {					
	      dkstr_chomp(ptrstart, NULL);
	      ysv_cur = new_ysv(lineno,ptrstart);
	      if(ysv_cur) {
	        if(!dksto_add(st,(void *)ysv_cur)) {
		  cc = 0; err = 1;
		  
		  dkapp_err_memory(app,sizeof(dk_storage_node_t),1);
		}
	      } else {
	        
		dkapp_err_memory(app,sizeof(Yalc_Snmp_Variable),1);
		cc = 0; err = 1;
	      }
	    }
	  }
	}
      }
    } else {
      cc = 0;
    }
  }
  if(!found) {
    yme_snmp_type_not_found(typename);
    
  }
  if(err) {
    found = 0;
    
  }
  if(is_this_for_me) {
    ymp_snmp_end_config_section();
  }
  ymp_snmp_end_config_file();
  
  return found;
}



/**	OID for device status.
*/
static char str_oid_hrDeviceStatus[] =
{ "1.3.6.1.2.1.25.3.2.1.5.1" };



/**	OID for printer status.
*/
static char str_oid_hrPrinterStatus[] =
{ "1.3.6.1.2.1.25.3.5.1.1.1" };



/**	Add OIDs to inspect for klpinfo request to container.
	@param	a	Application.
	@param	st	Container with OIDs to inspect.
	@param	typename	SNMP type name.
	@return	1 on success, 0 on error.
*/
static int
fill_short_snmp_storage_from_stream DK_P3(dk_app_t *,app,dk_storage_t *,st,char *,typename)
{
  int err, found, cc, is_this_for_me; /* int keyno, typeno; */
  unsigned long lineno;
  /* char il[256], *ptrstart, *p1, *p2; */
  Yalc_Snmp_Variable *ysv_cur;

  
  ymp_snmp_start_config_file();
  found = err = is_this_for_me = 0; lineno = 0UL;
  cc = 1; ysv_cur = NULL; found = 1;

  ysv_cur = new_ysv(0, str_oid_hrDeviceStatus);
  if(ysv_cur) {
    if(dksto_add(st, (void *)ysv_cur)) {
      ysv_cur = new_ysv(0, str_oid_hrPrinterStatus);
      if(ysv_cur) {
        if(!dksto_add(st, (void *)ysv_cur)) {
	  dkapp_err_memory(app,sizeof(dk_storage_node_t),1);
	  cc = 0; err = 1;
	} else {
	  
	}
      } else {
        dkapp_err_memory(app,sizeof(Yalc_Snmp_Variable),1);
	cc = 0; err = 1;
      }
    } else {
      dkapp_err_memory(app,sizeof(dk_storage_node_t),1);
      cc = 0; err = 1;
    }
  } else {
    dkapp_err_memory(app,sizeof(Yalc_Snmp_Variable),1);
    cc = 0; err = 1;
  }
  if(err) {
    found = 0;
    
  }
  if(is_this_for_me) {
    ymp_snmp_end_config_section();
  }
  ymp_snmp_end_config_file();
  
  return found;
}



/**	SNMP versions.
*/
static char *snmp_versions[] = {
  "1",
  "2",
  "2c",
  "2p",
  "3",

  NULL
};



/**	Show a parsed OID.
	@param	a	Application.
	@param	oidtext	Text representation of OID.
	@param	oidptr	OID elements array.
	@param	sz	Number of elements used in \a oidptr.
*/
static void
show_parsed_oid DK_P4(dk_app_t *,a,char *,oidtext,oid *,oidptr,size_t,sz)
{
  size_t i;
  char outbuffer[13*MAX_OID_LEN];
  char buffer[13];
  char *msg[3];
  if(sz <= MAX_OID_LEN) {
    for(i = 0; i < sz; i++) {
      sprintf(buffer, "%ld", (long)(oidptr[i]));
      if(i == 0) {
        strcpy(outbuffer, buffer);
      } else {
        strcat(outbuffer, str_dot);
	strcat(outbuffer, buffer);
	msg[0] = oidtext;
	msg[1] = str_equal;
	msg[2] = outbuffer;
      }
    }
    dkapp_log_msg(a, DK_LOG_LEVEL_DEBUG, msg, 3);
  }
}



/**	Default SNMP log file.
*/
static char default_snmp_log_file_name[] = { "snmp.log" };

/**	Preference key: SNMP log file name.
*/
static char pk_snmp_log_file_name[] = { "/log/snmp/file/name" };

/**	Preference key: Keep SNMP log file when exiting.
*/
static char pk_snmp_log_file_keep[] = { "/log/snmp/file/keep" };



/**	Find log file name for SNMP logging.
	@param	rq	YALC request.
	@param	app	Application.
	@param	buffer	Result buffer.
	@param	sz	Size of \a buffer.
	@return	1 on success, 0 on error.
*/
static int
find_snmp_log_file_name DK_P4(yalc_rq_t *,rq, dk_app_t *, app, char *,buffer, size_t,sz)
{
  int back = 0;
  char line[512], *p1;
  if(app && buffer && sz) {
    if(dkapp_get_pref(app, pk_snmp_log_file_keep, line, sizeof(line), 0)) {
      p1 = dkstr_start(line, NULL);
      if(p1) {
        dkstr_chomp(p1, NULL);
	if(dkstr_is_bool(p1)) {
	  if(dkstr_is_on(p1)) {
	    (rq->args).snmp.keep_logfile = 1;
	  }
	}
      }
    }
    if(dkapp_get_pref(app, pk_snmp_log_file_name, line, sizeof(line), 0)) {
      if(dkapp_transform_string_ext1(app,buffer,sz,line,1)) {
        back = 1;
      }
    } else {
      if(dkapp_tmpnam(app, line, sizeof(line))) {
        if(dkapp_transform_string_ext1(app,buffer,sz,line,1)) {
if((strlen(buffer)+strlen(default_snmp_log_file_name)+strlen(fnsep)) < sz) {
          strcat(buffer, fnsep);
	  strcat(buffer, default_snmp_log_file_name);
}
	}
      }
    }
  }
  if(back) {
    dksf_correct_fnsep(buffer);
  }
  return back;
}



/**	Parse OID using either netsnmp or ucdsnmp functions.
	@param	ysvptr	YALC SNMP variable.
	@param	oid_text	Text representation of OID.
	@param	oid_ptr		OID buffer.
	@param	oid_len		Size of \a oid_ptr in elements.
	@return	1 on success, 0 on error.
*/
static
int
my_read_objid DK_P4(\
  Yalc_Snmp_Variable *,ysv_ptr, char *,oid_text,\
  oid *,oid_ptr, size_t *,oid_len\
)
{
  int back = 0;
#if DK_HAVE_LIBNETSNMP
  if(snmp_parse_oid(oid_text, oid_ptr, oid_len)) {
    
#line 721 "yalc.ctr"
    
    
#line 723 "yalc.ctr"
    
#line 724 "yalc.ctr"
    
#line 725 "yalc.ctr"
    
#line 726 "yalc.ctr"
    
#line 727 "yalc.ctr"
    
#line 728 "yalc.ctr"
    
#line 729 "yalc.ctr"
    
#line 730 "yalc.ctr"
    back = 1;
  }
#else
  if(read_objid(oid_text, oid_ptr, oid_len)) {
    back = 1;
  }
#endif
  return back;
}



/**	Run snmpyalc request.
	@param	rq	YALC request.
	@param	h	SNMP host.
	@param	c	SNMP community.
	@param	t	???.
	@param	cfg	Configuration data stream.
	@param	snmpvers	SNMP version.
	@return	1 on success, 0 on error.
*/
static int
run_snmp_request DK_P6(yalc_rq_t *,rq,char *,h,char *,c,char *,t,dk_stream_t *,cfg,char *,snmpvers)
{
  int back = 0;
  dk_storage_t *st; dk_storage_iterator_t *stit;
  Yalc_Snmp_Variable *ysv_ptr;
#if DK_HAVE_LIBNETSNMP
  netsnmp_session session, *ss;
  netsnmp_pdu *request_pdu, *response_pdu;
  netsnmp_variable_list *vars;
#else
  struct snmp_session session, *ss;
  struct snmp_pdu *request_pdu, *response_pdu;
  struct variable_list *vars;
#endif
#if DK_HAVE_NETSNMP_ENABLE_FILELOG
  char lfnbuffer[512], *lfnptr = NULL;
#endif
  oid *oid_ptr;
  size_t oid_len;
  int must_continue, status, cc, sv;
  char *pa, *pb, *myprgname;
  
  st = dksto_open(0);
  if(st) {
    stit = dksto_it_open(st);
    if(stit) {
#if DK_HAVE_NETSNMP_ENABLE_FILELOG
      netsnmp_log_handler *logh = NULL;
#endif
      dksto_set_comp(st,compare_ysv,0);
      myprgname = dkapp_get_appname(rq->app);
      if(!myprgname) { myprgname = default_appname; }
#if DK_HAVE_NETSNMP_ENABLE_FILELOG
      logh = netsnmp_register_loghandler( NETSNMP_LOGHANDLER_FILE, 5 );
      if(logh) {
	lfnptr = default_snmp_log_file_name;
	if(rq->app) {
	  if(find_snmp_log_file_name(rq, rq->app, lfnbuffer, sizeof(lfnbuffer))) {
	    lfnptr = lfnbuffer;
	  }
	}
        logh->pri_max = 5;
	logh->token = strdup(lfnptr);
	if(logh->token) {
	  netsnmp_enable_filelog(logh, 0);
	}
      }
#endif
      init_snmp(myprgname);
      if(fill_snmp_storage_from_stream(rq->app,st,cfg,t)) {
        response_pdu = NULL;
        snmp_sess_init(&session);
	session.peername = h;
	session.version = SNMP_VERSION_1;
	sv = -1;
	if(snmpvers) {
	  sv = dkstr_array_index(snmp_versions, snmpvers, 0);
	}
	switch(sv) {
	  case 0: {
	    session.version = SNMP_VERSION_1;
	  } break;
	  case 1: {
	    session.version = SNMP_VERSION_2c;
	  } break;
	  case 2: {
	    session.version = SNMP_VERSION_2c;
	  } break;
	  case 3: {
	    session.version = SNMP_VERSION_2p;
	  } break;
	  case 4: {
	    session.version = SNMP_VERSION_3;
	  } break;
	  default: {
	    session.version = SNMP_VERSION_1;
	  } break;
	}
	session.community = (unsigned char *)c;
	session.community_len = strlen(c);
	ss = snmp_open(&session);
	if(ss) {			
	  must_continue = 1;
	  dksto_it_reset(stit);
	  while(must_continue) {
	    must_continue = 0;
	    response_pdu = NULL;
	    ysv_ptr = (Yalc_Snmp_Variable *)dksto_it_next(stit);
	    if(ysv_ptr) {		
	      request_pdu = snmp_pdu_create(SNMP_MSG_GET);
	      if(request_pdu) {		
	        oid_ptr = &(ysv_ptr->oid[0]);
		oid_len = MAX_OID_LEN;
		ysv_ptr->oid_len = 0;
		if(my_read_objid(ysv_ptr, ysv_ptr->oid_text, oid_ptr, &oid_len)) {
		  
		  if(rq->app) {
		    if(dkapp_get_min_loglevel(rq->app) >= DK_LOG_LEVEL_DEBUG) {
		      show_parsed_oid(
		        rq->app, ysv_ptr->oid_text, oid_ptr, oid_len
		      );
		    }
		  }
		  ysv_ptr->oid_len = oid_len;
		  if(snmp_add_null_var(request_pdu, oid_ptr, oid_len)) {
		    
		    ymp_snmp_start_request();
		    status = snmp_synch_response(ss,request_pdu,&response_pdu);
		    ymp_snmp_end_request();
		    if(status == STAT_SUCCESS) {	
		      if(response_pdu->errstat == SNMP_ERR_NOERROR) {
		        
		        for(vars=response_pdu->variables; vars; vars=vars->next_variable) {
			  if(oids_equal(vars->name,vars->name_length,ysv_ptr->oid,ysv_ptr->oid_len)) {
back = 1;

switch((int)(vars->type)) {
  case ((int)(ASN_OCTET_STR)) : {
    
    switch(ysv_ptr->t) {
      case 1:
      case 2: {
        size_t lgt;
        pb = ysv_ptr->string_value;
        for(lgt = 0; lgt < vars->val_len; lgt++) {
          if(*pb != ' ') {
  	if(*pb != '\t') {
  	if(*pb != '\r') {
  	if(*pb != '\n') {
  	if(*pb) {
  	  ysv_ptr->long_value = 1L;
  	  ysv_ptr->found = 1;
  	}
  	}
  	}
  	}
  	}
          pb++;
        }
      } break;
      case 3: {
        size_t lgt;
        lgt = vars->val_len + 1;
        pa = dk_new(char,lgt);
        if(pa) {
          pb = ysv_ptr->string_value;
  	if(pb) {
  	  dk_delete(pb);
  	}
  	lgt--;
  	strncpy(pa, (char *)((vars->val).string), lgt);
  	pa[lgt] = (char)0;
          ysv_ptr->string_value = pa;
  	ysv_ptr->found = 1;
  	pb = pa;
  	while(*pb) {
  	  if((*pb == '\r') || (*pb == '\n')) {
  	    *pb = ' ';
  	  }
  	  pb++;
  	}
  	
        } else {
          back = 0;
  	
  	dkapp_err_memory(rq->app,sizeof(char),lgt);
        }
      } break;
    }
  } break;
  case ((int)(ASN_INTEGER)):
  case ((int)(ASN_COUNTER)):
  case ((int)(ASN_GAUGE)):
  case ((int)(ASN_TIMETICKS)): {
    switch(ysv_ptr->t) {
      case 1:
      case 2: {
        ysv_ptr->long_value = *((vars->val).integer);
        ysv_ptr->found = 1;
      } break;
      case 3: {
        char buffer[16];
        ysv_ptr->long_value = *((vars->val).integer);
        sprintf(buffer, "%ld", ysv_ptr->long_value);
        pa = dkstr_dup(buffer);
        if(pa) {
          pb = ysv_ptr->string_value;
  	if(pb) {
  	  dk_delete(pb);
  	}
  	ysv_ptr->string_value = pa;
  	ysv_ptr->found = 1;
        } else {
          back = 0;
  	if(rq->app) {
  	  dkapp_err_memory(rq->app, sizeof(char), (1+strlen(buffer)));
  	}
        }
      } break;
    }
  } break;
}
if(ysv_ptr->found) {
      switch(ysv_ptr->t) {
        case 1: {
	  if(ysv_ptr->long_value) {
	    if(ysv_ptr->string_value) {
	      printf("%s\n", ysv_ptr->string_value);
	      cc = 0;
	      (rq->args).snmp.output_found = 1;
	    } else {
	      if(ysv_ptr->oid_text) {
	        printf("%s\n", ysv_ptr->oid_text);
		cc = 0;
		(rq->args).snmp.output_found = 1;
	      }
	    }
	  }
	} break;
	case 2: {
	  if(!(ysv_ptr->long_value)) {
	    if(ysv_ptr->string_value) {
	      printf("%s\n", ysv_ptr->string_value);
	      cc = 0;
	      (rq->args).snmp.output_found = 1;
	    } else {
	      if(ysv_ptr->oid_text) {
	        printf("%s\n", ysv_ptr->oid_text);
		cc = 0;
		(rq->args).snmp.output_found = 1;
	      }
	    }
	  }
	} break;
	case 3: {
	  if(ysv_ptr->string_value) {
	    char c, *myptr;
	    myptr = ysv_ptr->string_value;
	    while(*myptr) {
	      c = *myptr;
	      if(isascii(c) && isprint(c)) {
	        fputc(c, stdout);
	      } else {
	        printf("0x%02X", (((int)c) & 0xFF));
	      }
	      myptr++;
	    }
	    fputc('\n', stdout);
	    cc = 0;
	    (rq->args).snmp.output_found = 1;
	  } else {
	    if(ysv_ptr->oid_text) {
	      printf("%s\n", ysv_ptr->oid_text);
	      cc = 0;
	      (rq->args).snmp.output_found = 1;
	    }
	  }
	} break;
      }
} else {				
  must_continue = 1;
}
			  }
			}
		      } else {		
		        must_continue = 1;	/* attempt next oid */
		      }
		    } else {
		      
		      yme_snmp_no_response();
		      printf("<<< UNREACHABLE >>>\n");
		      (rq->args).snmp.output_found = 1;
		    }
		    if(response_pdu) {
		      snmp_free_pdu(response_pdu); response_pdu = NULL;
		    }
		  } else {
		    back = 0;
		    
		    yme_snmp_request_pdu();
		  }
		} else {
		  back = 0;
		  
		  yme_snmp_bad_oid_string(ysv_ptr->oid_text);
		}
#ifndef DO_NOT_FREE_REQUEST_PDU
                snmp_free_pdu(request_pdu);
#endif
	      } else {		
	        /* Failed to create request PDU */
		yme_err_snmp_request_pdu();
	      }
	    } else {		
	      /* No more OIDs to check */
	    }
	  }	
	  snmp_close(ss);
	} else {
	  
	  if((rq->args).snmp.force_output) {
	    printf("<<< SNMP-ERROR: No session >>>\n");
	    (rq->args).snmp.output_found = 1;
	  }
	  yme_snmp_failed_to_open_session();
	}
      } else {		
      }
      /* cleanup */
      dksto_it_reset(stit);
      while((ysv_ptr = (Yalc_Snmp_Variable *)dksto_it_next(stit)) != NULL) {
        
#line 1064 "yalc.ctr"
	  
	  
	  
	  
	  
	  
#line 1070 "yalc.ctr"
	    
	  
#line 1072 "yalc.ctr"
	
#line 1073 "yalc.ctr"
        delete_ysv(ysv_ptr);
      }
#if DK_HAVE_NETSNMP_ENABLE_FILELOG
      if(logh) {
        snmp_disable_filelog();
        if(logh->token) {
	  free((void *)(logh->token)); logh->token = NULL;
	}
	netsnmp_remove_loghandler(logh);
#if TAKE_RISK_OF_DOUBLE_FREE
	free(logh);
#endif
      }
#endif
      dksto_it_close(stit); stit = NULL;
#if DK_HAVE_NETSNMP_ENABLE_FILELOG
      if(lfnptr) {
        if(!((rq->args).snmp.keep_logfile)) {
	  dksf_remove_file(lfnptr); lfnptr = NULL;
	}
      }
#endif
    } else {
      
      dkapp_err_memory(rq->app,sizeof(dk_storage_iterator_t),1);
    }
    dksto_close(st); st = NULL;
  } else {
    
    dkapp_err_memory(rq->app,sizeof(dk_storage_t),1);
  }
  
  return back;
}



/**	Receive SNMP int response.
	@param	rpdu	Response PDU.
	@param	str_oid	OID to find.
	@param	dv	Default value.
	@return	Value from response PDU or default value.
*/
#if DK_HAVE_LIB_NETSNMP
int
get_snmp_response_int_value DK_P3(netsnmp_pdu *,rpdu, char *,str_oid, int,dv)
#else
int
get_snmp_response_int_value DK_P3(struct snmp_pdu *,rpdu, char *,str_oid, int,dv)
#endif
{
  int back;
  oid oid[MAX_OID_LEN], *oid_ptr;
  size_t oid_len;
  char buffer[256];
#if DK_HAVE_LIBNETSNMP
  netsnmp_variable_list *vars;
#else
  struct variable_list *vars;
#endif
  
  back = dv;
  oid_ptr = oid; oid_len = MAX_OID_LEN;
#if DK_HAVE_LIBNETSNMP
  if(snmp_parse_oid(str_oid, oid_ptr, &oid_len)) {
#else
  if(read_objid(str_oid, oid_ptr, &oid_len)) {
#endif
    for(vars = rpdu->variables; vars; vars = vars->next_variable) {
      if(oids_equal(vars->name, vars->name_length, oid, oid_len)) {
        switch((int)(vars->type)) {
	  case ((int)(ASN_OCTET_STR)): {
	    if(vars->val_len < sizeof(buffer)) {
	      int i;
	      for(i=0; i < sizeof(buffer); i++) { buffer[i] = ' '; }
	      i = vars->val_len;
	      if(i > (sizeof(buffer)-1)) i = sizeof(buffer) - 1;
	      strncpy(buffer, (char *)((vars->val).string), i);
              buffer[i] = '\0';
	      if(sscanf(buffer, "%d", &i) == 1) {
	        back = i;
	      }
	    }
	  } break;
	  case ((int)(ASN_TIMETICKS)):
	  case ((int)(ASN_GAUGE)):
	  case ((int)(ASN_COUNTER)):
	  case ((int)(ASN_INTEGER)): {
	    back = *(vars->val).integer;
	  } break;
	}
      }
    }
  }
  
  return back;
}

/**	Device status texts.
*/
static char *device_status_msg[] = {
  "", "unknown", "running", "warning", "testing", "down"
};

/**	Printer status texts.
*/
static char *printer_status_msg[] = {
  "", "other", "unknown", "idle", "printing", "warmup"
};

/**	Run klpinfo request.
	@param	rq	YALC request.
	@param	h	SNMP host.
	@param	c	SNMP community.
	@param	t	???
	@param	snmpvers	SNMP version.
	@return	1 on success, 0 on error.
*/
static int
run_snmp_short_request DK_P5(yalc_rq_t *,rq,char *,h,char *,c,char *,t,char *,snmpvers)
{
  int back = 0;
  dk_storage_t *st; dk_storage_iterator_t *stit;
  Yalc_Snmp_Variable *ysv_ptr;
#if DK_HAVE_LIBNETSNMP
  netsnmp_session session, *ss;
  netsnmp_pdu *request_pdu, *response_pdu;
#else
  struct snmp_session session, *ss;
  struct snmp_pdu *request_pdu, *response_pdu;
#endif
#if DK_HAVE_NETSNMP_ENABLE_FILELOG
  char lfnbuffer[512], *lfnptr = NULL;
#endif
  oid *oid_ptr;
  size_t oid_len;
  int status, is_first, sv; /* int cc ; */
  char *myprgname; /* char *pa, *pb, *myprgname; */
  int hrDeviceStatus, hrPrinterStatus, summaryStatus;
  
  hrDeviceStatus = 1; hrPrinterStatus = 2; summaryStatus = PRINTER_STATE_UNKNOWN;
  st = dksto_open(0);
  if(st) {
    stit = dksto_it_open(st);
    if(stit) {
#if DK_HAVE_NETSNMP_ENABLE_FILELOG
      netsnmp_log_handler *logh = NULL;
#endif
      dksto_set_comp(st,compare_ysv,0);
      myprgname = dkapp_get_appname(rq->app);
      if(!myprgname) { myprgname = default_appname; }
#if DK_HAVE_NETSNMP_ENABLE_FILELOG
      logh = netsnmp_register_loghandler( NETSNMP_LOGHANDLER_FILE, 5 );
      if(logh) {
	lfnptr = default_snmp_log_file_name;
	if(rq->app) {
	  if(find_snmp_log_file_name(rq, rq->app, lfnbuffer, sizeof(lfnbuffer))) {
	    lfnptr = lfnbuffer;
	  }
	}
        logh->pri_max = 5;
	logh->token = strdup(lfnptr);
	if(logh->token) {
	  netsnmp_enable_filelog(logh, 0);
	}
      }
#endif
      init_snmp(myprgname);
      if(fill_short_snmp_storage_from_stream(rq->app,st,t)) {
        
        response_pdu = NULL;
        snmp_sess_init(&session);
	session.peername = h;
	session.version = SNMP_VERSION_1;
	sv = -1;
	if(snmpvers) {
	  sv = dkstr_array_index(snmp_versions, snmpvers, 0);
	}
	switch(sv) {
	  case 0: {
	    session.version = SNMP_VERSION_1;
	  } break;
	  case 1: {
	    session.version = SNMP_VERSION_2c;
	  } break;
	  case 2: {
	    session.version = SNMP_VERSION_2c;
	  } break;
	  case 3: {
	    session.version = SNMP_VERSION_2p;
	  } break;
	  case 4: {
	    session.version = SNMP_VERSION_3;
	  } break;
	  default: {
	    session.version = SNMP_VERSION_1;
	  } break;
	}
	session.community = (unsigned char *)c;
	session.community_len = strlen(c);
	ss = snmp_open(&session);
	if(ss) {
	  request_pdu = snmp_pdu_create(SNMP_MSG_GET);
	  if(request_pdu) {
	    is_first = 1;
	    dksto_it_reset(stit);
	    while((ysv_ptr = (Yalc_Snmp_Variable *)dksto_it_next(stit)) != NULL) {
	      
	      if(is_first) {
	        back = 1; is_first = 0;
	      }
	      oid_ptr = &(ysv_ptr->oid[0]);
	      oid_len = MAX_OID_LEN;
	      ysv_ptr->oid_len = 0;
#if DK_HAVE_LIBNETSNMP
	      
	      if(snmp_parse_oid(ysv_ptr->oid_text, oid_ptr, &oid_len)) {
	        
#line 1291 "yalc.ctr"
		
		
#line 1293 "yalc.ctr"
		
#line 1294 "yalc.ctr"
		
#line 1295 "yalc.ctr"
		
#line 1296 "yalc.ctr"
		
#line 1297 "yalc.ctr"
		
#line 1298 "yalc.ctr"
#else
	      
	      if(read_objid(ysv_ptr->oid_text, oid_ptr, &oid_len)) {
#endif
		
                if(rq->app) {
		  if(dkapp_get_min_loglevel(rq->app) >= DK_LOG_LEVEL_DEBUG) {
		    show_parsed_oid(
		      rq->app, ysv_ptr->oid_text, oid_ptr, oid_len
		    );
		  }
		}
	        ysv_ptr->oid_len = oid_len;
	        if(snmp_add_null_var(request_pdu, oid_ptr, oid_len)) {
		  
		} else {
	          back = 0;
		  
		  yme_snmp_request_pdu();
	        }
	      } else {
	        back = 0;
	        
		yme_snmp_bad_oid_string(ysv_ptr->oid_text);
	      }
	    }
	    if(back) {
	      
	      ymp_snmp_start_request();
	      status = snmp_synch_response(ss,request_pdu,&response_pdu);
	      ymp_snmp_end_request();
	      if(status == STAT_SUCCESS) {
	        
	        if(response_pdu->errstat == SNMP_ERR_NOERROR) {
		  
		  hrPrinterStatus = get_snmp_response_int_value(
		    response_pdu, str_oid_hrPrinterStatus, 2
		  );
		  hrDeviceStatus = get_snmp_response_int_value(
		    response_pdu, str_oid_hrDeviceStatus, 1
		  );
		  
		  if(hrPrinterStatus == 5) {
		    summaryStatus = PRINTER_STATE_WARMUP;
		  } else {
		    if(hrDeviceStatus == 5) {
		      summaryStatus = PRINTER_STATE_OFFLINE;
		    } else {
		      if((hrDeviceStatus == 2) || (hrDeviceStatus == 3)) {
		        switch(hrPrinterStatus) {
			  case 1: {
			    summaryStatus = PRINTER_STATE_STANDBY;
			  } break;
			  case 3: {
			    if(hrDeviceStatus == 2) {
			      summaryStatus = PRINTER_STATE_NORMAL;
			    } else {
			      summaryStatus = PRINTER_STATE_WARNING;
			    }
			  } break;
			  case 4: {
			    summaryStatus = PRINTER_STATE_BUSY;
			  } break;
			}
		      } else {
		        if(hrDeviceStatus == 4) {
			  summaryStatus = PRINTER_STATE_TESTING;
			}
		      }
		    }
		  }
		  if(summaryStatus > PRINTER_STATE_TESTING) {
		    summaryStatus = PRINTER_STATE_TESTING;
		  }
		  fputs(printer_state_msg[summaryStatus], stdout);
		  if((rq->args).snmp.run_verbose) {
		    fputs("   ", stdout);
		    fprintf(stdout, "device status = %d (", hrDeviceStatus);
		    if(hrDeviceStatus > 5)  hrDeviceStatus = 1;
		    if(hrDeviceStatus < 1)  hrDeviceStatus = 1;
		    fputs(device_status_msg[hrDeviceStatus], stdout);
		    fprintf(stdout, ")   printer status = %d (", hrPrinterStatus);
		    if(hrPrinterStatus < 1) hrPrinterStatus = 1;
		    if(hrPrinterStatus > 5) hrPrinterStatus = 2;
		    fputs(printer_status_msg[hrPrinterStatus], stdout);
		    fputs(")", stdout);
		  }
		  fputc('\n', stdout);
		} else { /* response_pdu->errstat == SNMP_ERR_NOERROR */
		  
		  if((rq->args).snmp.force_output) {
		    printf("<<< SNMP-ERROR: Bad response >>>\n");
		    (rq->args).snmp.output_found = 1;
		  }
		  yme_snmp_response_packet();
		} /* response_pdu->errstat == SNMP_ERR_NOERROR */
	      } else { /* status == STAT_SUCCESS */
	        
		yme_snmp_no_response();
		printf("<<< UNREACHABLE >>>\n");
		(rq->args).snmp.output_found = 1;
	      } /* status == STAT_SUCCESS */
	      if(response_pdu) {
	        snmp_free_pdu(response_pdu);
	      }
	    }
#ifndef DO_NOT_FREE_REQUEST_PDU
            snmp_free_pdu(request_pdu);
#endif
	  }
	  snmp_close(ss);
	} else {
	  
	  if((rq->args).snmp.force_output) {
	    printf("<<< SNMP-ERROR: No session >>>\n");
	    (rq->args).snmp.output_found = 1;
	  }
	  yme_snmp_failed_to_open_session();
	}
      }
      /* cleanup */
      dksto_it_reset(stit);
      while((ysv_ptr = (Yalc_Snmp_Variable *)dksto_it_next(stit)) != NULL) {
        
#line 1422 "yalc.ctr"
	  
	  
	  
	  
	  
	  
#line 1428 "yalc.ctr"
	    
	  
#line 1430 "yalc.ctr"
	
#line 1431 "yalc.ctr"
        delete_ysv(ysv_ptr);
      }
#if DK_HAVE_NETSNMP_ENABLE_FILELOG
      if(logh) {
        snmp_disable_filelog();
        if(logh->token) {
	  free((void *)(logh->token)); logh->token = NULL;
	}
	netsnmp_remove_loghandler(logh);
#if TAKE_RISK_OF_DOUBLE_FREE
	free(logh);
#endif
      }
#endif
      dksto_it_close(stit); stit = NULL;
#if DK_HAVE_NETSNMP_ENABLE_FILELOG
      if(lfnptr) {
        if(!((rq->args).snmp.keep_logfile)) {
	  dksf_remove_file(lfnptr); lfnptr = NULL;
	}
      }
#endif
    } else {
      
      dkapp_err_memory(rq->app,sizeof(dk_storage_iterator_t),1);
    }
    dksto_close(st); st = NULL;
  } else {
    
    dkapp_err_memory(rq->app,sizeof(dk_storage_t),1);
  }
  
  return back;
}
#else

/**	Run snmpyalc request.
	@param	rq	YALC request.
	@param	h	SNMP host.
	@param	c	SNMP community.
	@param	t	???
	@param	snmpvers	SNMP version.
	@return	1 on success, 0 on error.
*/
static int
run_snmp_request DK_P6(yalc_rq_t *,rq,char *,h,char *,c,char *,t,dk_stream_t *,cfg,char *,snmpvers)
{
  return 0;
}

/**	Run klpinfo request.
	@param	rq	YALC request.
	@param	h	SNMP host.
	@param	c	SNMP community.
	@param	t	???
	@param	snmpvers	SNMP version.
	@return	1 on success, 0 on error.
*/
static int
run_snmp_short_request DK_P5(yalc_rq_t *,rq,char *,h,char *,c,char *,t,char *,snmpvers)
{
  return 0;
}

#endif



/**	File name for configuratin file.
*/
static char configfile[] = { "/yanolc.cfg" };

/**	File name for SNMP configuration file.
*/
static char snmpcfgfile[] = { "/snmpyalc.cfg" };



/**	Check whether a file is available.
	@param	fn	File name.
	@return	1 if file is available, 0 if not.
*/
static
int
have_file DK_P1(char *,fn)
{
  int back = 0;
  dk_stat_t *stptr;
  int ft;
  
  stptr = dkstat_open(fn);
  if(stptr) {
    ft = dkstat_filetype(stptr);
    if((ft & (~(DK_FT_SYMLINK))) ==  DK_FT_REG) {
      back = 1;
    }
    dkstat_close(stptr);
  } 
  return back;
}



/**	Retrieve a setting from registry key.
	@param	rq	YALC request.
	@param	how	Information sources (2=user, 1=system).
	@param	key	Entry name.
	@param	buf	Result buffer.
	@param	sz	Size of \a buffer.
	@return	1 on success, 0 on error.
*/
static
int
regkey_retrieve DK_P5(yalc_rq_t *, rq, int, how, char *, key, char *, buf, size_t, sz)
{
  int back = 0;
#if DK_HAVE_WINREG_H
  LONG retval;
  DWORD dwType, used_sz;
  
  used_sz = sz;
  if((how & 2) && (((rq->reg).what) & 2)) {
    retval = RegQueryValueExA(
      (rq->reg).hkcu,
      key,
      NULL,
      &dwType,
      buf,
      &used_sz
    );
    if(retval == ERROR_SUCCESS) {
      if(dwType == REG_SZ) {
	if(used_sz <= sz) {
	  if(used_sz == ((DWORD)sz)) {
	    used_sz--;
	  }
	  buf[used_sz] = '\0';
	  back = 1;
	}
      }
    }
  }
  if(!back) {
    if((how & 1) && (((rq->reg).what) & 1)) {
      used_sz = sz;
      retval = RegQueryValueExA(
	(rq->reg).hklm,
	key,
	NULL,
	&dwType,
	buf,
	&used_sz
      );
      if(retval == ERROR_SUCCESS) {
	if(dwType == REG_SZ) {
	  if(used_sz <= sz) {
	    if(used_sz == ((DWORD)sz)) {
	      used_sz--;
	    }
	    buf[used_sz] = '\0';
	    back = 1;
	  }
	}
      }
    }
  }
#endif
  
  return back;
}



/**	YANOLC alias information.
*/
typedef struct {
  char *name;	/**< Alias name. */
  char *value;	/**< Target queue. */
} yalc_alias_info;



/**	Destroy alias information, release memory.
	@param	yai	Alias information to destroy.
*/
static
void
yai_remove DK_P1(yalc_alias_info *, yai)
{
  char *x;
  
  if(yai) { 
    x = yai->name;
    if(x) { dk_delete(x); }
    yai->name = NULL;
    x = yai->value;
    if(x) { dk_delete(x); }
    yai->value = NULL;
    dk_delete(yai);
  } 
}



/**	Create new alias information.
	@param	name	Alias name.
	@param	value	Alias value.
	@return	Pointer to new alias information on success, NULL on error.
*/
static
yalc_alias_info *
yai_new DK_P2(char *, name, char *, value)
{
  char *n, *v;
  yalc_alias_info *back = NULL;
  
  if(name && value) {
    back = dk_new(yalc_alias_info,1);
    if(back) {
      back->name = NULL; back->value = NULL;
      n = dkstr_dup(name); v = dkstr_dup(value);
      if(n && v) {
	back->name = n;
	back->value = v;
      } else {
	if(n) { dk_delete(n); }
	if(v) { dk_delete(v); }
	dk_delete(back);
	back = NULL;
      }
    }
  } 
  return back;
}



/**	YANOLC host information.
*/
typedef struct {
  char *name;			/**< Host. */
  int   type; /**< Host type: 0=unknown, 1=LPRNG, 2=BSD, 3=raw, 4=jetdirect */
  unsigned short portno;	/**< Port number on host. */
  unsigned short o_min;		/**< Minimum local port. */
  unsigned short o_max;		/**< Maximum local port. */
  char *xusers; 		/**< List of users allowed to change username */
  int   have_timeouts;		/**< Which timeouts are defined. */
  double lpr_timeout;		/**< Timeout for LPR. */
  double lpq_timeout;		/**< Timeout for LPQ. */
  double lprm_timeout;		/**< Timeout for LPRM. */
  double lpc_timeout;		/**< Timeout for LPC. */
  int   data_file_first; /**< Data file first: 0=unknown, 1=control, 2=data. */
  char   *snmp_target;		/**< Target for SNMP operations. */
} yalc_host_info;



/**	Create new host information.
	@param	name	Host name.
	@return	Pointer to new host information on success, NULL on error.
*/
static
yalc_host_info *
yhi_new DK_P1(char *, name)
{
  yalc_host_info *back = NULL;
  
  if(name) {
    back = dk_new(yalc_host_info,1);
    if(back) {
      back->name = NULL; back->type = 0;
      back->snmp_target = NULL;
      back->portno = back->o_min = back->o_max = 0;
      back->xusers = NULL;
      back->have_timeouts = 0;
      back->lpr_timeout = back->lpq_timeout =
      back->lprm_timeout = back->lpc_timeout = 0.0;
      back->name = dkstr_dup(name);
      if(!(back->name)) {
	dk_delete(back);
	back = NULL;
      }
    }
  } 
  return back;
}



/**	Destroy host information, release memory.
	@param	yhi	Host information.
*/
static
void
yhi_remove DK_P1(yalc_host_info *, yhi)
{
  char *x;
  
  if(yhi) {
    x = yhi->name;
    if(x) { dk_delete(x); }
    yhi->name = NULL;
    yhi->type = 0;
    yhi->portno = yhi->o_min = yhi->o_max = 0;
    x = yhi->xusers;
    if(x) { dk_delete(x); }
    yhi->xusers = NULL;
    yhi->have_timeouts = 0;
    yhi->lpr_timeout = yhi->lpq_timeout =
    yhi->lprm_timeout = yhi->lpc_timeout = 0.0;
    x = yhi->snmp_target;
    if(x) { dk_delete(x); }
    yhi->snmp_target = NULL;
    dk_delete(yhi);
  } 
}



/**	YANOLC device information.
*/
typedef struct {
  char *name;		/**< Device name, queue\@host or host%port. */
  yalc_host_info i;	/**< Options here overwrite host options. */
  yalc_host_info *ip;	/**< Host settings. */
} yalc_device_info;



/**	Create new device information.
	@param	name	Device name.
	@return	Pointer to new device information on success, NULL on error.
*/
static
yalc_device_info *
ydi_new DK_P1(char *, name)
{
  yalc_device_info *back = NULL;
  
  if(name) {
    back = dk_new(yalc_device_info,1);
    if(back) {
      back->name = NULL;
      (back->i).name = NULL;
      (back->i).type = 0;
      (back->i).portno = (back->i).o_min = (back->i).o_max = 0;
      (back->i).xusers = NULL;
      (back->i).have_timeouts = 0;
      (back->i).lpr_timeout = (back->i).lpq_timeout =
      (back->i).lprm_timeout = (back->i).lpc_timeout = 0.0;
      back->ip = NULL;
      back->name = dkstr_dup(name);
      if(!(back->name)) {
	dk_delete(back);
	back = NULL;
      }
    }
  } 
  return back;
}



/**	Destroy one device information, release memory.
	@param	ydi	Device information.
*/
static
void
ydi_remove DK_P1(yalc_device_info *, ydi)
{
  char *x;
  
  if(ydi) {
    x = ydi->name;
    if(x) { dk_delete(x); }
    ydi->name = NULL;
    ydi->ip = NULL;
    (ydi->i).name = NULL;
    (ydi->i).type = 0;
    (ydi->i).portno = (ydi->i).o_min = (ydi->i).o_max = 0;
    x = (ydi->i).xusers;
    if(x) { dk_delete(x); }
    (ydi->i).xusers = NULL;
    (ydi->i).have_timeouts = 0;
    (ydi->i).lpq_timeout = (ydi->i).lpq_timeout =
    (ydi->i).lprm_timeout = (ydi->i).lpc_timeout = 0.0;
    dk_delete(ydi);
  } 
}



/**	YANOLC configuration.
*/
typedef struct {
  /* aliases */
  dk_storage_t *a;			/**< Aliases container. */
  dk_storage_iterator_t *ai;		/**< Aliases iterator. */
  /* hosts */
  dk_storage_t *h;			/**< Hosts container. */
  dk_storage_iterator_t *hi;		/**< Hosts iterator. */
  /* print queues */
  dk_storage_t *p;			/**< Queues container. */
  dk_storage_iterator_t *pi;		/**< Queues iterator. */
  yalc_alias_info  *first_alias;	/**< First alias found. */
  yalc_device_info *first_device;	/**< First device found. */
  yalc_host_info   *first_host;		/**< First host found. */
} yalc_cfg;



/**	Destroy configuration, release memory.
	@param	cfg	YANOLC configuration.
*/
static
void
forget_cfg DK_P1(yalc_cfg *, cfg)
{
  yalc_alias_info *yai;
  yalc_host_info  *yhi;
  yalc_device_info *ydi;
  
  if(cfg) {
    if(cfg->first_alias) {
      cfg->first_alias = NULL;
    }
    if(cfg->first_device) {
      cfg->first_device = NULL;
    }
    if(cfg->first_host) {
      cfg->first_host = NULL;
    }
    if(cfg->ai) {
    dksto_it_reset(cfg->ai);
    while((yai = (yalc_alias_info *)dksto_it_next(cfg->ai))) {
      yai_remove(yai);
    }
    }
    if(cfg->hi) {
    dksto_it_reset(cfg->hi);
    while((yhi = (yalc_host_info *)dksto_it_next(cfg->hi))) {
      yhi_remove(yhi);
    }
    }
    if(cfg->pi) {
    dksto_it_reset(cfg->pi);
    while((ydi = (yalc_device_info *)dksto_it_next(cfg->pi))) {
      ydi_remove(ydi);
    }
    }
    if(cfg->pi) { dksto_it_close(cfg->pi); }
    cfg->pi = NULL;
    if(cfg->hi) { dksto_it_close(cfg->hi); }
    cfg->hi = NULL;
    if(cfg->ai) { dksto_it_close(cfg->ai); }
    cfg->ai = NULL;
    if(cfg->p) { dksto_close(cfg->p); }
    cfg->p = NULL;
    if(cfg->h) { dksto_close(cfg->h); }
    cfg->h = NULL;
    if(cfg->a) { dksto_close(cfg->a); }
    cfg->a = NULL;
    dk_delete(cfg);
  } 
}



/**	Compare two alias informations by name.
	@param	p1	Left alias information.
	@param	p2	Right alias information or name.
	@param	how	Comparison criteria (1=alias/name,
	others=alias/alias).
	@return	Comparison result.
*/
static
int
compare_yalc_alias_info DK_P3(void *, p1, void *, p2, int, how)
{
  int back = 0;
  yalc_alias_info *i1, *i2;
  char *n;
  if(p1 && p2) {
    i1 = (yalc_alias_info *)p1;
    switch(how) {
      case 1: {
	n = (char *)p2;
	if(i1->name) {
	  back = strcmp(i1->name, n);
	}
      } break;
      default : {
	i2 = (yalc_alias_info *)p2;
	if((i1->name) && (i2->name)) {
	  back = strcmp(i1->name, i2->name);
	}
      } break;
    }
  }
  return back;
}



/**	Compare two host informations by name.
	@param	p1	Left host information.
	@param	p2	Right host information or name.
	@param	how	Comparison criteria (1=information/name,
	others=information/information).
	@return	Comparison result.
*/
static
int
compare_yalc_host_info DK_P3(void *, p1, void *, p2, int, how)
{
  int back = 0;
  yalc_host_info *i1, *i2;
  char *n;
  if(p1 && p2) {
    switch(how) {
      case 1: {
	i1 = (yalc_host_info *)p1;
	n =  (char *)p2;
	if(i1->name) {
	  back = strcmp(i1->name,n);
	}
      } break;
      default: {
	i1 = (yalc_host_info *)p1;
	i2 = (yalc_host_info *)p2;
	if((i1->name) && (i2->name)) {
	  back = strcmp(i1->name, i2->name);
	}
      } break;
    }
  }
  return back;
}



/**	Compare two device informations.
	@param	p1	Left device information.
	@param	p2	Right device information.
	@param	how	Comparison criteria (1=device/name,
	others=device/device by name).
	@return	Comparison result.
*/
static
int
compare_yalc_device_info DK_P3(void *, p1, void *, p2, int, how)
{
  int back = 0;
  yalc_device_info *d1, *d2;
  char *n;

  if(p1 && p2) {
    d1 = (yalc_device_info *)p1;
    switch(how) {
      case 1: {
	n = (char *)p2;
	if(d1->name) {
	  back = strcmp(d1->name, n);
	}
      } break;
      default : {
	d2 = (yalc_device_info *)p2;
	if((d1->name) && (d2->name)) {
	  back = strcmp(d1->name, d2->name);
	}
      } break;
    }
  }
  return back;
}



/**	Create a new (empty) YANOLC configuration.
	@return	Pointer to new configuration on success, NULL on error.
*/
static
yalc_cfg *
yalc_cfg_new DK_P0()
{
  yalc_cfg *back = NULL;
  
  back = dk_new(yalc_cfg,1);
  if(back) {
    back->first_host = NULL;
    back->first_alias = NULL;
    back->first_device = NULL;
    back->a = back->h = back->p = NULL;
    back->ai = back->hi = back->pi = NULL;
    back->a = dksto_open(0);
    back->h = dksto_open(0);
    back->p = dksto_open(0);
    if(back->a) back->ai = dksto_it_open(back->a);
    if(back->h) back->hi = dksto_it_open(back->h);
    if(back->p) back->pi = dksto_it_open(back->p);
    if(!((back->a) && (back->h) && (back->p) && (back->ai) && (back->hi) && (back->pi))) {
      forget_cfg(back);
      back = NULL;
    } else {
      dksto_set_comp(back->a, compare_yalc_alias_info, 0);
      dksto_set_comp(back->h, compare_yalc_host_info, 0);
      dksto_set_comp(back->p, compare_yalc_device_info, 0);
    }
  } 
  return back;
}



/**	Configuration keywords.
*/
static char *cfg_keywords[] = {
  /*  0 */ "type",
  /*  1 */ "port",
  /*  2 */ "originate",
  /*  3 */ "xusers",
  /*  4 */ "timeout.lpr",
  /*  5 */ "timeout.lpq",
  /*  6 */ "timeout.lprm",
  /*  7 */ "timeout.lpc",
  /*  8 */ "data-file-first",
  /*  9 */ "snmp",
  NULL
};



/**	Print server types.
*/
static char *pstype_keywords[] = {
  /* 0 */	"lprng",
  /* 1 */	"bsd",
  /* 2 */	"raw",
  /* 3 */	"jetdirect",
  NULL
};



/**	Set double variable from string.
	@param	res	Pointer to result variable.
	@param	s	Text containing the value.
	@return	1 on success, 0 on error.
*/
static
int
set_double DK_P2(double *,res,char *,s)
{
  int back = 0;
  double to;
  if(sscanf(s,"%lf", &to) == 1) {
    *res = to; back = 1;
  }
  return back;
}



/**	Add YANOLC host information.
	@param	rq	YALC request.
	@param	yhi	Yanolc host information.
	@param	ptr	Key.
	@param	vptr	Value.
*/
static
void
add_yhi_entry DK_P4(yalc_rq_t *,rq,yalc_host_info *,yhi,char *,ptr,char *,vptr)
{
  unsigned x1, x2;
  char *xptr, *pa, *pb;
  
  switch(dkstr_array_index(cfg_keywords, ptr, 0)) {
    case 0: {
      
      if(vptr) {
        yhi->type = dkstr_array_index(pstype_keywords, vptr, 0) + 1;
	switch(yhi->type) {
	  case YALC_METHOD_BSD:
	  case YALC_METHOD_LPRNG: {
	    if(yhi->portno == 0) {
	      yhi->portno = 515;
	    }
	  } break;
	}
      }
    } break;
    case 1: {
      if(sscanf(vptr, "%u", &x1) == 1) {
	yhi->portno = x1;
      }
    } break;
    case 2: {
      xptr = dkstr_chr(vptr, '-');
      if(xptr) {
	*xptr = ' ';
	if(sscanf(vptr, "%u %u", &x1, &x2) == 2) {
	  yhi->o_min = x1;
	  yhi->o_max = x2;
	}
      } else {
	if(sscanf(vptr, "%u", &x1) == 1) {
	  yhi->o_min = yhi->o_max = x1;
	}
      }
    } break;
    case 3: {
      if(yhi->xusers) {
	xptr = yhi->xusers;
	dk_delete(xptr);
	yhi->xusers = NULL;
      }
      yhi->xusers = dkstr_dup(vptr);
      if(!(yhi->xusers)) {
	rq->read_cfg_res = 0; 
      }
    } break;
    case 4: {
      if(set_double(&(yhi->lpr_timeout), vptr)) {
	yhi->have_timeouts |= 1;
      } else {
	yhi->have_timeouts &= (~(1));
      }
    } break;
    case 5: {
      if(set_double(&(yhi->lpq_timeout), vptr)) {
	yhi->have_timeouts |= 2;
      } else {
	yhi->have_timeouts &= (~(2));
      }
    } break;
    case 6: {
      if(set_double(&(yhi->lprm_timeout), vptr)) {
	yhi->have_timeouts |= 4;
      } else {
	yhi->have_timeouts &= (~(4));
      }
    } break;
    case 7: {
      if(set_double(&(yhi->lpc_timeout), vptr)) {
	yhi->have_timeouts |= 8;
      } else {
	yhi->have_timeouts &= (~(8));
      }
    } break;
    case 8: {
      yhi->data_file_first = 1;
      if(dkstr_is_on(vptr)) {
	yhi->data_file_first = 2;
      }
    } break;
    case 9: {
      pa = dkstr_dup(vptr);
      if(pa) {
        pb = yhi->snmp_target;
	if(pb) { dk_delete(pb); }
	yhi->snmp_target = pa;
	
      } else {
        rq->read_cfg_res = 0;
        if(rq->app) {
          dkapp_err_memory(rq->app,sizeof(char),(strlen(vptr)+1));
	}
      }
    } break;
  } 
}



/**	Add file contents to YANOLC configuration.
	@param	rq	YALC request.
	@param	c	Configuration.
	@param	filename	Configuration file name.
*/
static
void
add_cfg DK_P3(yalc_rq_t *, rq, yalc_cfg *, c, char *, filename)
{
  char *ptr, *vptr;
  FILE *f;
  int ende;
  char line[1024];
  int what_section;
  yalc_alias_info *yai;
  yalc_host_info  *yhi;
  yalc_device_info *ydi;
  
  ptr = filename;
  yai = NULL; yhi = NULL; ydi = NULL;
  while(*ptr) {
#if DK_HAVE_FEATURE_BACKSLASH
    if(*ptr == '/') { *ptr = '\\'; }
#else
    if(*ptr == '\\') { *ptr = '/'; }
#endif
    ptr++;
  }
  if(rq) {
    if(rq->app) {
      f = dkapp_fopen(rq->app, filename, "r");
    } else {
      f = dksf_fopen(filename, "r");
    }
  } else {
    f = dksf_fopen(filename, "r");
  }
  if(f) {
    rq->read_cfg_res = 1; 
    ende = 0;
    what_section = 1;
    while(!ende) {
      if(fgets(line, sizeof(line), f)) {
	ptr = dkstr_chr(line, '#');
	if(ptr) { *ptr = '\0'; }
	ptr = dkstr_start(line, NULL);
	if(ptr) {
	  if(*ptr == '[') {
	    what_section = 0;
	    dkstr_chomp(ptr, NULL);
	    if(strcmp(ptr, "[aliases]") == 0) {
	      what_section = 1;
	      yai = NULL;
	    } else {
	      if(strcmp(ptr, "[hosts]") == 0) {
		what_section = 2;
		yhi = NULL;
	      } else {
		if(strcmp(ptr, "[devices]") == 0) {
		  what_section = 3;
		  ydi = NULL;
		}
	      }
	    }
	  } else {
	    vptr = dkstr_chr(ptr, '=');
	    if(vptr) {
	      *(vptr++) = '\0';
	      vptr = dkstr_start(vptr, NULL);
	      if(vptr) {
		dkstr_chomp(vptr, NULL);
	        dkstr_chomp(ptr, NULL);
	        switch(what_section) {
		  case 1: { /* aliases */
		    yai = dksto_it_find_like(c->ai,ptr,1);
		    if(yai) {
		      if(yai->value) {
		        dk_delete(yai->value);
		      }
		      yai->value = dkstr_dup(vptr);
		      if(!(yai->value)) {
		        rq->read_cfg_res = 0; 
		      }
		    } else {
		      yai = yai_new(ptr, vptr);
		      if(yai) {
			if(!(c->first_alias)) {
			  c->first_alias = yai;
			}
		        if(!dksto_add(c->a, (void *)yai)) {
			  yai_remove(yai);
			  yai = NULL;
			  rq->read_cfg_res = 0; 
		        }
		      } else {
		        rq->read_cfg_res = 0; 
		      }
		    }
		  } break;
		  case 2: { /* hosts */
		    if(yhi) {
		      add_yhi_entry(rq, yhi, ptr, vptr);
		    }
		  } break;
		  case 3: { /* devices */
		    if(ydi) {
		      add_yhi_entry(rq, &(ydi->i), ptr, vptr);
		    }
		  } break;
	        }
	      }
	    } else {
	      dkstr_chomp(ptr, NULL);
	      switch(what_section) {
		case 2: { /* hosts */
		  yhi = dksto_it_find_like(c->hi, ptr, 1);
		  if(!yhi) {
		    yhi = yhi_new(ptr);
		    if(yhi) {
		    if(!(c->first_host)) {
		      c->first_host = yhi;
		    }
		    if(!dksto_add(c->h, (void *)yhi)) {
		      yhi_remove(yhi);
		      yhi = NULL;
		      rq->read_cfg_res = 0; 
		    }
		    } else {
		      rq->read_cfg_res = 0; 
		    }
		  }
		} break;
		case 3: { /* devices */
		  ydi = dksto_it_find_like(c->pi, ptr, 1);
		  if(!ydi) {
		    ydi = ydi_new(ptr);
		    if(ydi) {
		      if(!(c->first_device)) {
			c->first_device = ydi;
		      }
		      if(!dksto_add(c->p, (void *)ydi)) {
			rq->read_cfg_res = 0; 
			ydi_remove(ydi);
			ydi = NULL;
		      }
		    } else {
		      rq->read_cfg_res = 0; 
		    }
		  }
		} break;
	      }
	    }
	  }
	}
      } else {
	ende = 1;
      }
    }
    fclose(f);
  } 
}



/**	Preference key: Yanolc configuration file.
*/
static char cfg_file[] = { "/yanolc/config-file" };

/**	Preference key: Yanolc SNMP configuratin file name.
*/
static char snmp_file[] = { "/yanolc/snmpcfg-file" };



/**	Find and open yanolc.cfg file.
	@param	rq	YALC request.
	@return	Pointer to stream on success, NULL on error.
*/
static dk_stream_t *
yalc_snmp_cfg_open DK_P1(yalc_rq_t *, rq)
{
  dk_stream_t *back = NULL;
  size_t mpl;
  int have_filename, x;
  char *fn, *logmsg[3];
  
  if(rq) {
    have_filename = 0;
    mpl = dksf_get_maxpathlen();
    fn = dk_new(char,mpl);
    if(fn) {
      /* command line preference or user preference */
      if(!have_filename) {
        if(rq->app) {
	  /*
	  x = DK_APP_PREF_EXCL_CMD | DK_APP_PREF_EXCL_USER;
	  x = (~(x));
	  */
	  x = DK_APP_PREF_EXCL_SYSTEM ;
	  
	  if(dkapp_get_pref(rq->app, snmp_file, fn, mpl, x)) {
	    dksf_correct_fnsep(fn);
	    if(have_file(fn)) {
	      
	      have_filename = 1;
	    } else { 
	    }
	  } else { 
	  }
	}
      }
      /* HKCU */
      if(!have_filename) {
        
        if(regkey_retrieve(rq, 2, &(snmp_file[7]), fn, mpl)) {
	  dksf_correct_fnsep(fn);
	  if(have_file(fn)) {
	    
	    have_filename = 1;
	  } else { 
	  }
	} else { 
	}
      }
      if(!have_filename) {
        if(rq->app) {
	  /*
	   x = DK_APP_PREF_EXCL_SYSTEM;
	   x = (~(x));
	   */
	   x = DK_APP_PREF_EXCL_USER | DK_APP_PREF_EXCL_CMD;
	   
	   if(dkapp_get_pref(rq->app, snmp_file, fn, mpl, x)) {
	     dksf_correct_fnsep(fn);
	     if(have_file(fn)) {
	       
	       have_filename = 1;
	     } else { 
	     }
	   } else { 
	   }
	}
      }
      if(!have_filename) {
        
        if(regkey_retrieve(rq, 1, &(snmp_file[7]), fn, mpl)) {
	  dksf_correct_fnsep(fn);
	  if(have_file(fn)) {
	    
	    have_filename = 1;
	  } else { 
	  }
	} else { 
	}
      }
      if(!have_filename) {
        if(rq->app) {
	  
          have_filename = dkapp_find_file(
            rq->app, &(snmpcfgfile[1]), fn, mpl
          );
	  
	}
      }
      if(have_filename) {
        logmsg[0] = &(snmpcfgfile[1]);
	logmsg[1] = str_equal;
	logmsg[2] = fn;
	if(rq->app) {
	  dkapp_log_msg(rq->app, DK_LOG_LEVEL_DEBUG, logmsg, 3);
	}
        if(rq->app) {
          back = dkapp_stream_openfile(rq->app, fn, "r");
	} else {
	  back = dkstream_openfile(fn, "r", 0, NULL);
	}
      }
      if(!back) {
        
        back = dkapp_read_file(rq->app, &(snmpcfgfile[1]));
      }
      dk_delete(fn);
    } else {
      if(rq->app) { dkapp_err_memory(rq->app, 1, mpl); }
    }
  } 
  return back;
}



/**	Read yanolc.conf file.
	@param	rq	YALC request.
	@return	Pointer to configuration struct on success, NULL on error.
*/
static
yalc_cfg *
read_cfg DK_P1(yalc_rq_t *, rq)
{
  yalc_cfg *back = NULL;
  char *logmsg[3];
  size_t mpl = 0;
  char *fn = NULL;
  int  have_filename = 0, x = 0;
  
  if(rq) {
    mpl = dksf_get_maxpathlen();
    fn = dk_new(char,mpl);
    if(fn) {
      have_filename = 0;
      if(!have_filename) {
	if(rq->app) {
	  x |= DK_APP_PREF_EXCL_CMD;
	  x |= DK_APP_PREF_EXCL_PROG;
	  x |= DK_APP_PREF_EXCL_USER;
	  if(dkapp_get_pref(rq->app, cfg_file, fn, mpl, x)) {
	    dksf_correct_fnsep(fn);
	    if(have_file(fn)) {
	      have_filename = 1;
	    }
	  }
	}
      }
      if(!have_filename) {
        if(regkey_retrieve(rq, 1, &(cfg_file[7]), fn, mpl)) {
	  dksf_correct_fnsep(fn);
	  if(have_file(fn)) {
	    have_filename = 1;
	  }
        }
      }
      if((!have_filename) && (rq->app)) {
        have_filename = dkapp_find_cfg(
	  rq->app, &(configfile[1]), fn, mpl
	);
      }
      if(have_filename) {
	logmsg[0] = &(configfile[1]);
	logmsg[1] = str_equal;
	logmsg[2] = fn;
	if(rq->app) {
	  dkapp_log_msg(rq->app, DK_LOG_LEVEL_DEBUG, logmsg, 3);
	}
	back = yalc_cfg_new();
	if(back) {
	  rq->read_cfg_res = 0; 
	  add_cfg(rq, back, fn);
	} else {
	  if(rq->app) { dkapp_err_memory(rq->app, sizeof(yalc_cfg), 1); }
	}
      }
      dk_delete(fn);
    } else {
      if(rq->app) { dkapp_err_memory(rq->app, 1, mpl); }
    }
  } 
  return back;
}



/**	Flag: SIGPIPE received.
*/
static
#if DK_HAVE_VOLATILE
volatile
#endif
int sig_pipe_received = 0;



/**	Flag: SIGINT received.
*/
static
#if DK_HAVE_VOLATILE
volatile
#endif
int sig_int_received = 0;



/**	Flag: Keyboard hit detected.
*/
static
#if DK_HAVE_VOLATILE
volatile
#endif
int kbhit_received = 0;



/**	Check whether we can continue.
	@return	1 if we can continue, 0 otherwise.
*/
static
int
can_continue DK_P0()
{
  int back = 1;
  if(sig_pipe_received) back = 0;
  if(sig_int_received)  back = 0;
#if DK_HAVE__KBHIT
  if(kbhit_received) {
    back = 1;
  } else {
    if(_kbhit()) {
      kbhit_received = back = 1;
#if DK_HAVE__GETCH
      _getch();
#endif
    }
  }
#endif
  return back;
}



/**	SIGINT handler.
	@param	signo	Signal number (SIGINT).
*/
static
dk_signal_ret_t
sig_int_handler DK_P1(int, signo)
{
  dksignal_refresh(signo,sig_int_handler);
  sig_int_received = 1;
}



/**	SIGPIPE handler.
	@param	signo	Signal number (SIGPIPE).
*/
static
dk_signal_ret_t
sig_pipe_handler DK_P1(int, signo)
{
  dksignal_refresh(signo,sig_pipe_handler);
  sig_pipe_received = 1;
}

void
yalc_init DK_P1(yalc_rq_t *, rq)
{
  
  if(rq) {
    rq->printer_name = NULL;
    rq->server_name = NULL;
    rq->user_name = NULL;
    rq->app = NULL;
    rq->cmd = 0;
    rq->argc = 0; rq->argv = NULL;
    rq->data_file_first = 0;
    rq->snmp_host = NULL;
    rq->snmp_comm = NULL;
    rq->snmp_vers = NULL;
    rq->private_snmp = NULL;
  }
}

yalc_rq_t *
yalc_new DK_P0()
{
  yalc_rq_t *back = NULL;
  back = dk_new(yalc_rq_t,1);
  if(back) {
    yalc_init(back);
  } 
  return back;
}

void
yalc_delete DK_P1(yalc_rq_t *, rq)
{
  char *x;
  
  if(rq) {
    rq->snmp_vers = NULL;
    rq->snmp_host = NULL;
    rq->snmp_comm = NULL;
    rq->printer_name = NULL;
    rq->server_name = NULL;
    rq->user_name = NULL;
    rq->app = NULL;
    rq->argc = 0;
    rq->argv = NULL;
    rq->cfg_file = NULL;
    x = rq->private_snmp;
    if(x) { dk_delete(x); }
    rq->private_snmp = NULL;
    dk_delete(rq);
  }
}

void
yalc_set_lpr_filetype DK_P2(yalc_rq_t *, rq, int, t)
{
  if(rq) {
    if((rq->cmd) == YALC_OP_LPR) {
      (rq->args).lpr.type = t;
    }
  }
}

void
yalc_set_lpr_suppress_header DK_P2(yalc_rq_t *, rq, int, t)
{
  if(rq) {
    if((rq->cmd) == YALC_OP_LPR) {
      (rq->args).lpr.suppress_header = t;
    }
  }
}


void
yalc_set_lpr_indent_cols DK_P2(yalc_rq_t *, rq, int, t)
{
  if(rq) {
    if((rq->cmd) == YALC_OP_LPR) {
      (rq->args).lpr.indent_cols = t;
    }
  }
}


void
yalc_set_lpr_number_of_copies DK_P2(yalc_rq_t *, rq, int, t)
{
  if(rq) {
    if((rq->cmd) == YALC_OP_LPR) {
      (rq->args).lpr.number_of_copies = t;
    }
  }
}


void
yalc_set_lpr_keep_spool_queue DK_P2(yalc_rq_t *, rq, int, t)
{
  if(rq) {
    if((rq->cmd) == YALC_OP_LPR) {
      (rq->args).lpr.keep_spool_queue = t;
    }
  }
}


void
yalc_set_lpr_width DK_P2(yalc_rq_t *, rq, int, t)
{
  if(rq) {
    if((rq->cmd) == YALC_OP_LPR) {
      (rq->args).lpr.with = t;
    }
  }
}

void
yalc_set_lpr_class_name DK_P2(yalc_rq_t *, rq, char *, cln)
{
  if(rq && cln) {
    if((rq->cmd) == YALC_OP_LPR) {
      (rq->args).lpr.class_name = cln;
    }
  }
}


void
yalc_set_lpr_job_name DK_P2(yalc_rq_t *, rq, char *, cln)
{
  if(rq && cln) {
    if((rq->cmd) == YALC_OP_LPR) {
      (rq->args).lpr.job_name = cln;
    }
  }
}


void
yalc_set_lpr_mail_addr DK_P2(yalc_rq_t *, rq, char *, cln)
{
  if(rq && cln) {
    if((rq->cmd) == YALC_OP_LPR) {
      (rq->args).lpr.mail_recipient = cln;
    }
  }
}


void
yalc_set_lpr_remote_account DK_P2(yalc_rq_t *, rq, char *, cln)
{
  if(rq && cln) {
    if((rq->cmd) == YALC_OP_LPR) {
      (rq->args).lpr.remote_account = cln;
    }
  }
}


void
yalc_set_lpr_job_title DK_P2(yalc_rq_t *, rq, char *, cln)
{
  if(rq && cln) {
    if((rq->cmd) == YALC_OP_LPR) {
      (rq->args).lpr.job_title = cln;
    }
  }
}


void
yalc_set_lpr_other_options DK_P2(yalc_rq_t *, rq, char *, cln)
{
  if(rq && cln) {
    if((rq->cmd) == YALC_OP_LPR) {
      (rq->args).lpr.other_options = cln;
    }
  }
}

void
yalc_set_lpr DK_P1(yalc_rq_t *, rq)
{
  if(rq) {
    rq->cmd = YALC_OP_LPR;
    (rq->args).lpr.type = 0;
    (rq->args).lpr.class_name = NULL;
    (rq->args).lpr.suppress_header = 1;
    (rq->args).lpr.indent_cols = 0;
    (rq->args).lpr.job_name = NULL;
    (rq->args).lpr.number_of_copies = 0;
    (rq->args).lpr.mail_recipient = NULL;
    (rq->args).lpr.keep_spool_queue = 0;
    (rq->args).lpr.remote_account = NULL;
    (rq->args).lpr.job_title = NULL;
    (rq->args).lpr.with = 0;
    (rq->args).lpr.other_options = NULL;
  }
}

void
yalc_set_lprm DK_P2(yalc_rq_t *, rq, int, all)
{
  if(rq) {
    rq->cmd = YALC_OP_LPRM;
    (rq->args).lprm.all = (all ? 1 : 0);
  }
}

void
yalc_set_snmp_status DK_P1(yalc_rq_t *,rq)
{
  if(rq) {
    rq->cmd = YALC_OP_SNMP_STATUS;
    (rq->args).snmp.force_output = 0;
    (rq->args).snmp.output_found = 0;
    (rq->args).snmp.run_verbose = 0;
    (rq->args).snmp.keep_logfile = 0;
  }
}

void
yalc_set_snmp_short DK_P1(yalc_rq_t *,rq)
{
  if(rq) {
    rq->cmd = YALC_OP_SNMP_SHORT;
    (rq->args).snmp.force_output = 0;
    (rq->args).snmp.output_found = 0;
    (rq->args).snmp.run_verbose = 0;
    (rq->args).snmp.keep_logfile = 0;
  }
}


void
yalc_set_snmp_verbose DK_P1(yalc_rq_t *,rq)
{
  if(rq) (rq->args).snmp.run_verbose = 1;
}


void
yalc_set_snmp_force DK_P2(yalc_rq_t *,rq,int,val)
{
  if(rq) {
    (rq->args).snmp.force_output = val;
  }
}

void
yalc_set_lpc DK_P2(yalc_rq_t *, rq, int, all)
{
  if(rq) {
    rq->cmd = YALC_OP_LPC;
    (rq->args).lpc.all = (all ? 1 : 0);
  }
}

void
yalc_set_lpq DK_P7(yalc_rq_t *, rq, int, mv, int, v, int, s, int, p, int, pt, int, rdj)
{
  
  if(rq) {
    rq->cmd = YALC_OP_LPQ;
    (rq->args).lpq.max_verbosity = mv;
    (rq->args).lpq.verbosity     = v;
    (rq->args).lpq.short_status  = s;
    (rq->args).lpq.periodically  = p;
    (rq->args).lpq.period_time   = pt;
    (rq->args).lpq.remove_filter_status = 0;
    (rq->args).lpq.remove_done_jobs = rdj;
  }
}

void
yalc_set_printer DK_P2(yalc_rq_t *, rq, char *, pn)
{
  if(rq && pn) { rq->printer_name = pn; }
}

void
yalc_set_snmp_host DK_P2(yalc_rq_t *,rq,char *,hn)
{
  if(rq && hn) { rq->snmp_host = hn; }
}

void
yalc_set_snmp_comm DK_P2(yalc_rq_t *,rq,char *,co)
{
  if(rq && co) { rq->snmp_comm = co; }
}

void
yalc_set_snmp_vers DK_P2(yalc_rq_t *,rq, char *,v)
{
  if(rq && v) { rq->snmp_vers = v; }
}

void
yalc_set_snmp_type DK_P2(yalc_rq_t *,rq, char *,v)
{
  if(rq && v) { rq->snmp_type = v; }
}

void
yalc_set_server DK_P2(yalc_rq_t *, rq, char *, pn)
{
  if(rq && pn) { rq->server_name = pn; }
}

void
yalc_set_user DK_P2(yalc_rq_t *, rq, char *, pn)
{
  if(rq && pn) { rq->user_name = pn; }
}

void
yalc_set_app DK_P2(yalc_rq_t *, rq, dk_app_t *, a)
{
  if(rq && a) { rq->app = a; }
}

void
yalc_set_args DK_P3(yalc_rq_t *, rq, int, argc, char **, argv)
{
  if(rq && argv && (argc > 0))  { rq->argc = argc; rq->argv = argv; }
}



#if DEBUG

static
void
debug_hi DK_P2(yalc_host_info *, h, FILE *, f)
{
  if(h->name) {
    fprintf(f, "Name: %s\n", h->name);
  }
  fprintf(f, "Type: %d\n", h->type);
  fprintf(f, "Port: %u\n", (unsigned)(h->portno));
  fprintf(f, "Orig: %u %u\n",
    (unsigned)(h->o_min),
    (unsigned)(h->o_max)
  );
  fprintf(f, "Time: %lf %lf %lf %lf\n",
    (((h->have_timeouts) & 1) ? (h->lpr_timeout) : 0.0),
    (((h->have_timeouts) & 2) ? (h->lpq_timeout) : 0.0),
    (((h->have_timeouts) & 4) ? (h->lprm_timeout) : 0.0),
    (((h->have_timeouts) & 8) ? (h->lpc_timeout) : 0.0)
  );
}

static
void
print_cfg DK_P2(yalc_cfg *,c, FILE *,f)
{
  yalc_alias_info   *yai;
  yalc_host_info    *yhi;
  yalc_device_info *ydi;

  dksto_it_reset(c->ai);
  while(yai = dksto_it_next(c->ai)) {
    fprintf(f, "ALIAS\n%s=%s\n", yai->name, yai->value);
  }
  dksto_it_reset(c->hi);
  while(yhi = dksto_it_next(c->hi)) {
    fprintf(f, "HOST\n");
    debug_hi(yhi, f);
  }
  dksto_it_reset(c->pi);
  while(ydi = dksto_it_next(c->pi)) {
    fprintf(f, "PRINTER\n");
    if(ydi->name) {
      fprintf(f, "Name: %s\n", ydi->name);
    }
    debug_hi(&(ydi->i), f);
  }
}

#endif


#if DK_HAVE_WINREG_H



/**	Registry key name.
*/
static char myRegistryDefaultsKey[] =  { "Software\\DKrause\\Yanolc" };



/**	Open registry keys.
	@param	rq	YALC request.
*/
static
void
regkey_open DK_P1(yalc_rq_t *, rq)
{
  HKEY  hkTemp;
  PHKEY phkSubkey;
  DWORD disp;
  LONG  retval;
  
  (rq->reg).what = 0;
  hkTemp = 0;
  phkSubkey = &hkTemp;
  retval = RegCreateKeyExA(
    HKEY_LOCAL_MACHINE,
    myRegistryDefaultsKey,
    0,
    NULL,
    REG_OPTION_NON_VOLATILE,
    KEY_QUERY_VALUE,
    NULL,
    phkSubkey,
    &disp
  );
  if(retval == ERROR_SUCCESS) {
    (rq->reg).what |= 1;
    (rq->reg).hklm = hkTemp;
  } else { 
  }
  hkTemp = 0;
  phkSubkey = &hkTemp;
  retval = RegCreateKeyExA(
    HKEY_CURRENT_USER,
    myRegistryDefaultsKey,
    0,
    NULL,
    REG_OPTION_NON_VOLATILE,
    KEY_ALL_ACCESS,
    NULL,
    phkSubkey,
    &disp
  );
  if(retval == ERROR_SUCCESS) {
    (rq->reg).what |= 2;
    (rq->reg).hkcu = hkTemp;
  } else { 
  } 
}



/**	Close registry keys used by YALC request.
	@param	rq	YALC request.
*/
static
void
regkey_close DK_P1(yalc_rq_t *, rq)
{
  if(((rq->reg).what) & 1) {
    RegCloseKey((rq->reg).hklm);
  }
  if(((rq->reg).what) & 2) {
    RegCloseKey((rq->reg).hkcu);
  }
  (rq->reg).what = 0;
}

#endif



/**	Preference key: Default printer.
*/
static char key_default_printer[] = { "/yanolc/default-printer" };

/**	Preference key: Default print host.
*/
static char key_default_host[] = { "/yanolc/print-host" };

/**	Preference key: Print destination.
*/
static char default_printer_name[] = { "lp" };

/**	Preference key: Alias.
*/
static char key_alias[] = { "/yanolc/alias/" };

/**	Preference key: Device.
*/
static char key_device[] = { "/yanolc/device/" };

/**	Preference key: Server host.
*/
static char key_host[] = { "/yanolc/host/" };

/**	Preference key: Print queue type.
*/
static char key_type[] = { "/type" };

/**	Preference key: Users which can use -U.
*/
static char key_xusers[] = { "/xusers" };

/**	Preference key: General timeout.
*/
static char key_timeout[] = { "/timeout" };

/**	Preference key: Timeout for lpr.
*/
static char key_timeout_lpr[] = { "/timeout.lpr" };

/**	Preference key: Timeout for lpq.
*/
static char key_timeout_lpq[] = { "/timeout.lpq" };

/**	Preference key: Timeout for lprm.
*/
static char key_timeout_lprm[] = { "/timeout.lprm" };

/**	Preference key: Timeout for lpc.
*/
static char key_timeout_lpc[] = { "/timeout.lpc" };

/**	Preference key: Local ports.
*/
static char key_originate[] = { "/originate" };

/**	Preference key: Send data file first.
*/
static char key_data_file_first[] = { "/data-file-first" };

/**	Preference key: SNMP settings.
*/
static char key_snmp[] = { "/snmp" };



/**	Resolve alias for queue name.
	@param	rq	YALC request.
*/
static
void
get_alias DK_P1(yalc_rq_t *, rq)
{
  char key[512], val[sizeof(key)];
  yalc_cfg *ycfg;
  yalc_alias_info *ai;
  if((strlen(key_alias) + strlen(rq->printer_name)) < sizeof(key)) {
    strcpy(key, key_alias);
    strcat(key, rq->printer_name);
  }
#if DK_HAVE_WINREG_H
  if(regkey_retrieve(rq, 3, &(key[7]), val, sizeof(val))) {
    rq->dev = dkstr_dup(val);
  }
#endif
  if(!(rq->dev)) {
    if(rq->app) {
      if(dkapp_get_pref(rq->app, key, val, sizeof(val), 0)) {
	rq->dev = dkstr_dup(val);
      }
    }
  }
  if(!(rq->dev)) {
    if(rq->cfg_file) {
      ycfg = ((yalc_cfg *)(rq->cfg_file));
      ai = (yalc_alias_info *)dksto_it_find_like(ycfg->ai, rq->printer_name, 1);
      if(ai) {
	if(ai->value) { rq->dev = dkstr_dup(ai->value); }
      }
    }
  }
}



/**	Get configuration value.
	@param	rq	YALC request.
	@param	k	Key.
	@param	h	Configuration sources (2=user, 1=system).
	@param	v	Result buffer.
	@param	s	Size of \a v.
	@return	1 on success, 0 on error.
*/
static
int
get_config_value DK_P5(yalc_rq_t *, rq, char *, k, int, h, char *, v, size_t, s)
{
  int back = 0;
  char key[256];
  size_t sz;
  int ex;
  yalc_cfg *ycfg;
  yalc_host_info *yh1, *yh2;
  yalc_device_info *yd;
  
  if(!back) {
    if(h & 2) {
      if(rq->app) {
        if(rq->dev) {
          sz = strlen(k);
          sz += strlen(key_device);
          sz += strlen(rq->dev);
	  if(sz < sizeof(key)) {
	    strcpy(key, key_device);
	    strcat(key, rq->dev);
	    strcat(key, k);
	    ex = DK_APP_PREF_EXCL_SYSTEM;
            if(dkapp_get_pref(rq->app, key, v, s, ex)) {
	      back = 1;
	    }
	  }
        }
      }
    }
  }
  if(!back) {
    if(h & 2) {
      if(rq->dev) {
	sz = strlen(k);
	sz += strlen(key_device);
	sz += strlen(rq->dev);
	if(sz < sizeof(key)) {
	  strcpy(key, key_device);
	  strcat(key, rq->dev);
	  strcat(key, k);
	  if(regkey_retrieve(rq, 2, &(key[7]), v, s)) {
	    back = 1;
	  }
	}
      }
    }
  }
  if(!back) {
    if(h & 2) {
      if(rq->app) {
	if(rq->host) {
	  sz = strlen(k);
	  sz += strlen(key_host);
	  sz += strlen(rq->host);
	  if(sz < sizeof(key)) {
	    strcpy(key, key_host);
	    strcat(key, rq->host);
	    strcat(key, k);
	    ex = DK_APP_PREF_EXCL_SYSTEM;
	    if(dkapp_get_pref(rq->app, key, v, s, ex)) {
	      back = 1;
	    }
	  }
	}
      }
    }
  }
  if(!back) {
    if(h & 2) {
      if(rq->host) {
	sz = strlen(k);
	sz += strlen(key_host);
	sz += strlen(rq->host);
	if(sz < sizeof(key)) {
	  strcpy(key, key_host);
	  strcat(key, rq->host);
	  strcat(key, k);
	  if(regkey_retrieve(rq, 2, &(key[7]), v, s)) {
	    back = 1;
	  }
	}
      }
    }
  }
  if(!back) {
    if(h & 1) {
      if(rq->app) {
	if(rq->dev) {
	  sz = strlen(k);
	  sz += strlen(key_device);
	  sz += strlen(rq->dev);
	  if(sz < sizeof(key)) {
	    strcpy(key, key_device);
	    strcat(key, rq->dev);
	    strcat(key, k);
	    ex = DK_APP_PREF_EXCL_CMD;
	    ex |= DK_APP_PREF_EXCL_PROG;
	    ex |= DK_APP_PREF_EXCL_USER;
	    if(dkapp_get_pref(rq->app, key, v, s, ex)) {
	      back = 1;
	    }
	  }
	}
      }
    }
  }
  if(!back) {
    if(h & 1) {
      if(rq->dev) {
	sz = strlen(k);
	sz += strlen(key_device);
	sz += strlen(rq->dev);
	if(sz < sizeof(key)) {
	  strcpy(key, key_device);
	  strcat(key, rq->dev);
	  strcat(key, k);
	  if(regkey_retrieve(rq, 1, &(key[7]), v, s)) {
	    back = 1;
	  }
	}
      }
    }
  }
  if(!back) {
    if(h & 1) {
      if(rq->host) {
	if(rq->app) {
	  sz = strlen(k);
	  sz += strlen(key_host);
	  sz += strlen(rq->host);
	  if(sz < sizeof(key)) {
	    strcpy(key, key_host);
	    strcat(key, rq->host);
	    strcat(key, k);
	    ex = DK_APP_PREF_EXCL_CMD;
	    ex |= DK_APP_PREF_EXCL_PROG;
	    ex |= DK_APP_PREF_EXCL_USER;
	    if(dkapp_get_pref(rq->app, key, v, s, ex)) {
	      back = 1;
	    }
	  }
	}
      }
    }
  }
  if(!back) {
    if(h & 1) {
      if(rq->host) {
	sz = strlen(k);
	sz += strlen(key_host);
	sz += strlen(rq->host);
	if(sz < sizeof(key)) {
	  strcpy(key, key_host);
	  strcat(key, rq->host);
	  strcat(key, k);
	  if(regkey_retrieve(rq, 1, &(key[7]), v, s)) {
	    back = 1;
	  }
	}
      }
    }
  }
  if((rq->cfg_file) && (rq->read_cfg_res)) {
    
    ycfg = ((yalc_cfg *)(rq->cfg_file));
    yh1 = NULL; yh2 = NULL; yd = NULL;
    if(rq->dev) {
      yd = (yalc_device_info *)dksto_it_find_like((ycfg->pi), (rq->dev), 1);
      if(yd) {
	yh1 = &(yd->i);
      }
    }
    if(rq->host) {
      yh2 = (yalc_host_info *)dksto_it_find_like((ycfg->hi), (rq->host), 1);
    }
    if(!back) {
      if(strcmp(k, key_type) == 0) {
	if(yh1) {
	  if((yh1->type) != YALC_METHOD_UNKNOWN) {
	    sprintf(v, "%s", pstype_keywords[(yh1->type) - 1]);
	    back = 1;
	  }
	}
	if(!back) {
	  if(yh2) {
	    if((yh2->type) != YALC_METHOD_UNKNOWN) {
	      sprintf(v, "%s", pstype_keywords[(yh2->type) - 1]);
	      back = 1;
	    }
	  }
	}
      } else {
	if(strcmp(k, key_xusers) == 0) {
	  if(yh1) {
	    if(yh1->xusers) {
	      if(strlen(yh1->xusers) < s) {
		strcpy(v, yh1->xusers);
		back = 1;
	      }
	    }
	  }
	  if(!back) {
	    if(yh2) {
	      if(yh2->xusers) {
		if(strlen(yh2->xusers) < s) {
		  strcpy(v, yh2->xusers);
		  back = 1;
		}
	      }
	    }
	  }
	} else {
	  if(strcmp(k, key_originate) == 0) {
	    if(yh1) {
	      if(yh1->o_min) {
		sprintf(v, "%u-%u", ((unsigned)(yh1->o_min)), ((unsigned)(yh1->o_max)));
		back = 1;
	      }
	    }
	    if(!back) {
	      if(yh2) {
		if(yh2->o_min) {
		  sprintf(v, "%u-%u", ((unsigned)(yh2->o_min)), ((unsigned)(yh2->o_max)));
		  back = 1;
		}
	      }
	    }
	  } else {
	    if(strcmp(k, key_timeout_lpr) == 0) {
	      if(yh1) {
		if((yh1->have_timeouts) & 1) {
		  sprintf(v, "%lf", yh1->lpr_timeout);
		  back = 1;
		}
	      }
	      if(!back) {
		if(yh2) {
		  if((yh2->have_timeouts) & 1) {
		    sprintf(v, "%lf", yh2->lpr_timeout);
		    back = 1;
		  }
		}
	      }
	    } else {
	      if(strcmp(k, key_timeout_lpq) == 0) {
		if(yh1) {
		  if((yh1->have_timeouts) & 2) {
		    sprintf(v, "%lf", yh1->lpq_timeout);
		    back = 1;
		  }
		}
		if(!back) {
		  if(yh2) {
		    if((yh2->have_timeouts) & 2) {
		      sprintf(v, "%lf", yh2->lpq_timeout);
		      back = 1;
		    }
		  }
		}
	      } else {
		if(strcmp(k, key_timeout_lprm) == 0) {
		  if(yh1) {
		    if((yh1->have_timeouts) & 4) {
		      sprintf(v, "%lf", yh1->lprm_timeout);
		      back = 1;
		    }
		  }
		  if(!back) {
		    if(yh2) {
		      if((yh2->have_timeouts) & 4) {
			sprintf(v, "%lf", yh2->lprm_timeout);
			back = 1;
		      }
		    }
		  }
		} else {
		  if(strcmp(k, key_timeout_lpc) == 0) {
		    if(yh1) {
		      if((yh1->have_timeouts) & 8) {
			sprintf(v, "%lf", yh1->lpc_timeout);
			back = 1;
		      }
		    }
		    if(!back) {
		      if(yh2) {
			if((yh2->have_timeouts) & 8) {
			  sprintf(v, "%lf", yh2->lpc_timeout);
			  back = 1;
			}
		      }
		    }
		  } else {
		    if(strcmp(k, key_data_file_first) == 0) {
		      if(yh1) {
			if(yh1->data_file_first) {
			  back = 1;
			  if(yh1->data_file_first == 2) {
			    sprintf(v, "yes");
			  } else {
			    sprintf(v, "no");
			  }
			}
		      }
		      if(!back) {
			if(yh2) {
			  if(yh2->data_file_first) {
			    back = 1;
			    if(yh2->data_file_first == 2) {
			      sprintf(v, "yes");
			    } else {
			      sprintf(v, "no");
			    }
			  }
			}
		      }
		    } else {
		      if(strcmp(k, key_snmp) == 0) {
		        if(yh1) {
			  if(yh1->snmp_target) {
			    if(strlen(yh1->snmp_target) < s) {
			      strcpy(v, yh1->snmp_target);
			      back = 1;
			    }
			  }
			}
			if((!back) && (yh2)) {
			  if(yh2->snmp_target) {
			    if(strlen(yh1->snmp_target) < s) {
			      strcpy(v, yh1->snmp_target);
			      back = 1;
			    }
			  }
			}
		      } else {
		        /* OTHER OPTIONS HERE */
		      }
		    }
		  }
		}
	      }
	    }
	  }
	}
      }
    }
  } 
  return back;
}



/**	Set up request type.
	@param	rq	YALC request.
*/
static
void
setup_type DK_P1(yalc_rq_t *, rq)
{
  char val[256];
  if(get_config_value(rq, key_type, 3, val, sizeof(val))) {
    rq->type = dkstr_array_index(pstype_keywords, val, 0) + 1;
    switch(rq->type) {
      case YALC_METHOD_LPRNG:
      case YALC_METHOD_BSD: {
	if(rq->portno == 0) {
	  rq->portno = 515;
	}
      } break;
    }
  }
}



/**	Set up internal list of users allowed to use -U.
	@param	rq	YALC request.
*/
static
void
setup_xusers DK_P1(yalc_rq_t *, rq)
{
  char val[256], username[256], *ptr1, *ptr2;
  rq->xuser_allowed = 0; 
  if(get_config_value(rq, key_xusers, 1, val, sizeof(val))) {
    
    if(dksf_get_uname(username, sizeof(username))) {
      
      ptr1 = dkstr_start(val, NULL);
      if(ptr1) {
	dkstr_chomp(ptr1, NULL);
	while(ptr1) {
	  ptr2 = dkstr_next(ptr1, NULL); 
	  
          if(strcmp(ptr1, username) == 0) {
	    rq->xuser_allowed = 1; 
	  } else {
	    if(strcmp(ptr1, "*") == 0) {
	      rq->xuser_allowed = 1; 
	    }
	  }
	  ptr1 = ptr2;
	}
      }
    }
  }
}



/**	Set up local port range if necessary.
	@param	rq	YALC request.
*/
static
void
setup_originate DK_P1(yalc_rq_t *, rq)
{
  char val[256], *ptr1;
  unsigned u1, u2;
  if(get_config_value(rq, key_originate, 3, val, sizeof(val))) {
    ptr1 = dkstr_chr(val, '-');
    if(ptr1) {
      *ptr1 = ' ';
      if(sscanf(val, "%u %u", &u1, &u2) == 2) {
	rq->o_min = u1; rq->o_max = u2;
      }
    } else {
      if(sscanf(val, "%u %u", &u1, &u2) == 2) {
	rq->o_min = u1; rq->o_max = u2;
      } else {
	if(sscanf(val, "%u", &u1) == 1) {
	  rq->o_min = u1; rq->o_max = u1;
	}
      }
    }
  }
}



/**	Find LPR-specific timeout.
	@param	rq	YALC request.
*/
static
void
setup_timeout_lpr DK_P1(yalc_rq_t *, rq)
{
  char val[256]; double d;
  if(rq->cmd == YALC_OP_LPR) {
  if(get_config_value(rq, key_timeout_lpr, 3, val, sizeof(val))) {
    if(strcmp(val, "-")) {
      if(sscanf(val, "%lf", &d) == 1) {
	rq->have_timeout = 1;
	rq->to = d;
      }
    }
  }
  }
}



/**	Find LPQ-specific timeout.
	@param	rq YALC request.
*/
static
void
setup_timeout_lpq DK_P1(yalc_rq_t *, rq)
{
  char val[256]; double d;
  if(rq->cmd == YALC_OP_LPQ) {
  if(get_config_value(rq, key_timeout_lpq, 3, val, sizeof(val))) {
    if(strcmp(val, "-")) {
      if(sscanf(val, "%lf", &d) == 1) {
	rq->have_timeout = 1;
	rq->to = d;
      }
    }
  }
  }
}



/**	Find LPRM-specific timeout.
	@param	rq	YALC request.
*/
static
void
setup_timeout_lprm DK_P1(yalc_rq_t *, rq)
{
  char val[256]; double d;
  if(rq->cmd == YALC_OP_LPRM) {
  if(get_config_value(rq, key_timeout_lprm, 3, val, sizeof(val))) {
    if(strcmp(val, "-")) {
      if(sscanf(val, "%lf", &d) == 1) {
	rq->have_timeout = 1;
	rq->to = d;
      }
    }
  }
  }
}



/**	Find LPC-specific timeout.
	@param	rq	YALC request.
*/
static
void
setup_timeout_lpc DK_P1(yalc_rq_t *, rq)
{
  char val[256]; double d;
  if(rq->cmd == YALC_OP_LPC) {
  if(get_config_value(rq, key_timeout_lpc, 3, val, sizeof(val))) {
    if(strcmp(val, "-")) {
      if(sscanf(val, "%lf", &d) == 1) {
	rq->have_timeout = 1;
	rq->to = d;
      }
    }
  }
  }
}



/**	Setup for SNMP request.
	@param	rq	YALC request.
*/
static
void
setup_snmp DK_P1(yalc_rq_t *, rq)
{
  char val[256], *pa, *pb, *p1, *p2, *p3, *p4;
  
  if((rq->cmd == YALC_OP_SNMP_STATUS) || (rq->cmd == YALC_OP_SNMP_SHORT)) {
  if(get_config_value(rq, key_snmp, 3, val, sizeof(val))) {
    pa = dkstr_dup(val);
    if(pa) {
      pb = rq->private_snmp;
      if(pb) { dk_delete(pb); }
      rq->private_snmp = pa;
      p1 = p2 = p3 = p4 = NULL;
      p1 = dkstr_start(rq->private_snmp, NULL);
      if(p1) {
        p2 = dkstr_chr(p1, ':');
	if(p2) {
	  *(p2++) = (char)0;
	  p2 = dkstr_start(p2, NULL);
	  if(p2) {
	    p3 = dkstr_chr(p2, ':');
	    if(p3) {
	      *(p3++) = (char)0;
	      p3 = dkstr_start(p3, NULL);
	      if(p3) {
	        p4 = dkstr_chr(p3, ':');
		if(p4) {
		  *(p4++) = (char)0;
		  p4 = dkstr_start(p4, NULL);
		}
	      }
	    }
	  }
	}
      }
      if(p1 && (!(rq->snmp_host))) {
        rq->snmp_host = p1;
      }
      if(p2 && (!(rq->snmp_type))) {
        rq->snmp_type = p2;
      }
      if(p3 && (!(rq->snmp_comm))) {
        rq->snmp_comm = p3;
      }
      if(p4 && (!(rq->snmp_vers))) {
        rq->snmp_vers = p4;
      }
    } else {
      if(rq->app) { dkapp_err_memory(rq->app,sizeof(char),(strlen(val)+1)); }
    }
  }
  }
  
  
  
  
  
}



/**	Set option "data file first".
	@param	rq	YALC request.
*/
static
void
setup_data_file_first DK_P1(yalc_rq_t *, rq)
{
   char val[256];
   if(get_config_value(rq, key_data_file_first, 3, val, sizeof(val))) {
     if(dkstr_is_on(val)) {
       rq->data_file_first = 1;
     }
   }
}



/**	Setup timeouts for operations.
	@param	rq	YALC request.
*/
static
void
setup_timeouts DK_P1(yalc_rq_t *, rq)
{
  char val[256];
  double d;
  if(get_config_value(rq, key_timeout, 3, val, sizeof(val))) {
    if(strcmp(val, "-")) {
      if(sscanf(val, "%lf", &d) == 1) {
	rq->have_timeout = 1;
	rq->to = d;
      } else {
	rq->have_timeout = 0;
	rq->to = 0.0;
      }
    } else {
      rq->have_timeout = 0;
      rq->to = 0.0;
    }
  }
}



/**	Find printer name.
	@param	rq	YALC request.
*/
static
void
get_printer_name DK_P1(yalc_rq_t *, rq)
{
  char *ptr, val[128];
  unsigned u;
  size_t sz;
  int exclreg;
  yalc_cfg *ycfg;
  /*
    Printer name from command line
  */
  
  ycfg = NULL;
  if(rq->cfg_file) {
    ycfg = (yalc_cfg *)(rq->cfg_file);
  }
  if(!(rq->printer_name)) {
    if(rq->app) {
    exclreg = DK_APP_PREF_EXCL_SYSTEM;
    exclreg |= DK_APP_PREF_EXCL_USER;
    exclreg |= DK_APP_PREF_EXCL_PROG;
    if(dkapp_get_pref(rq->app,key_default_printer,val,sizeof(val),exclreg)) {
      rq->printer_from_env = dkstr_dup(val);
      if(rq->printer_from_env) {
	rq->printer_name = rq->printer_from_env;
	
      }
    }
    }
  }
  /*
    Printer name from environment variables
  */
  if(!(rq->printer_name)) {
    ptr = getenv("NGPRINTER");
    if(ptr) {
      rq->printer_from_env = dkstr_dup(ptr);
      if(rq->printer_from_env) {
	rq->printer_name = rq->printer_from_env;
	
      }
    }
  }
  if(!(rq->printer_name)) {
    ptr = getenv("NPRINTER");
    if(ptr) {
      rq->printer_from_env = dkstr_dup(ptr);
      if(rq->printer_from_env) {
	rq->printer_name = rq->printer_from_env;
	
      }
    }
  }
  if(!(rq->printer_name)) {
    ptr = getenv("LPDEST");
    if(ptr) {
      rq->printer_from_env = dkstr_dup(ptr);
      if(rq->printer_from_env) {
	rq->printer_name = rq->printer_from_env;
	
      }
    }
  }
  if(!(rq->printer_name)) {
    ptr = getenv("PRINTER");
    if(ptr) {
      rq->printer_from_env = dkstr_dup(ptr);
      if(rq->printer_from_env) {
	rq->printer_name = rq->printer_from_env;
	
      }
    }
  }
  /*
    Printer from user preferences
  */
  if(!(rq->printer_name)) {
    if(rq->app) {
    exclreg = DK_APP_PREF_EXCL_SYSTEM;
    exclreg |= DK_APP_PREF_EXCL_CMD;
    if(dkapp_get_pref(rq->app,key_default_printer,val,sizeof(val),exclreg)) {
      rq->printer_from_env = dkstr_dup(val);
      if(rq->printer_from_env) {
	rq->printer_name = rq->printer_from_env;
	
      }
    }
    }
  }
  /*
    Printer name from registry HKCU
  */
#if DK_HAVE_WINREG_H
  if(!(rq->printer_name)) {
    if(regkey_retrieve(rq, 2, &(key_default_printer[7]), val, sizeof(val))) {
      rq->printer_from_env = dkstr_dup(val);
      if(rq->printer_from_env) {
	rq->printer_name = rq->printer_from_env;
	
      }
    }
  }
#endif
  /*
    Printer name from system preferences
  */
  if(!(rq->printer_name)) {
    if(rq->app) {
    exclreg = DK_APP_PREF_EXCL_USER;
    exclreg |= DK_APP_PREF_EXCL_PROG;
    exclreg |= DK_APP_PREF_EXCL_CMD;
    if(dkapp_get_pref(rq->app,key_default_printer,val,sizeof(val),exclreg)) {
      rq->printer_from_env = dkstr_dup(val);
      if(rq->printer_from_env) {
	rq->printer_name = rq->printer_from_env;
	
      }
    }
    }
  }
  /*
    Printer name from registry HKLM
  */
#if DK_HAVE_WINREG_H
  
  if(!(rq->printer_name)) {
    if(regkey_retrieve(rq, 1, &(key_default_printer[7]), val, sizeof(val))) {
      rq->printer_from_env = dkstr_dup(val);
      if(rq->printer_from_env) {
	rq->printer_name = rq->printer_from_env;
	
      }
    }
  }
#endif
  if(!(rq->printer_name)) {
    if(ycfg) {
      if(ycfg->first_alias) {
	if((ycfg->first_alias)->value) {
	  rq->printer_from_env = dkstr_dup( (ycfg->first_alias)->value );
	  if(rq->printer_from_env) {
	    rq->printer_name = rq->printer_from_env ;
	  }
	}
      }
      if(!(rq->printer_name)) {
	if(ycfg->first_device) {
          if((ycfg->first_device)->name) {
	    rq->printer_from_env = dkstr_dup( (ycfg->first_device)->name );
	    if(rq->printer_from_env) {
	      rq->printer_name = rq->printer_from_env ;
	    }
	  }
	}
      }
    }
  }
  if(!(rq->printer_name)) {
    rq->printer_name = default_printer_name;
    
  } 
  /*
	Get the print host now
  */
  if(rq->printer_name) {
    ptr = dkstr_chr(rq->printer_name, '@');
    if(ptr) {					
      rq->queue = dkstr_dup(rq->printer_name);
      ptr++;
      rq->host = dkstr_dup(ptr);
      rq->dev  = dkstr_dup(rq->printer_name);
      if(rq->queue) {
	ptr = dkstr_chr(rq->queue, '@');
	*ptr = '\0';
      }
      rq->type = YALC_METHOD_BSD;
      rq->portno = 515;
    } else {
      ptr = dkstr_chr(rq->printer_name, '%');
      if(ptr) {					
	rq->host = dkstr_dup(rq->printer_name);
	rq->dev  = dkstr_dup(rq->printer_name);
	if(rq->host) {
	  ptr = dkstr_chr(rq->host, '%');
	  if(ptr) {
	    *(ptr++) = '\0';
	    if(sscanf(ptr, "%u", &u) == 1) {
	      rq->portno = u;
	      rq->type = YALC_METHOD_RAWTCPIP;
	    }
	  }
	}
      } else {
	if(rq->server_name) {
	  rq->queue = dkstr_dup(rq->printer_name);
	  rq->host  = dkstr_dup(rq->server_name);
	  sz = strlen(rq->printer_name) + strlen(rq->server_name) + 2;
	  rq->dev = dk_new(char,sz);
	  if(rq->dev) {
	    strcpy(rq->dev, rq->printer_name);
	    strcat(rq->dev, "@");
	    strcat(rq->dev, rq->server_name);
	  }
	  rq->type = YALC_METHOD_BSD;
	  rq->portno = 515;
	} else {
	  get_alias(rq);
	  if(rq->dev) {
	    ptr = dkstr_chr(rq->dev, '@');
	    if(ptr) {					
	      rq->queue = dkstr_dup(rq->dev);
	      if(rq->queue) {
		ptr = dkstr_chr(rq->queue, '@');
		if(ptr) {
		  *(ptr++) = '\0';
		  rq->host = dkstr_dup(ptr);
		  rq->type = YALC_METHOD_BSD;
		  rq->portno = 515;
		}
	      }
	    } else {
	      ptr = dkstr_chr(rq->dev, '%');
	      if(ptr) {
		rq->host = dkstr_dup(rq->dev);
		if(rq->host) {
		ptr = dkstr_chr(rq->host, '%');
		if(ptr) {
		  *(ptr++) = '\0';
		  if(sscanf(ptr, "%u", &u) == 1) {
		    rq->portno = u;
		    rq->type = YALC_METHOD_RAWTCPIP;
		  }
		}
		}
	      }
	    }
	  } else {
	    ptr = getenv("PRINTHOST");
	    if(ptr) {
	      rq->server_name = dkstr_dup(ptr);
	    }
	    if(!(rq->server_name)) {
	      /*
		User prefereneces
	      */
	      exclreg = DK_APP_PREF_EXCL_SYSTEM;
	      exclreg |= DK_APP_PREF_EXCL_CMD;
	      if(dkapp_get_pref(rq->app,key_default_host,val,sizeof(val),exclreg)) {
		rq->server_name = dkstr_dup(val);
	      }
	    }
#if DK_HAVE_WINREG_H
	    if(!(rq->server_name)) {
	      /*
		HKCU
	      */
	      if(regkey_retrieve(rq,2,&(key_default_host[7]),val,sizeof(val))) {
		rq->server_name = dkstr_dup(val);
	      }
	    }
#endif
	    if(!(rq->server_name)) {
	      /*
		System preferences
	      */
	      exclreg =  DK_APP_PREF_EXCL_USER;
	      exclreg |= DK_APP_PREF_EXCL_PROG;
	      exclreg |= DK_APP_PREF_EXCL_CMD;
	      if(dkapp_get_pref(rq->app,key_default_host,val,sizeof(val),exclreg)) {
		rq->server_name = dkstr_dup(val);
	      }
	    }
#if DK_HAVE_WINREG_H
	    if(!(rq->server_name)) {
	      /*
		HKLM
	      */
	      if(regkey_retrieve(rq,1,&(key_default_host[7]),val,sizeof(val))) {
		rq->server_name = dkstr_dup(val);
	      }
	    }
#endif
	    if(!(rq->server_name)) {
	      if(ycfg) {
		if(ycfg->first_host) {
		  if((ycfg->first_host)->name) {
		    rq->server_name = dkstr_dup( (ycfg->first_host)->name );
		  }
		}
	      }
	    }
	    if(rq->server_name) {
	      rq->queue = dkstr_dup(rq->printer_name);
	      rq->host  = dkstr_dup(rq->server_name);
	      sz = strlen(rq->printer_name) + strlen(rq->server_name) + 2;
	      rq->dev = dk_new(char,sz);
	      if(rq->dev) {
	        strcpy(rq->dev, rq->printer_name);
	        strcat(rq->dev, "@");
	        strcat(rq->dev, rq->server_name);
	      }
	      rq->type = YALC_METHOD_BSD;
	      rq->portno = 515;
	    }
	  }
	}
      }
    }
    if(rq->dev) {
      
      /*
	type
      */
      setup_type(rq);
      /*
	xusers
      */
      setup_xusers(rq);
      /*
	originate
      */
      setup_originate(rq);
      /*
	all timeouts
      */
      setup_timeouts(rq);
      /*
	timeout lpr
      */
      setup_timeout_lpr(rq);
      /*
	timeout lpq
      */
      setup_timeout_lpq(rq);
      /*
	timeout lprm
      */
      setup_timeout_lprm(rq);
      /*
	timeout lpc
      */
      setup_timeout_lpc(rq);
      /*
	check whether to send data or control file first
      */
      setup_data_file_first(rq);
      /*
        create SNMP setup
      */
      setup_snmp(rq);
    }
    if((rq->xuser_allowed) && (rq->user_name)) {
      rq->user = dkstr_dup(rq->user_name);
    } else {
      if(dksf_get_uname(val, sizeof(val))) {
	rq->user = dkstr_dup(val);
      }
    }
  } 
}



/**	Complete request (insert defaults for missing settings).
	@param	rq	YALC request.
	@return	1 on success, 0 on error.
*/
static
int
complete_request DK_P1(yalc_rq_t *, rq)
{
  int back = 1;
  
  switch(rq->cmd) {
    case YALC_OP_LPR : {
      get_printer_name(rq);
    } break;
    case YALC_OP_LPQ : {
      get_printer_name(rq);
    } break;
    case YALC_OP_LPRM : {
      get_printer_name(rq);
    } break;
    case YALC_OP_LPC : {
      /*
	printer name from argc/argv first,
	if no name available, get_printer_name()
      */
      if((rq->argv) && ((rq->argc) > 1)) {
	rq->printer_name = (rq->argv)[1];
      }
      get_printer_name(rq);
    } break;
    case YALC_OP_SNMP_STATUS: case YALC_OP_SNMP_SHORT: {
      get_printer_name(rq);
    } break;
  } 
  return back;
}



/**	Chech whether or not a character is printable.
	@param	c	Character to test.
	@return	1 for printable characters, 0 otherwise.
*/
static
int
my_isprintable DK_P1(char, c)
{
  int back = 0;
  if((c >= 0x20) && (c <= 0x7F)) {
    back = 1;
  } else {
    switch(c) {
      case '\r' :
      case '\n' :
      case '\t' :
      case 'ä' :
      case 'ö' :
      case 'ü' :
      case 'Ä' :
      case 'Ö' :
      case 'Ü' :
      case 'ß' :
      {
        back = 1;
      } break;
    }
  }
  return back;
}



/**	Remove unprintable characters from output line.
	@param	buf	Buffer containing printer response.
	@param	sz	Number of bytes used in \a buf.
*/
static
void
remove_unprintables DK_P2(char *,buf, size_t *, sz)
{
  /*
  char *ptr, *ptra, *ptrb;
  size_t max, x, y;
  max = *sz;
  x = 0; ptr = buf;
  while(x < max) {
    if(my_isprintable(*ptr)) {
      ptr++; x++;
    } else {
      ptra = ptrb = ptr;
      ptrb++;
      y = max - x;
      y--;
      while(y--) { *(ptra++) = *(ptrb++); }
      max--;
    }
  }
  *sz = max;
  */
}



/**	Keywords, used to remove filter status lines from output.
*/
static char *keywords_to_remove[] = {
  "Status:",
  "Filter_status:",
  NULL
};



/**	Keyword, used to remove completed jobs.
*/
static char *keyword_done[] = {
  "done",
  NULL
};



/**	Check whether a string starts with one value from an array.
	@param	str	String to check.
	@param	array	Array of patterns which might occur at start.
	@return	1 if \a str starts with one of the strings from \a array,
	0 otherwise.
*/
static int start_with DK_P2(char *, str, char **, array)
{
  int back = 0;
  char **ptr;
  size_t lgt1, lgt2;
  
  ptr = array; lgt1 = strlen(str);
  while((*ptr) && (!back)) {
    lgt2 = strlen(*ptr);
    if(lgt1 >= lgt2) {
      
      if(strncmp(str, *ptr, lgt2) == 0) {
	back = 1; 
      }
    }
    ptr++;
  } 
  return back;
}



/**	Run LPRM request.
	@param	rq	YALC request.
	@return	1 on success, 0 on error.
*/
static
int
run_lprm DK_P1(yalc_rq_t *, rq)
{
  int back = 0;
  char *request = NULL;
  char response[8192];
  size_t sz;
  char opcode;
  unsigned long mpl; char *tmpfilename;
  int i, ende;
  FILE *f;
  dk_tcpip_t *sock;
  dk_ip_addr_t *addr;
  

  opcode = 0x05;
  mpl = dksf_get_maxpathlen();
  tmpfilename = dk_new(char,mpl);
  if(tmpfilename) {
    if(rq->app) {
      if(dkapp_tmpnam(rq->app, tmpfilename, (size_t)mpl)) {
        request = NULL;
        if((rq->args).lprm.all) {
	  sz = strlen(rq->user) + 12;
	  request = dk_new(char,sz);
	  if(request) {
	    sprintf(request, "%call %s all\n", opcode, rq->user);
	  }
	} else {
	  sz = strlen(rq->user) + strlen(rq->queue) + 6;
	  if((rq->argc) && (rq->argv)) {
	    for(i = 0; i < rq->argc; i++) {
	      if((rq->argv)[i]) {
	        sz += (1 + strlen((rq->argv)[i]));
	      }
	    }
	    request = dk_new(char,sz);
	    if(request) {
	      sprintf(request, "%c%s %s",
	        opcode, rq->queue, rq->user
	      );
	      for(i = 0; i < rq->argc; i++) {
	        if((rq->argv)[i]) {
		  strcat(request, " ");
		  strcat(request, (rq->argv)[i]);
		}
	      }
	      strcat(request, "\n");
	    }
	  } else {
	    sz = strlen(rq->user) + strlen(rq->queue) + 10;
	    request = dk_new(char,sz);
	    if(request) {
	      sprintf(request, "%c%s %s all\n",
	        opcode, rq->queue, rq->user
	      );
	    }
	  }
	}
	if(request) { 
	  f = dkapp_fopen(rq->app, tmpfilename, "wb");
	  if(f) { 
	    sock = dktcpip_new();
	    if(sock) { 
	      dktcpip_set_reuse(sock, 1);
	      if(rq->have_timeout) {
	        dktcpip_set_timeout(sock, rq->to);
	      }
	      addr = dktcpip_get_addr(sock, DK_IP_ADDR_LOCAL_WISHED);
	      dktcpip_addr_set_port(addr, rq->o_min, rq->o_max);
	      ymp_configure_local_nic();
	      if(dktcpipaddr_set_ip_any(addr)) {
		ymp_local_nic_configured();
	        
	        addr = dktcpip_get_addr(sock, DK_IP_ADDR_REMOTE_WISHED);
	        dktcpip_addr_set_port(addr, rq->portno, rq->portno);
	        
	        
	        
		ymp_lookup_remote(rq->host);
	        if(dktcpipaddr_set_ip_byname(addr,rq->host,sock)) {
		  ymp_looked_up_remote(rq->host);
	          
		  ymp_connect(rq->host);
	          if(dktcpip_up(sock)) { 
		    ymp_connected(rq->host);
		    sz = strlen(request);
		    ymp_try_send(sz);
		    if(dktcpip_write(sock, request, &sz)) {
		      ymp_have_send(sz);
		      
		      dktcpip_closewrite(sock);
		      back = 1;
		      ende = 0;
		      while(!ende) {
		        sz = sizeof(response); 
			ymp_try_receive(sz);
			if(dktcpip_read(sock, response, &sz)) {
			  ymp_have_received(sz);
			  
			  if(sz > 0) {
			    
			    remove_unprintables(response, &sz);
			    if(sz > 0) { 
			      (void)fwrite(response,1,sz,f);
			    }
			  } else {
			    ende = 1;
			  }
			} else { 
			  ende = 1;
			}
		      }
		    } else {
		      yme_error_while_sending();
		    }
		    dktcpip_closewrite(sock);
		    ymp_close_conn();
		    dktcpip_down(sock);
		    ymp_have_closed_conn();
	          } else {
		    yme_failed_to_establish_connection(rq->host);
		  }
	        } else {
		  yme_failed_to_find_remote_host(rq->host);
		}
	      } else {
		yme_failed_to_find_local_network_address();
	      }
	      dktcpip_delete(sock);
	    }
	    fclose(f);
	    f = dkapp_fopen(rq->app, tmpfilename, "r");
	    if(f) { 
	      ende = 0;
	      while(!ende) {
	        sz = fread(response,1,sizeof(response),f);
		
		if(sz > 0) {
		  
		  (void)fwrite(response,1,sz,stdout);
		} else {
		  ende = 1;
		}
	      }
	      fclose(f);
	    } else {
	      
	      yme_failed_to_read_from_file(tmpfilename);
	    }
	  } else {
	    
	    yme_failed_to_write_to_file(tmpfilename);
	  }
	  dk_delete(request);
	}
      } else {
	
	yme_could_not_find_temp_filename();
      }
    } else {
      
      yme_incomplete_configuration();
    }
    dk_delete(tmpfilename);
  } else {
    
    if(rq->app) { dkapp_err_memory(rq->app, 1, mpl); }
  }
  
  return back;
}



/**	Lpc commands.
*/
static char *lpc_keywords[] = {
  /*  0 */ "start",
  /*  1 */ "stop",
  /*  2 */ "enable",
  /*  3 */ "disable",
  /*  4 */ "abort",
  /*  5 */ "kill",
  /*  6 */ "topq",
  /*  7 */ "status",
  /* ----- END OF RFC1179 commands ----- */
  /*  8 */ "hold",
  /*  9 */ "holdall",
  /* 10 */ "release",
  /* 11 */ "move",
  /* 12 */ "redirect",
  /* 13 */ "active",
  /* 14 */ "lpd",
  /* 15 */ "reread",
  NULL
};



/**	@defgroup	yanolclpccommands	[yanolc] LPC commands. */
/*@{*/
/**	Start print queue.
*/
#define LPC_START	0

/**	Stop print queue.
*/
#define LPC_STOP	1

/**	Enable queueing to queue.
*/
#define LPC_ENABLE	2

/**	Disable queueing to queue.
*/
#define LPC_DISABLE	3

/**	Abort current job.
*/
#define LPC_ABORT	4

/**	Kill current job.
*/
#define LPC_KILL	5

/**	Move job to top of queue.
*/
#define LPC_TOPQ	6

/**	Show queue status.
*/
#define LPC_STATUS	7
/* ----- END OF RFC1179 commands ----- */
/**	Hold job.
*/
#define LPC_HOLD	8

/**	Hold all jobs.
*/
#define LPC_HOLDALL	9

/**	Release job.
*/
#define LPC_RELEASE	10

/**	???
*/
#define LPC_MOVE	11

/**	Redirect job to another queue.
*/
#define LPC_REDIRECT	12

/**	Check whether queue is active.
*/
#define LPC_ACTIVE	13

/**	???
*/
#define LPC_LPD		14

/**	Reread configuration.
*/
#define LPC_REREAD	15
/*@}*/


/**	Run LPC request.
	@param	rq	YALC request.
	@return	1 on success, 0 on error.
*/
static
int
run_lpc DK_P1(yalc_rq_t *, rq)
{
  int back = 0;
  unsigned long mpl;
  char *tmpfilename;
  char opcode;
  size_t sz;
  char *request;
  char response[8192];
  int i, ende;
  FILE *f;
  dk_tcpip_t *sock;
  dk_ip_addr_t *addr;

  
  mpl = dksf_get_maxpathlen();
  tmpfilename = dk_new(char,mpl);
  if(tmpfilename) {				
    if(rq->app) {
      if(dkapp_tmpnam(rq->app, tmpfilename, mpl)) {
	opcode = 0x06;
	if(rq->argc > 0) {
	  ende = dkstr_array_index(lpc_keywords, (rq->argv)[0], 1);
	  if(ende >= 0) {
	    if((rq->cmd = YALC_METHOD_LPRNG) || (ende < LPC_HOLD)) {
	      
	      sz = strlen(rq->queue);
	      sz += strlen(rq->user);
	      sz += 5;
	      if((rq->argc) && (rq->argv)) {
		for(i = 0; i < (rq->argc); i++) {
		  if((rq->argv)[i]) {
		    if(i == 1) {
		      sz += (1 + strlen(rq->queue));
		    } else {
		      sz += (1 + strlen((rq->argv)[i]));
		    }
		  }
		}
	      }
	      request = dk_new(char,sz);
	      if(request) {
		sprintf(request, "%c%s %s",
		  opcode, rq->queue, rq->user
		);
		if((rq->argc) && (rq->argv)) {
		  for(i = 0; i < (rq->argc); i++) {
		    if((rq->argv)[i]) {
		      strcat(request, " ");
		      if(i == 1) {
			strcat(request, rq->queue);
		      } else {
		        strcat(request, (rq->argv)[i]);
		      }
		    }
		  }
		}
		strcat(request, "\n");
		f = dkapp_fopen(rq->app, tmpfilename, "wb");
		if(f) {
                  sock = dktcpip_new();
		  if(sock) {
                    dktcpip_set_reuse(sock, 1);
		    if(rq->have_timeout) {
		      dktcpip_set_timeout(sock, rq->to);
		    }
		    addr = dktcpip_get_addr(sock, DK_IP_ADDR_LOCAL_WISHED);
		    dktcpip_addr_set_port(addr, rq->o_min, rq->o_max);
		    ymp_configure_local_nic();
		    if(dktcpipaddr_set_ip_any(addr)) {
		      ymp_local_nic_configured();
		      addr = dktcpip_get_addr(sock, DK_IP_ADDR_REMOTE_WISHED);
		      dktcpip_addr_set_port(addr, rq->portno, rq->portno);
		      ymp_lookup_remote(rq->host);
		      if(dktcpipaddr_set_ip_byname(addr,rq->host,sock)) {
			ymp_looked_up_remote(rq->host);
			ymp_connect(rq->host);
			if(dktcpip_up(sock)) { 
			  ymp_connected(rq->host);
			  sz = strlen(request);
			  ymp_try_send(sz);
			  if(dktcpip_write(sock, request, &sz)) {
			    ymp_have_send(sz);
			    dktcpip_closewrite(sock);
			    ende = 0;
			    while((!ende) && (can_continue())) {
			      sz = sizeof(response);
			      ymp_try_receive(sz);
			      if(dktcpip_read(sock, response, &sz)) {
				ymp_have_received(sz);
				back = 1;
				if(sz > 0) {
				  remove_unprintables(response, &sz);
				  if(sz > 0) {
				    (void)fwrite(response,1,sz,f);
				  }
				} else {
				  ende = 1;
				}
			      } else {
				ende = 1;
			      }
			    }
			  } else {
			    
			    yme_error_while_sending();
			  }
			  ymp_close_conn();
			  dktcpip_down(sock);
			  ymp_have_closed_conn();
			} else {
			  
			  yme_failed_to_establish_connection(rq->host);
			}
		      } else {
			
			yme_failed_to_find_remote_host(rq->host);
		      }
		    } else {
		      
		      yme_failed_to_find_local_network_address();
		    }
		    dktcpip_delete(sock);
		  } else {
		    
		    if(rq->app) { dkapp_err_memory(rq->app, sizeof(dk_tcpip_t), 1); }
		  }
		  fclose(f);
		  f = dkapp_fopen(rq->app, tmpfilename, "rb");
		  if(f) {
		    ende = 0;
		    while(!ende) {
		      sz = fread(response,1,sizeof(response),f);
		      if(sz > 0) {
			(void)fwrite(response,1,sz,stdout);
		      } else {
			ende = 1;
		      }
		    }
		    fclose(f);
		  } else {
		    yme_failed_to_read_from_file(tmpfilename);
		    
		  }
		} else {
		  
		  yme_failed_to_write_to_file(tmpfilename);
		}
		dk_delete(request);
	      } else {
		
		if(rq->app) { dkapp_err_memory(rq->app, 1, sz); }
	      }
	    } else {
	      
	      yme_lpc_for_lprng_only();
	    }
	  } else {
	    
	    yme_unknown_command_in_lpc();
	  }
	} else {
	  
	  yme_missing_command_in_lpc();
	}
      } else {
	
	yme_could_not_find_temp_filename();
      }
    } else {
      
    }
    dk_delete(tmpfilename);
  } else {
    
    if(rq->app) { dkapp_err_memory(rq->app, 1, mpl); }
  }
  
  return back;
}



/**	Run LPQ request.
	@param	rq	YALC request.
	@return	1 on success, 0 on error.
*/
static
int
run_lpq DK_P1(yalc_rq_t *, rq)
{
  int back = 0;
  unsigned long mpl;
  char     *tmpfilename, *ptr;
  char     opcode;
  size_t   sz;
  char     *request;
  char     response[8192];
  int      i, ende, t, must_print;
  dk_tcpip_t *sock;
  dk_ip_addr_t *addr;
  FILE *f;

  
  mpl = dksf_get_maxpathlen();
  tmpfilename = dk_new(char,mpl);
  if(tmpfilename) { 
    if(rq->app) { 
      if(dkapp_tmpnam(rq->app, tmpfilename, mpl)) {
	
        opcode = 0x04;
	(rq->args).lpq.remove_filter_status = 1;
	if((rq->args).lpq.short_status) {
	  opcode = 0x03;
	} else {
	  if(rq->type == YALC_METHOD_LPRNG) {
	    if(((rq->args).lpq.verbosity) || ((rq->args).lpq.max_verbosity)) {
	      (rq->args).lpq.remove_filter_status = 0;
	    }
	    if((rq->args).lpq.max_verbosity) {
	      opcode = 0x09;
	    }
	  } else {
            if((rq->type) == YALC_METHOD_BSD) {
	    if(((rq->args).lpq.verbosity) || ((rq->args).lpq.max_verbosity)) {
	      (rq->args).lpq.remove_filter_status = 0;
	    }
	    }
	  }
	}
	
	sz = strlen(rq->queue) + 2;
	if((rq->argc) && (rq->argv)) {
	  for(i = 0; i < rq->argc; i++) {
	    sz += (1 + strlen((rq->argv)[i]));
	  }
	}
	request = dk_new(char,sz);
	if(request) {
	  sprintf(request, "%c%s", opcode, rq->queue);
          if((rq->argc) && (rq->argv)) {
	    for(i = 0; i < rq->argc; i++) {
	      strcat(request, " ");
	      strcat(request, ((rq->argv)[i]));
	    }
	  }
	  strcat(request, "\n"); 
          back = 1;
	  sig_int_received = sig_pipe_received = kbhit_received = 0;
#if !DK_HAVE_SLEEP
	  if((rq->args).lpq.periodically) {
	    yme_no_sleep();
	  }
#endif
          do { 					
	    ende = 0;
	    f = dkapp_fopen(rq->app, tmpfilename, "wb");
	    if(f) {				
	      sock = dktcpip_new();
	      if(sock) {			
		dktcpip_set_reuse(sock, 1);
		if(rq->have_timeout) {
		  dktcpip_set_timeout(sock, rq->to);
		}
		addr = dktcpip_get_addr(sock, DK_IP_ADDR_LOCAL_WISHED);
		dktcpip_addr_set_port(addr, rq->o_min, rq->o_max);
		ymp_configure_local_nic();
		if(dktcpipaddr_set_ip_any(addr)) {
		    ymp_local_nic_configured();
		    
		    addr = dktcpip_get_addr(sock, DK_IP_ADDR_REMOTE_WISHED);
		    dktcpip_addr_set_port(addr, rq->portno, rq->portno);
		    
		    
		    
		    ymp_lookup_remote(rq->host);
		    if(dktcpipaddr_set_ip_byname(addr,rq->host,sock)) {
		      ymp_looked_up_remote(rq->host);
		      
		      ymp_connect(rq->host);
		      if(dktcpip_up(sock)) { 
			ymp_connected(rq->host);
			sz = strlen(request);
			ymp_try_send(sz);
			if(dktcpip_write(sock, request, &sz)) {
			  ymp_have_send(sz);
			  
			  dktcpip_closewrite(sock);
			  ende = 0;
			  while((!ende) && can_continue()) {
			    sz = sizeof(response);
			    ymp_try_receive(sz);
			    if(dktcpip_read(sock, response, &sz)) {
			      ymp_have_received(sz);
			      if(sz > 0) {
				remove_unprintables(response, &sz);
				if(sz > 0) {
				  (void)fwrite(response,1,sz,f);
				}
			      } else {
				ende = 1;
			      }
			    } else {
			      ende = 1;
			    }
			  }
			} else {
			  
			  back = 0;
			  yme_error_while_sending();
			}
			ymp_close_conn();
			dktcpip_down(sock);
			ymp_have_closed_conn();
		      } else {
			
			back = 0;
			yme_failed_to_establish_connection(rq->host);
		      }
		    } else {
		      back = 0;
		      
		      yme_failed_to_find_remote_host(rq->host);
		    }
		} else {
		    
		    back = 0;
		    yme_failed_to_find_local_network_address();
		}
		dktcpip_delete(sock);
	      } else {
		
		back = 0;
		if(rq->app) { dkapp_err_memory(rq->app, sizeof(dk_tcpip_t), 1); }
	      }
	      fclose(f);
	      if(ende && can_continue()) {
		f = dkapp_fopen(rq->app, tmpfilename, "r");
		if(f) {
		  must_print = 0;
		  if((rq->args).lpq.remove_filter_status) {
		    must_print = 1;
		  }
		  if((rq->args).lpq.remove_done_jobs) {
		    must_print = 1;
		  }
		  if(must_print) {
		    /* zeilenweise einlesen, Zeilen herausfiltern */
		    ende = 0;
		    while((!ende) && can_continue()) {
		      if(fgets(response,sizeof(response),f)) {
			must_print = 1;
			ptr = response;
			
			if((response[0] == ' ') || (response[0] == '\t')) {
                          ptr = dkstr_start(response, NULL);
			  if(ptr) {
			    if((rq->args).lpq.remove_filter_status) {
			      if(start_with(ptr, keywords_to_remove)) {
			        must_print = 0;
			      }
			    }
			  } else {
			    ptr = response;
			  }
			}
			if(must_print) {
			  if((rq->args).lpq.remove_done_jobs) {
			    
			    if(start_with(ptr, keyword_done)) {
			      
			      must_print = 0;
			    }
			  }
			}
			if(must_print) {
			  printf("%s", response);
			}
		      } else {
			ende = 1;
		      }
		    }
		  } else {
		    ende = 0;
		    while((!ende) && can_continue()) {
		      sz = fread(response,1,sizeof(response),f);
		      if(sz > 0) {
			(void)fwrite(response,1,sz,stdout);
		      } else {
			ende = 1;
		      }
		    }
		  }
		  fclose(f);
		} else {
		  
		  back = 0;
		  yme_failed_to_read_from_file(tmpfilename);
		}
	      }
	    } else {
	      
	      back = 0;
	      yme_failed_to_write_to_file(tmpfilename);
	    }
	    if(((rq->args).lpq.periodically) && can_continue()) {
	      t = (rq->args).lpq.period_time;
	      if(t < 1) t = 1;
#if DK_HAVE_SLEEP
	      sleep(t);
#endif
	    }
	  } while(can_continue() && ((rq->args).lpq.periodically));
	  dk_delete(request);
	} else {
	  
	  if(rq->app) { dkapp_err_memory(rq->app, 1, sz); }
	}
      } else {
	
	yme_could_not_find_temp_filename();
      }
    } else {
      
    }
    dk_delete(tmpfilename);
  } else {
    
    if(rq->app) { dkapp_err_memory(rq->app, 1, mpl); }
  }
  
  return back;
}



#if DK_HAVE_WINREG_H
/**	Registry key name to store job ID.
*/
static char job_number_key[] =
{ "Software\\DKrause\\Shared\\Yanolc" };
/**	Registry value name to store job ID.
*/
static char job_id_key[] = 
{ "JobId" };
#else
/**	File name to store job ID.
*/
static char job_number_file[] =
{ "lpr-job.id" };
#endif



/**	Get 3-digit job ID for print job.
	@param	rq	YALC request.
	@return	1 on success, 0 on error.
*/
static
int
get_job_number DK_P1(yalc_rq_t *, rq)
{
  int back = 0;
  char buffer[16];
  unsigned u;
#if DK_HAVE_WINREG_H
  HKEY  hkTemp;
  PHKEY phkSubkey;
  DWORD disp;
  LONG  retval;
  DWORD dwType, used_sz;
#else
  unsigned long mpl; char *fn; FILE *f;
#endif
  u = rq->job_number = 0;
#if DK_HAVE_WINREG_H
  hkTemp = 0;
  phkSubkey = &hkTemp;
  retval = RegCreateKeyExA(
    HKEY_LOCAL_MACHINE,
    job_number_key,
    0,
    NULL,
    REG_OPTION_NON_VOLATILE,
    KEY_ALL_ACCESS,
    NULL,
    phkSubkey,
    &disp
  );
  if(retval == ERROR_SUCCESS) {
    back = 1;
    used_sz = sizeof(buffer);
    retval = RegQueryValueExA(
      hkTemp,
      job_id_key,
      NULL,
      &dwType,
      buffer,
      &used_sz
    );
    if(retval == ERROR_SUCCESS) {
      if(dwType == REG_SZ) {
	if(used_sz < sizeof(buffer)) {
	  buffer[used_sz] = '\0';
	} else {
	  buffer[sizeof(buffer)-1] = '\0';
	}
	u = 0;
	if(sscanf(buffer, "%u", &u) == 1) {
	  rq->job_number = (unsigned short)u;
	}
      }
    }
    u = (unsigned)(rq->job_number);
    u++;
    if(u > 999) {
      u = 0;
    }
    back = 1;
    sprintf(buffer, "%u", u);
    retval = RegSetValueExA(
	hkTemp,
	job_id_key,
	0,
	REG_SZ,
	buffer,
	(strlen(buffer) + 1)
    );
    if(retval != ERROR_SUCCESS) {
      yme_err_save_jobid();
    }
    RegCloseKey(hkTemp);
  } else {
    yme_err_open_jobid_regkey(job_number_key);
  }
#else
  mpl = dksf_get_maxpathlen();
  fn = dk_new(char,mpl);
  if(fn) {
    if(dksf_get_tempdir(fn,mpl)) {
      if(mpl > (strlen(fn) + strlen(job_number_file) + strlen(fnsep))) {
	strcat(fn, fnsep);
	strcat(fn, job_number_file);
	if(rq) {
	  if(rq->app) {
	    f = dkapp_fopen(rq->app, fn, "r");
	  } else {
	    f = dksf_fopen(fn, "r");
	  }
	} else {
	  f = dksf_fopen(fn, "r");
	}
	if(f) {
	  if(fgets(buffer, sizeof(buffer), f)) {
	    if(sscanf(buffer, "%u", &u) == 1) {
	      rq->job_number = u;
	    }
	  }
	  fclose(f);
	}
	u = rq->job_number; u++;
	if(u > 999) u = 0;
	f = dkapp_fopen(rq->app, fn, "w");
	if(f) {
	  fprintf(f, "%u\n", u);
	  back = 1;
	  fclose(f);
	}
      } else {
	
	yme_file_name_too_long(fn);
      }
    } else {
      
      yme_could_not_find_temp_directory();
    }
    dk_delete(fn);
  } else {
    
    if(rq->app) { dkapp_err_memory(rq->app, 1, mpl); }
  }
#endif
  return back;
}



/**	Print on file by submitting an LPR request.
	@param	rq	YALC request.
	@param	fn	File name.
	@return	1 on success, 0 on error.
*/
static
int
lpr_one_file DK_P2(yalc_rq_t *, rq, char *, fn)
{
 int back = 0;
 char host_name[128], domain_name[128], response[8192];
#if DK_HAVE_LONG_LONG_INT
 char ullbuffer[128];
#endif
 char *short_file_name, *ptr;
 int flags, ende, x;
 FILE *f;
 dk_tcpip_t *sock;
 dk_ip_addr_t *addr;
 size_t sz, sz1, sz2;
 dk_long_long_unsigned_t ctrl_file_length, data_file_length, bytes_transmitted;
 dk_stat_t *st;
 
 ymp_print_one(fn);
 switch(rq->type) {
  case YALC_METHOD_RAWTCPIP:
  case YALC_METHOD_JETDIRECT: 
  {
   if(rq) {
    if(rq->app) {
     f = dkapp_fopen(rq->app, fn, "rb");
    } else {
     f = dksf_fopen(fn, "rb");
    }
   } else {
    f = dksf_fopen(fn, "rb");
   }
   if(f) {
    sock = dktcpip_new();
    if(sock) {
     dktcpip_set_reuse(sock, 1);
     if(rq->have_timeout) {
      dktcpip_set_timeout(sock, rq->to);
     }
     addr = dktcpip_get_addr(sock, DK_IP_ADDR_LOCAL_WISHED);
     dktcpip_addr_set_port(addr, rq->o_min, rq->o_max);
     ymp_configure_local_nic();
     if(dktcpipaddr_set_ip_any(addr)) {
      ymp_local_nic_configured();
      
      addr = dktcpip_get_addr(sock, DK_IP_ADDR_REMOTE_WISHED);
      dktcpip_addr_set_port(addr, rq->portno, rq->portno);
      
      
      
      ymp_lookup_remote(rq->host);
      if(dktcpipaddr_set_ip_byname(addr,rq->host,sock)) {
       ymp_looked_up_remote(rq->host);
       
       ymp_connect(rq->host);
       if(dktcpip_up(sock)) { 
	ymp_connected(rq->host);
	back = 1;
	ende = 0;
	while((!ende) && (can_continue())) {
	 ymp_try_read(fn, sizeof(response));
	 sz = fread(response,1,sizeof(response),f);
	 ymp_have_read(fn, sz);
	 if(sz > 0) {
	  sz1 = sz;
	  ymp_try_send(sz);
	  if(!dktcpip_write(sock,response,&sz)) {
	   ende = 1;
	   yme_error_while_sending();
	  } else {
	   ymp_have_send(sz);
	   if(sz1 != sz) {
	    ende = 1;
	    yme_error_while_sending();
	   }
	  }
	 } else {
	  ende = 1;
	 }
	}
	dktcpip_closewrite(sock);
	ymp_close_conn();
	dktcpip_down(sock);
	ymp_have_closed_conn();
       } else {
	
	yme_failed_to_establish_connection(rq->host);
       }
      } else {
       
       yme_failed_to_find_remote_host(rq->host);
      }
     } else {
      yme_failed_to_find_local_network_address();
      
     }
     dktcpip_delete(sock);
    } else {
     
     if(rq->app) { dkapp_err_memory(rq->app, sizeof(dk_tcpip_t), 1); }
    }
    fclose(f);
   }
  } break;
  case YALC_METHOD_LPRNG:
  case YALC_METHOD_BSD:
  {
   f = dkapp_fopen(rq->app, rq->control_file_name, "wb");
   if(f) {
    flags = 0;
    if(dksf_get_domainname(domain_name, sizeof(domain_name))) {
     flags |= 1;
    }
    if(dksf_get_hostname(host_name, sizeof(host_name))) {
     char *myptr;
     flags |= 2;
     /* 2009-10-01
        Shorten host name if necessary and possible.
     */
     if(strlen(host_name) >= 32) {
      myptr = strchr(host_name, '.');
      if(myptr) { *myptr = '\0'; }
     }
    }
    short_file_name = dkstr_rchr(fn, fnsep[0]);
    if(short_file_name) { short_file_name++; }
    else short_file_name = fn;
    if(get_job_number(rq)) {
      
      if(flags & 2) {
	if(strlen(host_name) < 32) {
	  if(rq->user) {
	    if(strlen(rq->user) < 32) {
	      if(flags & 1) {
	        /* 2009-10-01
		   Append domain name only if the name does not
		   contain the domain name yet.
		*/
	        if(strchr(host_name, '.') == NULL) {
		  if((strlen(host_name) + strlen(domain_name) + 1) < 32) {
		    flags |= 4;
		  }
		}
	      }
	      back = 1;
	      /* H */
	      fprintf(f, "H%s", host_name);
	      if(flags & 4) { fprintf(f, ".%s", domain_name); }
	      fprintf(f, "\n");
	      /* J */
	      ptr = (rq->args).lpr.job_title;
	      if(!ptr) {
		ptr = short_file_name;
	      }
	      if(ptr) {
		fprintf(f, "J");
		x = 0; 
		while(*ptr && (x < 100)) {
		  fprintf(f, "%c", *(ptr++)); x++;
		}
		fprintf(f, "\n");
	      }
	      /* C */
	      fprintf(f, "C");
	      ptr = (rq->args).lpr.class_name;
	      if(ptr) {
		x = 0;
		while(*ptr && (x < 32)) {
		  fprintf(f, "%c", *(ptr++)); x++;
		}
	      } else {
		fprintf(f, "A");
	      }
	      fprintf(f, "\n");
	      /* L */
	      if(!((rq->args).lpr.suppress_header)) {
		fprintf(f, "L");
		if(rq->user) {
		  fprintf(f, "%s", rq->user);
		}
		fprintf(f, "\n");
	      }
	      /* T */
	      if((rq->args).lpr.job_title) {
		ptr = (rq->args).lpr.job_title;
		fprintf(f, "T");
		  x = 0;
		  while(*ptr && (x < 80)) {
		    fprintf(f, "%c", *(ptr++)); x++;
		  }
		fprintf(f, "\n");
	      }
	      /* W */
	      if((rq->args).lpr.with) {
		fprintf(f, "W%d\n", (rq->args).lpr.with);
	      }
	      /* I */
	      if((rq->args).lpr.indent_cols) {
		fprintf(f, "I%d\n", (rq->args).lpr.indent_cols);
	      }
	      /* A */
	      if(rq->type == YALC_METHOD_LPRNG) {
		fprintf(f, "A%s@%s+%u\n",
		  rq->user, host_name, rq->job_number
		);
	      }
	      /* P */
	      fprintf(f, "P%s\n", rq->user);
	      /* Q */
	      if(rq->type == YALC_METHOD_LPRNG) {
	      }
	      /* R */
	      if(rq->type == YALC_METHOD_LPRNG) {
	      }
	      /* Z */
	      if(rq->type == YALC_METHOD_LPRNG) {
	      }
	      /* M */
	      if((rq->args).lpr.mail_recipient) {
		fprintf(f, "M%s\n", (rq->args).lpr.mail_recipient);
	      }
	      /* f */
	      switch((rq->args).lpr.type) {
		case YALC_TYPE_CIFPLOT: fprintf(f, "c"); break;
		case YALC_TYPE_DVI    : fprintf(f, "d"); break;
		case YALC_TYPE_PLOT   : fprintf(f, "g"); break;
		case YALC_TYPE_TROFF_N: fprintf(f, "n"); break;
		case YALC_TYPE_FILTER : fprintf(f, "f"); break;
		case YALC_TYPE_TROFF_T: fprintf(f, "t"); break;
		case YALC_TYPE_PR     : fprintf(f, "p"); break;
		case YALC_TYPE_RASTER : fprintf(f, "v"); break;
		default : fprintf(f, "l"); break;
	      }
	      fprintf(f, "dfA%03u%s", rq->job_number, host_name);
	      if(flags & 4) { fprintf(f, ".%s", domain_name); }
	      fprintf(f, "\n");
	      /* N */
	      if(strlen(short_file_name) < 132) {
		fprintf(f, "N%s\n", short_file_name);
	      }
	      /* U */
	      fprintf(f, "UdfA%03u%s", rq->job_number, host_name);
	      if(flags & 4) { fprintf(f, ".%s", domain_name); }
	      fprintf(f, "\n");
	    } else {	
	      yme_err_username_too_long(rq->user);
	    }
	  } else {	
	    yme_err_no_user_name();
	  }
	} else {	
	  yme_err_hostname_too_long(host_name);
	}
      } else {		
        yme_err_no_hostname();
      }
    } else {		
      yme_failed_to_find_job_number();
    }
    fclose(f);
    
    if(back) {
      back = 0;
      
#if DEBUG
      
#line 5520 "yalc.ctr"
      
#line 5521 "yalc.ctr"
#endif
      ctrl_file_length = data_file_length = ULLZERO;
      st = dkstat_open(rq->control_file_name);
      if(st) {
	ctrl_file_length = dkstat_size(st);
	dkstat_close(st);
	st = dkstat_open(fn);
	if(st) {
	  data_file_length = dkstat_size(st);
	  dkstat_close(st);
	  if(strlen(rq->queue) < (sizeof(response) - 2)) {
	   sprintf(response, "%c%s\n", 0x02, rq->queue);
	   if(data_file_length && ctrl_file_length) {
	   sock = dktcpip_new();
	   if(sock) {
	    dktcpip_set_reuse(sock, 1);
	    if(rq->have_timeout) {
	     dktcpip_set_timeout(sock, rq->to);
	    }
	    addr = dktcpip_get_addr(sock, DK_IP_ADDR_LOCAL_WISHED);
	    dktcpip_addr_set_port(addr, rq->o_min, rq->o_max);
	    ymp_configure_local_nic();
	    if(dktcpipaddr_set_ip_any(addr)) {
	     ymp_local_nic_configured();
	     
	     addr = dktcpip_get_addr(sock, DK_IP_ADDR_REMOTE_WISHED);
	     dktcpip_addr_set_port(addr, rq->portno, rq->portno);
	     
	     
	     
	     ymp_lookup_remote(rq->host);
	     if(dktcpipaddr_set_ip_byname(addr,rq->host,sock)) {
	      ymp_looked_up_remote(rq->host);
	      
	      ymp_connect(rq->host);
	      if(dktcpip_up(sock)) { 
	       ymp_connected(rq->host);
	       sz = strlen(response);
	       ymp_try_send(sz);
	       if(dktcpip_write(sock,response,&sz)) {
		ymp_have_send(sz);
		
		if(sz == strlen(response)) {
		 
		 sz = 2;
		 ymp_try_receive(sz);
		 if(dktcpip_read(sock,response,&sz)) {
		  ymp_have_received(sz);
		  
		  if(sz > 0) {
		   
		   if(!response[0]) {
		    
		    if(rq->data_file_first) {
		     
		     /* send data file first */
		     back = 1;
		     if(back) {
#if DK_HAVE_LONG_LONG_INT
		      ull_to_string(ullbuffer, data_file_length);
		      sprintf(response, "%c%s dfA%03u%s",
			0x03, ullbuffer, rq->job_number, host_name
		      );
#else
		      sprintf(response, "%c%lu dfA%03u%s",
			0x03, data_file_length, rq->job_number, host_name
		      );
#endif
		      if(flags & 4) {
			strcat(response, ".");
			strcat(response, domain_name);
		      }
		      strcat(response, "\n");
		      sz = strlen(response);
		      ymp_try_send(sz);
		      if(dktcpip_write(sock, response, &sz)) {
		       ymp_have_send(sz);
		       if(sz == strlen(response)) {
			sz = 2;
			ymp_try_receive(sz);
			if(dktcpip_read(sock, response, &sz)) {
			 ymp_have_received(sz);
			 if(sz) {
			  if(!response[0]) {
			   if(rq) {
			    if(rq->app) {
			     f = dkapp_fopen(rq->app, fn, "rb");
			    } else {
			     f = dksf_fopen(fn, "rb");
			    }
			   } else {
			    f = dksf_fopen(fn, "rb");
			   }
			   if(f) {
			    bytes_transmitted = data_file_length;
			    while(back && bytes_transmitted && can_continue()) {
			     if(bytes_transmitted > (dk_long_long_unsigned_t)sizeof(response)) {
			      sz = sizeof(response);
			     } else {
			      sz = (size_t)bytes_transmitted;
			     }
			     sz1 = sz;
			     ymp_try_read(fn,sz);
			     sz1 = fread(response,1,sz,f);
			     ymp_have_read(fn,sz1);
			     if(sz1 > 0) {
			      if(sz1 < sz) {
			       back = 0;
			      }
			      sz2 = sz1;
			      ymp_try_send(sz2);
			      if(dktcpip_write(sock,response,&sz2)) {
			       ymp_have_send(sz2);
			       if(sz2 != sz1) {
				back = 0;
				yme_error_while_sending();
			       }
			       /* bytes_transmitted -= ((unsigned long)(sz2)); */
			       if(bytes_transmitted > (dk_long_long_unsigned_t)sz2) {
			         bytes_transmitted -= ((dk_long_long_unsigned_t)sz2);
			       } else {
			         bytes_transmitted = ULLZERO;
			       }
			      } else {
			       back = 0;
			       yme_error_while_sending();
			      }
			     } else {
			      back = 0;
			      yme_failed_to_read_from_file(fn);
			     }
			    }
			    if(back) {
			     
			     response[0] = '\0';
			     sz = 1;
			     ymp_try_send(sz);
			     if(dktcpip_write(sock,response,&sz)) {
			      ymp_have_send(sz);
			      if(sz != 1) {
			       
			       yme_error_while_sending();
			      }
			     } else {
			      
			      yme_error_while_sending();
			     }
			    }
			    if(back) {
			     
			     sz = 2;
			     ymp_try_receive(sz);
			     if(dktcpip_read(sock,response,&sz)) {
			      ymp_have_received(sz);
			      
			      if(sz) {
			       
			       if(response[0]) {
				
				back = 0;
				
				yme_server_does_not_accept_jobs();
			       } else {
				
			       }
			      } else {
			       back = 0;
			       yme_error_while_receiving();
			      }
			     } else {
			      back = 0;
			      yme_error_while_receiving();
			     }
			    }
			    fclose(f);
			   } else {
			    back = 0;
			    yme_failed_to_read_from_file(fn);
			   }
			  } else {
			   back = 0;
			   yme_server_does_not_accept_jobs();
			  }
			 } else {
			  back = 0;
			  yme_error_while_receiving();
			 }
			} else {
			 back = 0;
			 yme_error_while_receiving();
			}
		       } else {
			back = 0;
			yme_error_while_sending();
		       }
		      } else {
		       back = 0;
		       yme_error_while_sending();
		      }
		     }
		     if(back) {
#if DK_HAVE_LONG_LONG_INT
		      ull_to_string(ullbuffer, ctrl_file_length);
		      sprintf(response, "%c%s cfA%03u%s",
			0x02, ullbuffer, rq->job_number, host_name
		      );
#else
		      sprintf(response, "%c%lu cfA%03u%s",
			0x02, ctrl_file_length, rq->job_number, host_name
		      );
#endif
		      if(flags & 4) {
			strcat(response, ".");
			strcat(response, domain_name);
		      }
		      strcat(response, "\n");
		      sz = strlen(response);
		      ymp_try_send(sz);
		      if(dktcpip_write(sock, response, &sz)) {
		       ymp_have_send(sz);
		       if(sz == strlen(response)) {
			sz = 2;
			ymp_try_receive(sz);
			if(dktcpip_read(sock, response, &sz)) {
			 ymp_have_received(sz);
			 if(sz) {
			  if(!response[0]) {
			   if(rq) {
			    if(rq->app) {
			     f = dkapp_fopen(rq->app,
			           rq->control_file_name, "rb");
			    } else {
			     f = dksf_fopen(rq->control_file_name, "rb");
			    }
			   } else {
			    f = dksf_fopen(rq->control_file_name, "rb");
			   }
			   if(f) {
			    bytes_transmitted = ctrl_file_length;
			    while(back && bytes_transmitted && can_continue()) {
			     if(bytes_transmitted > (dk_long_long_unsigned_t)sizeof(response)) {
			      sz = sizeof(response);
			     } else {
			      sz = (size_t)bytes_transmitted;
			     }
			     sz1 = sz;
			     ymp_try_read(rq->control_file_name,sz);
			     sz1 = fread(response,1,sz,f);
			     ymp_have_read(rq->control_file_name,sz1);
			     if(sz1 > 0) {
			      if(sz1 < sz) {
			       back = 0;
			      }
			      sz2 = sz1;
			      ymp_try_send(sz2);
			      if(dktcpip_write(sock,response,&sz2)) {
			       ymp_have_send(sz2);
			       if(sz2 != sz1) {
				back = 0;
				yme_error_while_sending();
			       }
			       /* bytes_transmitted -= ((unsigned long)(sz2)); */
			       if(bytes_transmitted > (dk_long_long_unsigned_t)sz2) {
			         bytes_transmitted -= ((dk_long_long_unsigned_t)sz2);
			       } else {
			         bytes_transmitted = ULLZERO;
			       }
			      } else {
			       back = 0;
			       yme_error_while_sending();
			      }
			     } else {
			      back = 0;
			      yme_failed_to_read_from_file(rq->control_file_name);
			     }
			    }
			    if(back) {
			     
			     response[0] = '\0';
			     sz = 1;
			     ymp_try_send(sz);
			     if(dktcpip_write(sock,response,&sz)) {
			      ymp_have_send(sz);
			      if(sz != 1) {
			       
			       yme_error_while_sending();
			      }
			     } else {
			      
			      yme_error_while_sending();
			     }
			    }
			    if(back) {
			     
			     sz = 2;
			     ymp_try_receive(sz);
			     if(dktcpip_read(sock,response,&sz)) {
			      ymp_have_received(sz);
			      
			      if(sz) {
			       
			       if(response[0]) {
				
				back = 0;
				
				yme_server_does_not_accept_jobs();
			       } else {
				
			       }
			      } else {
			       back = 0;
			       yme_error_while_receiving();
			      }
			     } else {
			      back = 0;
			      yme_error_while_receiving();
			     }
			    }
			    fclose(f);
			   } else {
			    back = 0;
			    yme_failed_to_read_from_file(rq->control_file_name);
			   }
			  } else {
			   back = 0;
			   yme_server_does_not_accept_jobs();
			  }
			 } else {
			  back = 0;
			  yme_error_while_receiving();
			 }
			} else {
			 back = 0;
			 yme_error_while_receiving();
			}
		       } else {
			back = 0;
			yme_error_while_sending();
		       }
		      } else {
		       back = 0;
		       yme_error_while_sending();
		      }
		     }
		    } else {
		     
		     /* send control file first */
		     back = 1;
		     if(back) {
#if DK_HAVE_LONG_LONG_INT
		      ull_to_string(ullbuffer, ctrl_file_length);
		      sprintf(response, "%c%s cfA%03u%s",
			0x02, ullbuffer, rq->job_number, host_name
		      );
#else
		      sprintf(response, "%c%lu cfA%03u%s",
			0x02, ctrl_file_length, rq->job_number, host_name
		      );
#endif
		      if(flags & 4) {
			strcat(response, ".");
			strcat(response, domain_name);
		      }
		      strcat(response, "\n");
		      sz = strlen(response); 
		      ymp_try_send(sz);
		      if(dktcpip_write(sock, response, &sz)) {
		       ymp_have_send(sz);
		       
		       if(sz == strlen(response)) {
			
			sz = 2;
			ymp_try_receive(sz);
			if(dktcpip_read(sock, response, &sz)) {
			 ymp_have_received(sz);
			 
			 if(sz) {
			  
			  if(!response[0]) {
			   
			   if(rq) {
			    if(rq->app) {
			     f = dkapp_fopen(rq->app,
			           rq->control_file_name, "rb");
			    } else {
			     f = dksf_fopen(rq->control_file_name, "rb");
			    }
			   } else {
			    f = dksf_fopen(rq->control_file_name, "rb");
			   }
			   if(f) {
			    
			    bytes_transmitted = ctrl_file_length;
			    while(back && bytes_transmitted && can_continue()) {
			     
			     if(bytes_transmitted > (dk_long_long_unsigned_t)sizeof(response)) {
			      sz = sizeof(response);
			     } else {
			      sz = (size_t)bytes_transmitted;
			     }
			     sz1 = sz;
			     ymp_try_read(rq->control_file_name, sz);
			     sz1 = fread(response,1,sz,f);
			     ymp_have_read(rq->control_file_name, sz1);
			     
			     if(sz1 > 0) {
			      if(sz1 < sz) { 
			       back = 0;
			      }
			      sz2 = sz1;
			      ymp_try_send(sz2);
			      if(dktcpip_write(sock,response,&sz2)) {
			       ymp_have_send(sz2);
			       
			       if(sz2 != sz1) {
				back = 0;
				yme_error_while_sending();
			       }
			       /* bytes_transmitted -= ((unsigned long)(sz2)); */
			       if(bytes_transmitted > (dk_long_long_unsigned_t)sz2) {
			         bytes_transmitted -= ((dk_long_long_unsigned_t)sz2);
			       } else {
			         bytes_transmitted = ULLZERO;
			       }
			      } else {
			       back = 0;
			       yme_error_while_sending();
			      }
			     } else {
			      back = 0;
                              yme_failed_to_read_from_file(rq->control_file_name);
			     }
			    }
			    if(back) {
			     
			     response[0] = '\0';
			     sz = 1;
			     ymp_try_send(sz);
			     if(dktcpip_write(sock,response,&sz)) {
			      ymp_have_send(sz);
			      if(sz != 1) {
			       
			       yme_error_while_sending();
			      }
			     } else {
			      
			      yme_error_while_sending();
			     }
			    }
			    if(back) {
			     
			     sz = 2;
			     ymp_try_receive(sz);
			     if(dktcpip_read(sock,response,&sz)) {
			      ymp_have_received(sz);
			      
			      if(sz) {
			       
			       if(response[0]) {
				
				back = 0;
				
				yme_server_does_not_accept_jobs();
			       } else {
				
			       }
			      } else {
			       back = 0;
			       yme_error_while_receiving();
			      }
			     } else {
			      back = 0;
			      yme_error_while_receiving();
			     }
			    }
			    fclose(f);
			   } else {
			    back = 0;
			    yme_failed_to_read_from_file(rq->control_file_name);
			   }
			  } else {
			   back = 0;
			   yme_server_does_not_accept_jobs();
			  }
			 } else {
			  back = 0;
			  yme_error_while_receiving();
			 }
			} else {
			 back = 0;
			 yme_error_while_receiving();
			}
		       } else {
			back = 0;
			yme_error_while_sending();
		       }
		      } else {
		       back = 0;
		       yme_error_while_sending();
		      }
		     }
		     if(back) {
#if DK_HAVE_LONG_LONG_INT
		      ull_to_string(ullbuffer, data_file_length);
		      sprintf(response, "%c%s dfA%03u%s",
			0x03, ullbuffer, rq->job_number, host_name
		      );
#else
		      sprintf(response, "%c%lu dfA%03u%s",
			0x03, data_file_length, rq->job_number, host_name
		      );
#endif
		      if(flags & 4) {
			strcat(response, ".");
			strcat(response, domain_name);
		      }
		      strcat(response, "\n");
		      sz = strlen(response);
		      
		      ymp_try_send(sz);
		      if(dktcpip_write(sock, response, &sz)) {
		       ymp_have_send(sz);
		       
		       if(sz == strlen(response)) {
			
			sz = 2;
			ymp_try_receive(sz);
			if(dktcpip_read(sock, response, &sz)) {
			 ymp_have_received(sz);
			 
			 if(sz) {
			  
			  if(!response[0]) {
			   
			   if(rq) {
			    if(rq->app) {
			     f = dkapp_fopen(rq->app, fn, "rb");
			    } else {
			     f = dksf_fopen(fn, "rb");
			    }
			   } else {
			    f = dksf_fopen(fn, "rb");
			   }
			   if(f) {
			    
			    bytes_transmitted = data_file_length;
			    while(back && bytes_transmitted && can_continue()) {
			     
			     if(bytes_transmitted > (dk_long_long_unsigned_t)sizeof(response)) {
			      sz = sizeof(response);
			     } else {
			      sz = (size_t)bytes_transmitted;
			     }
			     sz1 = sz;
			     ymp_try_read(fn, sz);
			     sz1 = fread(response,1,sz,f);
			     ymp_have_read(fn, sz1);
			     
			     if(sz1 > 0) {
			      if(sz1 < sz) {
			       back = 0;
			      }
			      sz2 = sz1;
			      ymp_try_send(sz2);
			      if(dktcpip_write(sock,response,&sz2)) {
			       ymp_have_send(sz2);
			       
			       if(sz2 != sz1) {
				back = 0;
				yme_error_while_sending();
			       }
			       /* bytes_transmitted -= ((unsigned long)(sz2)); */
			       if(bytes_transmitted > (dk_long_long_unsigned_t)sz2) {
			         bytes_transmitted -= ((dk_long_long_unsigned_t)sz2);
			       } else {
			         bytes_transmitted = ULLZERO;
			       }
			      } else {
			       back = 0;
			       yme_error_while_sending();
			      }
			     } else {
			      back = 0;
			      yme_failed_to_read_from_file(fn);
			     }
			    }
			    if(back) {
			     
			     response[0] = '\0';
			     sz = 1;
			     ymp_try_send(sz);
			     if(dktcpip_write(sock,response,&sz)) {
			      ymp_have_send(sz);
			      if(sz != 1) {
			       
			       yme_error_while_sending();
			      }
			     } else {
			      
			      yme_error_while_sending();
			     }
			    }
			    if(back) {
			     
			     sz = 2;
			     ymp_try_receive(sz);
			     if(dktcpip_read(sock,response,&sz)) {
			      ymp_have_received(sz);
			      
			      if(sz) {
			       
			       if(response[0]) {
				
				back = 0;
				
				yme_server_does_not_accept_jobs();
			       } else {
				
			       }
			      } else {
			       back = 0;
			       yme_error_while_receiving();
			      }
			     } else {
			      back = 0;
			      yme_error_while_receiving();
			     }
			    }
			    fclose(f);
			   } else {
			    back = 0;
			    yme_failed_to_read_from_file(fn);
			   }
			  } else {
			   back = 0;
			   yme_server_does_not_accept_jobs();
			  }
			 } else {
			  back = 0;
			  yme_error_while_receiving();
			 }
			} else {
			 back = 0;
			 yme_error_while_receiving();
			}
		       } else {
			back = 0;
			yme_error_while_sending();
		       }
		      } else {
		       back = 0;
		       yme_error_while_sending();
		      }
		     }
		    }
		   } else {
		    yme_server_does_not_accept_jobs();
		   }
		  } else {
		   yme_error_while_receiving();
		  }
		 } else {
		  yme_error_while_receiving();
		 }
		} else {
		 yme_error_while_sending();
		}
	       } else {
		yme_error_while_sending();
	       }
	      } else {
		   if(rq->host) { yme_failed_to_establish_connection(rq->host); }
	      }
             } else {
		 if(rq->host) { yme_failed_to_find_remote_host(rq->host); }
	     }
	    } else {
	       yme_failed_to_find_local_network_address();
	    }
	    dktcpip_delete(sock);
	   } else {
	    if(rq->app) { dkapp_err_memory(rq->app, sizeof(dk_tcpip_t), 1); }
	   }
	   } else {
	    yme_illegal_file_length(ctrl_file_length, data_file_length);
	   }
	  } else {
	   yme_queue_name_too_long(rq->queue);
	  }
	} else {
	   yme_stat_failed_for_file(fn);
	}
      } else {
	yme_stat_failed_for_file(rq->control_file_name);
      }
    } else {
      /* yme_failed_to_find_job_number(); */
    }
   } else {
    yme_failed_to_write_to_file(rq->control_file_name);
   }
  } break;
 }
 ymp_printed_one(fn);
 
 return back;
}



/**	Run LPR request.
	@param	rq	YALC request.
	@return	1 on success, 0 on error.
*/
static
int
run_lpr DK_P1(yalc_rq_t *, rq)
{
  int back = 0;
  unsigned long mpl;
  char response[8192];
  char *pchr, *tmpfn1, *tmpfn2, *tmpfn3;
  size_t sz;
  int ende, i, j;
  FILE *f;
#if DK_HAVE_FEATURE_BACKSLASH
  dk_fne_t *fne;
#endif
  
  mpl = dksf_get_maxpathlen();
  tmpfn1 = dk_new(char,mpl);
  tmpfn2 = dk_new(char,mpl);
  tmpfn3 = dk_new(char,mpl);
  sig_int_received = sig_pipe_received = kbhit_received = 0;
  if(tmpfn1 && tmpfn2 && tmpfn3) {		
   if((rq->args).lpr.number_of_copies == 0) {
     (rq->args).lpr.number_of_copies = 1;
   }
   rq->control_file_name = tmpfn2;
   if(rq->app) {				
    if(dkapp_tmpnam(rq->app,tmpfn1,mpl)) {
     if(dkapp_tmpnam(rq->app,tmpfn2,mpl)) {	
      if(!((rq->argc) && (rq->argv))) {		
       f = dkapp_fopen(rq->app, tmpfn1, "wb");
       if(f) {					
	rq->argv = &tmpfn1; rq->argc = 1;
	ende = 0;
	while((!ende) && (can_continue())) {	
	 sz = fread(response,1,sizeof(response),stdin);
	 if(sz > 0) {				
	  if(!(fwrite(response,1,sz,f) == sz)) {
	   ende = 1;
	  }
	 } else {
	  ende = 1;
	 }
	}
	fclose(f);
       } else {
	yme_failed_to_write_to_file(tmpfn1);
       }
      }
      if((rq->argc) && (rq->argv)) {		
       for(i = 0; i < (rq->argc); i++) {
	pchr = ((rq->argv)[i]);			
	if(strlen(pchr) < mpl) {
	 strcpy(tmpfn3, pchr);
	 dksf_correct_fnsep(tmpfn3);
#if DK_HAVE_FEATURE_BACKSLASH
         if (dksf_must_expand_filename(tmpfn3)) {
	  fne = dkfne_open(tmpfn3, 1, 0);
	  if(fne) {
	   back = 1;
	   while(dkfne_next(fne)) {
	    for(j = 0; j < ((rq->args).lpr.number_of_copies); j++) {
	    if(!lpr_one_file(rq, dkfne_get_fullname(fne))) {
	     back = 0;
	    }
	    }
	   }
	   dkfne_close(fne);
	  } else {
	   yme_failed_to_open_filename_expander(tmpfn3);
	  }
	 } else {
	  back = 1;
	  for(j = 0; j < ((rq->args).lpr.number_of_copies); j++) {
	   if(!lpr_one_file(rq, tmpfn3)) {
	    back = 0;
	   }
	  }
	 }
#else
	 back = 1;
	 for(j = 0; j < ((rq->args).lpr.number_of_copies); j++) {
	  if(!lpr_one_file(rq, tmpfn3)) {
	   back = 0;
	  }
	 }
#endif
	} else {
	 yme_file_name_too_long(pchr);
	}
       }
      } else {
       yme_no_data_to_print();
      }
     } else {
      yme_could_not_find_temp_filename();
     }
    } else {
     yme_could_not_find_temp_filename();
    }
   } else {
    yme_incomplete_configuration();
   }
  } else {
   if(rq->app) { dkapp_err_memory(rq->app, sizeof(char), mpl); }
  }
  if(tmpfn1) { dk_delete(tmpfn1); }
  if(tmpfn2) { dk_delete(tmpfn2); }
  if(tmpfn3) { dk_delete(tmpfn3); }
  
  return back;
}



/**	SNMP community: public.
*/
static char str_snmp_comm_public[] = { "public" };



/**	SNMP version: 1.
*/
static char str_snmp_vers_1[] = { "1" };



/**	Run snmpyalc request (SNMP status).
	@param	rq	YALC request.
	@return	1 on success, 0 on error.
*/
static int
run_snmp_status DK_P1(yalc_rq_t *,rq)
{
  int back = 0;
  dk_stream_t *cfg_stream;

  
  if((rq->app) && (rq->snmp_host) && (rq->snmp_type)) {
    /* cfg_stream = dkapp_read_file(rq->app, "snmp.cfg"); */
    cfg_stream = yalc_snmp_cfg_open(rq);
    if(cfg_stream) {
      back = run_snmp_request(
        rq,
	rq->snmp_host,
	((rq->snmp_comm) ? (rq->snmp_comm) : str_snmp_comm_public),
	rq->snmp_type,
	cfg_stream,
	((rq->snmp_vers) ? (rq->snmp_vers) : str_snmp_vers_1)
      );
      dkstream_close(cfg_stream);
    } else {
      
      yme_snmp_failed_to_open_configuration();
    }
  } else {
    
    if(!(rq->snmp_host)) {
      yme_snmp_no_host();
    }
    if(!(rq->snmp_type)) {
      yme_snmp_no_type();
    }
  }
  
  return back;
}




/**	Run klpinfo request (SNMP short).
	@param	rq	YALC request.
	@return	1 on success, NULL on error.
*/
static int
run_snmp_short DK_P1(yalc_rq_t *,rq)
{
  int back = 0;
  dk_stream_t *cfg_stream;

  
  if((rq->app) && (rq->snmp_host) && (rq->snmp_type)) {
    /* cfg_stream = dkapp_read_file(rq->app, "snmp.cfg"); */
    cfg_stream = yalc_snmp_cfg_open(rq);
    if(cfg_stream) {
      back = run_snmp_short_request(
        rq,
	rq->snmp_host,
	((rq->snmp_comm) ? (rq->snmp_comm) : str_snmp_comm_public),
	rq->snmp_type,
	((rq->snmp_vers) ? (rq->snmp_vers) : str_snmp_vers_1)
      );
      dkstream_close(cfg_stream);
    } else {
      
      yme_snmp_failed_to_open_configuration();
    }
  } else {
    
    if(!(rq->snmp_host)) {
      yme_snmp_no_host();
    }
    if(!(rq->snmp_type)) {
      yme_snmp_no_type();
    }
  }
  
  return back;
}



int
yalc_run DK_P1(yalc_rq_t *, rq)
{
  int back = 0;
#ifdef SIGINT
  dk_signal_disp_t old_disp_int;
#endif
#ifdef SIGPIPE
  dk_signal_disp_t old_disp_pipe;
#endif
  char *x;
  
  if(rq) {
    ym_init(rq->app);
#ifdef SIGINT
	  old_disp_int = dksignal_set(SIGINT, sig_int_handler);
#endif
#ifdef SIGPIPE
	  old_disp_pipe = dksignal_set(SIGPIPE, sig_pipe_handler);
#endif
#if DK_HAVE_WINREG_H
    regkey_open(rq);
#endif
    rq->cfg_file = NULL;
    rq->read_cfg_res = 1; 
    rq->cfg_file = (void *)read_cfg(rq);
    rq->queue = NULL; rq->host = NULL; rq->dev = NULL;
    rq->user = NULL;
    rq->data_file_first = 0;
    rq->printer_from_env = NULL;
    rq->type = YALC_METHOD_UNKNOWN;
    rq->portno = 0;
    rq->o_min = 0; rq->o_max = 0; rq->xuser_allowed = 0;
    

    ymp_going_to_complete_request();
    if(complete_request(rq)) {
      ymp_request_completed();
#if DEBUG
      /* print_cfg((yalc_cfg *)(rq->cfg_file), stdout); */
      printf(  "Readcfg: %d\n", rq->read_cfg_res);
      if(rq->printer_name) {
	printf("Printer: %s\n", rq->printer_name);
      }
      if(rq->dev) {
	printf("Device:  %s\n", rq->dev);
      }
      if(rq->queue) {
	printf("Queue:   %s\n", rq->queue);
      }
      if(rq->host) {
	printf("Host:    %s\n", rq->host);
      }
      printf(  "Type:    %d\n", rq->type);
      printf(  "Port:    %u\n", ((unsigned)(rq->portno)));
      printf(  "Origin:  %u %u\n",
	((unsigned)(rq->o_min)),
	((unsigned)(rq->o_max))
      );
      printf(  "Timeout: %d %lf\n", rq->have_timeout, rq->to);
      printf(  "Xu:      %d\n", rq->xuser_allowed);
      printf(  "User:    %s\n",
	((rq->user) ? (rq->user) : ("-"))
      );
#endif
      switch(rq->cmd) {
	case YALC_OP_LPR : {
	  switch(rq->type) {
	    case YALC_METHOD_RAWTCPIP:
	    case YALC_METHOD_JETDIRECT :
	    {
	      if((rq->dev) && (rq->host) && (rq->app)) {
		back = run_lpr(rq);
	      }
	    } break;
	    case YALC_METHOD_LPRNG:
	    case YALC_METHOD_BSD:
	    {
	      if((rq->dev) && (rq->queue) && (rq->host) && (rq->app)) {
		back = run_lpr(rq);
	      }
	    } break;
	    default: {
	      yme_requires_type_rjlb();
	    } break;
	  }
	} break;
	case YALC_OP_LPQ : {
	  switch(rq->type) {
	    case YALC_METHOD_LPRNG:
	    case YALC_METHOD_BSD:
	    {
	      if((rq->dev) && (rq->queue) && (rq->host) && (rq->app)) {
		back = run_lpq(rq);
	      }
	    } break;
	    default : {
	      yme_requires_type_lb();
	    } break;
	  }
	} break;
	case YALC_OP_LPRM : {
	  switch(rq->type) {
	    case YALC_METHOD_LPRNG:
	    case YALC_METHOD_BSD:
	    {
	      if((rq->queue) && (rq->host) && (rq->user) && (rq->app)) {
		if(rq->dev) {
	          back = run_lprm(rq);
		}
	      }
	    } break;
	    default : {
	      yme_requires_type_lb();
	    } break;
	  }
	} break;
	case YALC_OP_LPC : {
	  switch(rq->type) {
	    case YALC_METHOD_LPRNG:
	    case YALC_METHOD_BSD: {
	      if((rq->queue) && (rq->host) && (rq->user) && (rq->app)) {
		if(rq->dev) {
		  back = run_lpc(rq);
		}
	      } else {
		yme_incomplete_configuration();
	      }
	    } break;
	    default: {
	      yme_requires_type_lb();
	    } break;
	  }
	} break;
	case YALC_OP_SNMP_STATUS: {
	  (rq->args).snmp.output_found = 0;
	  back = run_snmp_status(rq);
          if((rq->args).snmp.force_output) {
          if(!((rq->args).snmp.output_found)) {
            printf("-\n");
	    (rq->args).snmp.output_found = 1;
          }
          }
	} break;
	case YALC_OP_SNMP_SHORT: {
	  
	  (rq->args).snmp.output_found = 0;
	  back = run_snmp_short(rq);
          if((rq->args).snmp.force_output) {
          if(!((rq->args).snmp.output_found)) {
            printf("-\n");
	    (rq->args).snmp.output_found = 1;
          }
          }
	} break;
      }
    } else {
      yme_failed_to_complete_request();
    }
#if DK_HAVE_WINREG_H
    regkey_close(rq);
#endif
    if(rq->cfg_file) {
      forget_cfg(rq->cfg_file);
      rq->cfg_file = NULL;
    }
    x = rq->user; if(x) { dk_delete(x); } rq->user = NULL;
    x = rq->queue; if(x) { dk_delete(x); } rq->queue = NULL;
    x = rq->host; if(x) { dk_delete(x); } rq->host = NULL;
    x = rq->dev; if(x) { dk_delete(x); } rq->dev = NULL;
    x = rq->printer_from_env; if(x) { dk_delete(x); } rq->printer_from_env = NULL;
#ifdef SIGINT
	  (void)dksignal_set(SIGINT, old_disp_int);
#endif
#ifdef SIGPIPE
	  (void)dksignal_set(SIGPIPE, old_disp_pipe);
#endif
  } else {
    yme_incomplete_configuration();
  } 
  return back;
}



/**	Yanolc version text.
*/
char *yalc_version[] = {
  "",
  "yanolc - Yet ANOther Lpr(ng) Client (klpr/klq/klprm/klpc), version " VERSNUMB,
  "Copyright (C) 2001-2010 - Dipl.-Ing. Dirk Krause",
  "http://dktools.sourceforge.net/yanolc.html",
  "",
"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 other 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.",
NULL
};



char **yalc_get_version DK_P0()
{
  return yalc_version;
}


