/*
	WARNING: This file was generated by dkct.
	Changes you make here will be lost if dkct is run again!
	You should modify the original source and run dkct on it.
	Original source: dknet.ctr
*/

/*
Copyright (C) 2012-2013, Dirk Krause

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice,
  this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above opyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.
* Neither the name of the author nor the names of contributors may be used
  to endorse or promote products derived from this software without specific
  prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/**	@file dknet.c The dknet module.
*/


#line 116 "dknet.ctr"

#include "dknet.h"





#line 122 "dknet.ctr"



#if DK3_HAVE_SELECT || DK3_ON_WINDOWS



/**	Version number.
*/
static dkChar const		dknet_version[] = { DKT_VERSION };



/**	Keywords used by the program, not localized.
*/
static dkChar const * const	dknet_noloc[] = {
/* 0 */
dkT("dkt-3"),

/* 1 */
dkT("dknet.str"),

/* 2 */
dkT("dknet.txt"),

/* 3 */
dkT("dknet"),

/* 4 */
dkT(" "),

/* 5 */
dkT("unlimited"),

NULL


#line 164 "dknet.ctr"
};



/**	Message texts used by the module, localized.
*/
static dkChar const * const     dknet_loc[] = {
/* 0 */
dkT("Just one file name allowed!"),

/* 1 */
dkT("Not a number: \""),

/* 2 */
dkT("\"!"),

/* 3 */
dkT("Range overflow (not in 1...65535): \""),

/* 4 */
dkT("\"!"),

/* 5 */
dkT("Remote port must not be 0!"),

/* 6 */
dkT("Port number already set!"),

/* 7 */
dkT("Host name already set!"),

/* 8 */
dkT("Number of clients must not be negative!"),

/* 9 */
dkT("Unknown option: \""),

/* 10 */
dkT("\"!"),

/* 11 */
dkT("Incompatible actions!"),

/* 12 */
dkT("Option \"-r\" requires two arguments (Host name and port number)!"),

/* 13 */
dkT("Option \"-s\" requires an argument (port number)!"),

/* 14 */
dkT("Option \"-n\" requires an argument (maximum number of clients)!"),

/* 15 */
dkT("Option \"-a\" requires an argument (allowed client)!"),

/* 16 */
dkT("Can not combine send/receive with help/version/license!"),

/* 17 */
dkT("Can not send and receive at same time!"),

/* 18 */
dkT("No action was choosen!"),

/* 19 */
dkT("Use \"dknet --help\" for help!"),

/* 20 */
dkT("Creating listener socket set."),

/* 21 */
dkT("Finished creating listener socket set."),

/* 22 */
dkT("Waiting for client connections."),

/* 23 */
dkT("Finished waiting for client connections, closing listener socket set."),

/* 24 */
dkT("Listener socket set closed."),

/* 25 */
dkT("Sending data."),

/* 26 */
dkT("Finished sending data."),

/* 27 */
dkT("Receiving data."),

/* 28 */
dkT("Finished receiving data."),

/* 29 */
dkT("Failed to read initial byte from client!"),

/* 30 */
dkT("Error while sending to socket "),

/* 31 */
dkT(", disconnected!"),

NULL


#line 289 "dknet.ctr"
};



/**	Help text to show if no help file is found.
*/
dkChar const * const    dknet_help_text[] = {
dkT(""),
dkT("NAME"),
dkT(""),
dkT("\tdknet - Dirk Krause's network tool"),
dkT(""),
dkT("SYNOPSIS"),
dkT(""),
dkT("\tdknet -s <port> [-n <clients>] [-a <address>[/<mask>]] [<file>]"),
dkT("\tdknet -r <host> <port> [-t] [-f <number>] [<file>]"),
dkT("\tdknet -h"),
dkT("\tdknet -v"),
dkT("\tdknet -l"),
dkT(""),
dkT("DESCRIPTION"),
dkT(""),
dkT("The dknet program transfers data over a network. One sender process can"),
dkT("send data to multiple recipient processes, each input data block is sent"),
dkT("to each recipient sequently (no broadcast/multicast involved)."),
dkT(""),
dkT("The first of the commands above runs the program as server and provides"),
dkT("the specified file to the recipients. If no file is specified, data from"),
dkT("standard input is used."),
dkT("The -s option configures the port to listen for connection attempts."),
dkT("The -n option specifies the maximum number of clients (default: 1). 0 or"),
dkT("the \"unlimited\" keyword indicates an unlimited number of clients, the"),
dkT("last client connecting has to use the -t option to start the transfer."),
dkT("The -a option can be used to restrict clients to IP addresses, this option"),
dkT("can be used multiple times."),
dkT(""),
dkT("The second command runs the program as recipient and connects to the"),
dkT("specified host and port to receive data. Data is saved to the specified"),
dkT("file. If no file is specified, data is written to standard output."),
dkT("The -t option can be used at the last client connecting to start the"),
dkT("transfer immediately."),
dkT("The -f option can be used to enforce an output file flush after each"),
dkT("n-th block."),
dkT(""),
dkT("OPTIONS"),
dkT(""),
dkT("-s\t\t\truns the program as sender."),
dkT(""),
dkT("-n <clients>\t\tspecifies the maximum number of clients."),
dkT(""),
dkT("-a <address>[/<mask>]\trestricts clients to IP addresses."),
dkT(""),
dkT("-r\t\t\truns the program as recipient."),
dkT(""),
dkT("-t\t\t\ttells the sender to start the transfer immediately."),
dkT(""),
dkT("-f <number>\t\tflushes output buffers after each n-th block."),
dkT(""),
dkT("-h\t\t\tshows the help text."),
dkT(""),
dkT("-v\t\t\tshows the version number."),
dkT(""),
dkT("-l\t\t\tshows the license conditions."),
dkT(""),
dkT("RETURN VALUE"),
dkT(""),
dkT("Exit status code 0 indicates success. Positive exit status codes indicate"),
dkT("errors."),
dkT(""),
dkT("NOTES"),
dkT(""),
dkT("Previous versions of this program used \"-r host:port\". This version"),
dkT("uses \"-r host port\" (the -r option takes two arguments)."),
dkT("This change was necessary as the colon is used in IPv6 addresses"),
dkT("so we can no longer use it to separate address and port number."),
dkT(""),
dkT("AUTHOR"),
dkT(""),
dkT("Dirk Krause"),
dkT(""),
dkT("COPYRIGHT AND LICENSE"),
dkT(""),
dkT("Please run"),
dkT("  dknet -l"),
dkT("to see the license conditions."),
dkT(""),
dkT("SEE ALSO"),
dkT(""),
dkT("http://dktools.sourceforge.net"),
dkT(""),
NULL


#line 381 "dknet.ctr"
};



/**	License conditions for dknet.
*/
dkChar const * const    dknet_license_text[] = {
dkT(""),
dkT("License conditions"),
dkT("=================="),
dkT("Copyright (c) 2012-2013, Dirk Krause"),
dkT("All rights reserved."),
dkT(""),
dkT("Redistribution and use in source and binary forms,"),
dkT("with or without modification, are permitted provided"),
dkT("that the following conditions are met:"),
dkT(""),
dkT("* Redistributions of source code must retain the above"),
dkT("  copyright notice, this list of conditions and the"),
dkT("  following disclaimer."),
dkT("* Redistributions in binary form must reproduce the above "),
dkT("  copyright notice, this list of conditions and the following"),
dkT("  disclaimer in the documentation and/or other materials"),
dkT("  provided with the distribution."),
dkT("* Neither the name of the copyright holder(s) nor the names of"),
dkT("  contributors may be used to endorse or promote"),
dkT("  products derived from this software without specific"),
dkT("  prior written permission."),
dkT(""),
dkT("THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND"),
dkT("CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,"),
dkT("INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF"),
dkT("MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE"),
dkT("DISCLAIMED."),
dkT("IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE"),
dkT("LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,"),
dkT("EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT"),
dkT("LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;"),
dkT("LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)"),
dkT("HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN"),
dkT("CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE"),
dkT("OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS"),
dkT("SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH"),
dkT("DAMAGE."),
dkT(""),
NULL


#line 428 "dknet.ctr"
};



/**	Long options keywords.
*/
static dkChar const * const	dknet_long_options[] = {
/* 0 */
dkT("r$eceive"),

/* 1 */
dkT("se$nd"),

/* 2 */
dkT("h$elp"),

/* 3 */
dkT("v$ersion"),

/* 4 */
dkT("l$icense"),

/* 5 */
dkT("recv"),

/* 6 */
dkT("c$lients"),

/* 7 */
dkT("a$llow"),

/* 8 */
dkT("st$art"),

NULL


#line 446 "dknet.ctr"
};



/**	Initialize job structure.
	@param	job	Job structure to initialize.
*/
static
void
dknet_job_init(dknet_job *job)
{
  job->app = NULL;
  job->msg = NULL;
  job->ssess = NULL;
  job->isess = NULL;
  job->sacl = NULL;
  job->iacl = NULL;
  job->hn = NULL;
  job->fn = NULL;
  job->rfn = NULL;
  job->fipo = NULL;
  job->cmd = 0;		/* Default: Read data from network. */
  job->exval = 1;	/* Set to 0 later on success. */
  job->flush = 0UL;
  job->clmax = 1;
  job->clcur = 0;
  job->stt = 0;
  job->blog = 5;
  job->llerr = 0;
  job->nport = 0;
}



/**	Job cleanup.
	@param	job	Job structure to clean up.
*/
static
void
dknet_job_cleanup(dknet_job *job)
{
}



/**	Clean up data structures set up during and after
	command line processing.
*/
static
void
dknet_job_cleanup_command_line_processing(dknet_job *job)
{
  void *pp;
  /*
  	Release all acceptable clients.
  */
  if(job->sacl) {
    if(job->iacl) {
      dk3sto_it_reset(job->iacl);
      while(NULL != (pp = dk3sto_it_next(job->iacl))) {
        dk3_delete(pp)
      }
      dk3sto_it_close(job->iacl); job->iacl = NULL;
    }
    dk3sto_close(job->sacl); job->sacl = NULL;
  }
  /*
  	Release host name.
  */
  if(job->hn) {
    dk3_delete(job->hn)
    job->hn = NULL;
  }
  /*
  	Release file name.
  */
  if(job->fn) {
    dk3_delete(job->fn)
    job->fn = NULL;
  }
}



/**	Save file name in job.
	@param	job	Job structure.
	@param	fn	File name to store.
	@return	1 on success, 0 on error.
*/
static
int
dknet_save_filename(dknet_job *job, dkChar const *fn)
{
  int	back = 0;
  if(!(job->fn)) {
    job->fn = dk3str_dup_app(fn, job->app);
    if(job->fn) {
      back = 1;
    } else {
      job->exval = DKNET_EXIT_ERROR_MEMORY;
    }
  } else {
    /* ERROR: Already have file name! */
    dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 0);
    job->exval = DKNET_EXIT_ERROR_OPTIONS;
  }
  return back;
}



/**	Save port number to send data to or receive data from.
	@param	job	Job structure.
	@param	ptr	Port number as text.
	@return	1 on success, 0 on error.
*/
static
int
dknet_save_portnumber(dknet_job *job, dkChar const *ptr)
{
  int		 back = 0;
  unsigned	 u;
  unsigned short us;
  

#line 570 "dknet.ctr"
  if(1 == dk3sf_sscanf3(ptr, dkT("%u"), &u)) {
    us = (unsigned short)u;
    if(u == (unsigned)us) {
      if(us > 0) {
        if(0 == job->nport) {
	  job->nport = us;
	  back = 1;
	} else {		

#line 578 "dknet.ctr"
	  /* ERROR: Port number already set! */
	  job->exval = DKNET_EXIT_ERROR_OPTIONS;
	  dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 6);
	}
      } else {			

#line 583 "dknet.ctr"
        /* ERROR: Remote port must not be 0! */
        job->exval = DKNET_EXIT_ERROR_OPTIONS;
	dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 5);
      }
    } else {			

#line 588 "dknet.ctr"
      /* ERROR: Range overflow! */
      dk3app_log_3(job->app, DK3_LL_ERROR, job->msg, 3, 4, ptr);
      job->exval = DKNET_EXIT_ERROR_OPTIONS;
    }
  } else {			

#line 593 "dknet.ctr"
    /* ERROR: Not a number! */
    dk3app_log_3(job->app, DK3_LL_ERROR, job->msg, 1, 2, ptr);
    job->exval = DKNET_EXIT_ERROR_OPTIONS;
  } 

#line 597 "dknet.ctr"
  return back;
}



/**	Save host name and port number to receive data from.
	@param	job	Job structure.
	@param	p1	Host name.
	@param	p2	Port number.
	@return	1 on success, 0 on error.
*/
static
int
dknet_save_host_and_port(dknet_job *job, dkChar const *p1, dkChar const *p2)
{
  int		 back = 0;
  

#line 614 "dknet.ctr"
  if(!(job->hn)) {
    job->hn = dk3str_dup_app(p1, job->app);
    if(job->hn) {
      back = dknet_save_portnumber(job, p2);
    } else {		

#line 619 "dknet.ctr"
      job->exval = DKNET_EXIT_ERROR_MEMORY;
    }
  } else {		

#line 622 "dknet.ctr"
    /* ERROR: Host name already defined! */
    job->exval = DKNET_EXIT_ERROR_OPTIONS;
    dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 7);
  } 

#line 626 "dknet.ctr"
  return back;
}



/**	Save maximum number of clients.
	@param	job	Job structure.
	@param	ptr	Text containing the number.
	@return	1 on success, 0 on error.
*/
static
int
dknet_save_max_clients(dknet_job *job, dkChar const *ptr)
{
  int		 back = 0;
  int		 mx = 0;
  

#line 643 "dknet.ctr"
  if(1 == dk3sf_sscanf3(ptr, dkT("%d"), &mx)) {
    if(mx >= 0) {
      job->clmax = mx;
      back = 1;
    } else {					

#line 648 "dknet.ctr"
      /* ERROR: Negative number! */
      dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 8);
    }
  } else {					

#line 652 "dknet.ctr"
    if(0 == dk3str_cmp(dknet_noloc[5], ptr)) {
      job->clmax = 0;
      back = 1;
    } else {					

#line 656 "dknet.ctr"
      /* ERROR: Not a number! */
      dk3app_log_3(job->app, DK3_LL_ERROR, job->msg, 1, 2, ptr);
    }
  } 

#line 660 "dknet.ctr"
  return back;
}



/**	Save an allowed client.
	@param	job	Job structure.
	@param	ptr	Text containing address/mask.
	@return	1 on success, 0 on error.
*/
static
int
dknet_save_allowed_client(dknet_job *job, dkChar const *ptr)
{
  dk3_peer_allowed_t	 allowed_client;
  dk3_peer_allowed_t	*np;
  int		 	 back = 0;
  

#line 678 "dknet.ctr"
  if(!(job->sacl)) {
    job->sacl = dk3sto_open_app(job->app);
    if(job->sacl) {
      dk3sto_set_comp(job->sacl, dk3socket_compare_peer, 0);
    }
  }
  if(!(job->iacl)) {
    if(job->sacl) {
      job->iacl = dk3sto_it_open(job->sacl);
    }
  }
  if((job->sacl) && (job->iacl)) {
    if(dk3socket_dkchar_set_peer(&allowed_client, ptr, NULL, job->app)) {
      np = dk3_new_app(dk3_peer_allowed_t,1,job->app);
      if(np) {
        dk3mem_cpy(
	  (void *)np, (void *)(&allowed_client), sizeof(dk3_peer_allowed_t)
	);
        if(dk3sto_add(job->sacl, (void *)np)) {
	  back = 1;
	} else {				

#line 699 "dknet.ctr"
	  dk3_delete(np)
	  job->exval = DKNET_EXIT_ERROR_MEMORY;
	  dk3app_log_i1(job->app, DK3_LL_ERROR, 9);
	}
      } else {					

#line 704 "dknet.ctr"
        job->exval = DKNET_EXIT_ERROR_MEMORY;
	dk3app_log_i1(job->app, DK3_LL_ERROR, 9);
      }
    } else {					

#line 708 "dknet.ctr"
      job->exval = DKNET_EXIT_ERROR_OPTIONS;
    }
  } else {					

#line 711 "dknet.ctr"
    /* ERROR: Memory! */
    dk3app_log_i1(job->app, DK3_LL_ERROR, 9);
    job->exval = DKNET_EXIT_ERROR_MEMORY;
  } 

#line 715 "dknet.ctr"
  return back;
}




/**	Process command line arguments.
	As -r takes two arguments and -a can occur multiple
	times we have to do this manually.
	@param	job	Job structure.
	@return	1 on success, 0 on error.
*/
static
int
dknet_process_command_line_arguments(dknet_job *job)
{
  dkChar const * const	*xargv;		/* Command line arguments array. */
  dkChar const * const	*lfdptr;	/* Current command line argument. */
  dkChar const		*ptr;		/* Current command line argument. */
  dkChar const		*p1;		/* First argument to -r . */
  dkChar const		*p2;		/* Second argument to -r . */
  unsigned long		 ul;		/* Temporary scan result. */
  int			 xargc;		/* Number of command line arguments. */
  int			 i;		/* Current cmd line argument index. */
  int			 act;		/* Action to take. */
  int			 cmdhvl;	/* Help, version, license. */
  int			 cmdrun;	/* Send, receive. */
  int			 back	= 1;
  

#line 744 "dknet.ctr"
  job->exval = DKNET_EXIT_ERROR_OPTIONS;
  cmdhvl = DKNET_CMD_HELP | DKNET_CMD_VERSION | DKNET_CMD_LICENSE;
  cmdrun = DKNET_CMD_SEND | DKNET_CMD_RECEIVE;
  xargc = dk3app_get_argc(job->app);
  xargv = dk3app_get_argv(job->app);
  lfdptr = xargv; lfdptr++; i = 1;
  while(i < xargc) {
    act = 0;
    ptr = *lfdptr;			

#line 753 "dknet.ctr"
    if(dkT('-') == *ptr) {		

#line 754 "dknet.ctr"
      ptr++;
      switch(*ptr) {
        case dkT('-'): {		

#line 757 "dknet.ctr"
	  ptr++;
	  act = dk3str_array_abbr(dknet_long_options, ptr, dkT('$'), 0);
	  if(-1 < act) {
	    act += 1;
	    if(6 == act) act = 1;
	  } else {
	    back = 0;
	    /* ERROR: Unknown option! */
	    job->exval = DKNET_EXIT_ERROR_OPTIONS;
	    ptr--; ptr--;
	    dk3app_log_3(job->app, DK3_LL_ERROR, job->msg, 9, 10, ptr);
	  }
	  ptr = NULL;
	} break;
	case dkT('r'): {		

#line 772 "dknet.ctr"
	  act = 1;
	  ptr++; if(!(*ptr)) ptr = NULL;
	} break;
	case dkT('s'): {		

#line 776 "dknet.ctr"
	  act = 2;
	  ptr++; if(!(*ptr)) ptr = NULL;
	} break;
	case dkT('h'): {		

#line 780 "dknet.ctr"
	  act = 3;
	} break;
	case dkT('v'): {		

#line 783 "dknet.ctr"
	  act = 4;
	} break;
	case dkT('l'): {		

#line 786 "dknet.ctr"
	  act = 5;
	} break;
	case dkT('n'): {		

#line 789 "dknet.ctr"
	  act = 7;
	  ptr++; if(!(*ptr)) ptr = NULL;
	} break;
	case dkT('a'): {		

#line 793 "dknet.ctr"
	  act = 8;
	  ptr++; if(!(*ptr)) ptr = NULL;
	} break;
	case dkT('t'): {		

#line 797 "dknet.ctr"
	  act = 9;
	} break;
	case dkT('f'): {
	  act = 10;
	  ptr++; if(!(*ptr)) ptr = NULL;
	} break;
	default: {			

#line 804 "dknet.ctr"
	  back = 0;
	  /* ERROR: Unknown option! */
	  job->exval = DKNET_EXIT_ERROR_OPTIONS;
	  ptr--;
	  dk3app_log_3(job->app, DK3_LL_ERROR, job->msg, 9, 10, ptr);
	} break;
      }
    } else {			

#line 812 "dknet.ctr"
      if(!dknet_save_filename(job, ptr)) { back = 0; }
    }
    switch(act) {
      case 1: {	/* receive */
        if(0 != job->cmd) {
	  /* ERROR: Incompatible actions! */
	  dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 11);
	  back = 0;
	  job->exval = DKNET_EXIT_ERROR_OPTIONS;
	}
        p1 = NULL;
	p2 = NULL;
        job->cmd |= DKNET_CMD_RECEIVE;
	if(!(ptr)) {
	  i++; lfdptr++;
	  if(i < xargc) {
	    ptr = *lfdptr;
	  }
	}
	if(ptr) {
	  p1 = ptr;
	  i++; lfdptr++;
	  if(i < xargc) {
	    p2 = *lfdptr;
	    if(!dknet_save_host_and_port(job, p1, p2)) back = 0;
	  } else {			

#line 838 "dknet.ctr"
	    back = 0;
	    /* ERROR: Two arguments required */
	    dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 12);
	    job->exval = DKNET_EXIT_ERROR_OPTIONS;
	  }
	} else {			

#line 844 "dknet.ctr"
	  back = 0;
	  /* ERROR: Argument expected! */
	  job->exval = DKNET_EXIT_ERROR_OPTIONS;
	  dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 12);
	}
      } break;
      case 2: {	/* send */
        if(0 != job->cmd) {
	  /* ERROR: Incompatible action! */
	  dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 11);
	  back = 0;
	  job->exval = DKNET_EXIT_ERROR_OPTIONS;
	}
        job->cmd |= DKNET_CMD_SEND;
	if(!(ptr)) {
	  i++; lfdptr++;
	  if(i < xargc) {
	    ptr = *lfdptr;
	  }
	}
	if(ptr) {
	  if(!dknet_save_portnumber(job, ptr)) { back = 0; }
	} else {
	  back = 0;
	  /* ERROR: Argument expected! */
	  job->exval = DKNET_EXIT_ERROR_OPTIONS;
	  dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 13);
	}
      } break;
      case 3: {	/* help */
        job->cmd |= DKNET_CMD_HELP;
      } break;
      case 4: {	/* version */
        job->cmd |= DKNET_CMD_VERSION;
      } break;
      case 5: {	/* license */
        job->cmd |= DKNET_CMD_LICENSE;
      } break;
      case 7: {				

#line 883 "dknet.ctr"
	if(!(ptr)) {
	  i++; lfdptr++;
	  if(i < xargc) {
	    ptr = *lfdptr;
	  }
	}
	if(ptr) {
	  if(!dknet_save_max_clients(job, ptr)) back = 0;
	} else {
	  /* ERROR: Argument expected! */
	  job->exval = DKNET_EXIT_ERROR_OPTIONS;
	  dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 14);
	  back = 0;
	}
      } break;
      case 8: {				

#line 899 "dknet.ctr"
	if(!(ptr)) {
	  i++; lfdptr++;
	  if(i < xargc) {
	    ptr = *lfdptr;
	  }
	}
	if(ptr) {
	  if(!dknet_save_allowed_client(job, ptr)) back = 0;
	} else {
	  /* ERROR: Argument expected! */
	  job->exval = DKNET_EXIT_ERROR_OPTIONS;
	  dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 15);
	  back = 0;
	}
      } break;
      case 9: {				

#line 915 "dknet.ctr"
	job->stt = 1;
      } break;
      case 10: {
	if(!(ptr)) {
	  i++; lfdptr++;
	  if(i < xargc) {
	    ptr = *lfdptr;
	  }
	}
	if(ptr) {
	  ul = 0UL;
	  if(dk3sf_sscanf3(ptr,dkT("%lu"),&ul)) {
	    job->flush = ul;
	  } else {
	    /* ERROR: Not a number. */
	    back = 0;
	    dk3app_log_i3(job->app, DK3_LL_ERROR, 141, 142, ptr);
	  }
	} else {
	  job->exval = DKNET_EXIT_ERROR_OPTIONS;
	  dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 15);
	  back = 0;
	}
      } break;
    }
    i++; lfdptr++;			

#line 941 "dknet.ctr"
  }
  if(back) {
    if((job->cmd & cmdhvl) && (job->cmd & cmdrun)) {	

#line 944 "dknet.ctr"
      back = 0;
      /* ERROR: Send/receive can not be combined with help, version */
      dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 16);
    } else {
      if(cmdrun == (job->cmd & cmdrun)) {		

#line 949 "dknet.ctr"
        back = 0;
	/* ERROR: Either send or receive is allowed, not both! */
	dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 17);
      }
    }
  }
  if(0 == job->cmd) {					

#line 956 "dknet.ctr"
    back = 0;
    /* ERROR: No action was choosen! */
    job->exval = DKNET_EXIT_ERROR_OPTIONS;
    dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 18);
  } else {
    job->exval = DKNET_EXIT_ERROR_ANY;
  } 

#line 963 "dknet.ctr"
  return back;
}



/**	Accept connection requests from clients.
	@param	job	Job structure.
	@return	1 on success, 0 on error.
*/
static
int
dknet_accept_clients(dknet_job *job)
{
  dk3_socket_set_t	*lso;		/* Listener sockets. */
  dknet_session		*sp;		/* Session pointer. */
  dk3_socket_t		 newsock;	/* New socket. */
  int			 mustContinue;	/* Flag: Must continue listening. */
  int			 back = 0;
  char			 c;
  

#line 983 "dknet.ctr"
  if(job->llerr < DK3_LL_PROGRESS) {
    dk3app_set_stderr_log_level(job->app, DK3_LL_PROGRESS);
  }
  /* PROGRESS: Creating listener socket set. */
  dk3app_log_1(job->app, DK3_LL_PROGRESS, job->msg, 20);
  lso = dk3socket_listeners(job->nport, job->blog, 0, NULL, job->app);
  /* PROGRESS: Finished creating listener socket set. */
  dk3app_log_1(job->app, DK3_LL_PROGRESS, job->msg, 21);
  if(lso) {
    back = 1;
    /* PROGRESS: Waiting for clients to connect. */
    dk3app_log_1(job->app, DK3_LL_PROGRESS, job->msg, 22);
    do {
      mustContinue = 0;
      c = 0x00;
      newsock = dk3socket_set_accept(
        lso, NULL, NULL, job->iacl, 1, 0L, 0L, NULL, job->app
      );
      if(INVALID_SOCKET != newsock) {		

#line 1002 "dknet.ctr"
        mustContinue = 1;
        if(1 == dk3socket_recv(newsock,(void *)(&c),1,5L,0L,NULL,job->app)) {
	  job->clcur += 1;			

#line 1005 "dknet.ctr"
	  sp = dk3_new_app(dknet_session,1,job->app);
	  if(sp) {				

#line 1007 "dknet.ctr"
	    sp->ss = newsock; sp->ec = 0;
	    if(dk3sto_add(job->ssess, (void *)sp)) {	

#line 1009 "dknet.ctr"
	      if(job->clmax > 0) {		

#line 1010 "dknet.ctr"
	        if(job->clcur >= job->clmax) {
		  mustContinue = 0;
		}
	      }
	      if(0x01 == c) {			

#line 1015 "dknet.ctr"
	        mustContinue = 0;
	      }
	    } else {				

#line 1018 "dknet.ctr"
	      dk3socket_close(newsock, NULL, NULL);
	      sp->ss = 0; sp->ec = 0;
	      dk3_delete(sp)
	      back = 0;
	      mustContinue = 0;
	      job->exval = DKNET_EXIT_ERROR_MEMORY;
	    }
	  } else {				

#line 1026 "dknet.ctr"
	    dk3socket_close(newsock, NULL, NULL);
	    back = 0;
	    mustContinue = 0;
	    job->exval = DKNET_EXIT_ERROR_MEMORY;
	  }
	} else {				

#line 1032 "dknet.ctr"
	  dk3socket_close(newsock, NULL, NULL);
	  /* ERROR: Failed to read initial byte from client! */
	  dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 29);
	}
      } else {					

#line 1037 "dknet.ctr"
        back = 0;
      }
    } while((mustContinue) && (back));
    /* PROGRESS: Finished waiting for clients to connect, closing set */
    dk3app_log_1(job->app, DK3_LL_PROGRESS, job->msg, 23);
    dk3socket_set_close(lso, NULL, job->app);
    if(0 == job->clcur) {
      back = 0;
    }
    /* PROGRESS: Listener set closed. */
    dk3app_log_1(job->app, DK3_LL_PROGRESS, job->msg, 24);
  }
  dk3app_set_stderr_log_level(job->app, job->llerr);
  

#line 1051 "dknet.ctr"
  return back;
}



/**	Do data transfer (send file).
	@param	job	Job structure.
*/
static
void
dknet_transfer_data(dknet_job *job)
{
  dkChar	 sobu[64];	/* Buffer for socket number. */
  char		 buffer[1460];	/* Buffer to read data from file. */
  dknet_session	*sp;		/* Current session. */
  size_t	 rb;		/* Bytes read from file. */
  int		 wb;
  if(job->llerr < DK3_LL_PROGRESS) {
    dk3app_set_stderr_log_level(job->app, DK3_LL_PROGRESS);
  }
  /* PROGRESS: Sending data. */
  dk3app_log_1(job->app, DK3_LL_PROGRESS, job->msg, 25);
  job->exval = DKNET_EXIT_OK;
  do {
    if((job->rfn) && (job->fipo)) {
      rb = dk3sf_fread_app((void *)buffer,1,sizeof(buffer),job->fipo,job->app);
    } else {
      rb = dk3sf_read_app(0, (void *)buffer, sizeof(buffer), job->app);
    }
    if(rb > 0) {
      dk3sto_it_reset(job->isess);
      while(NULL != (sp = (dknet_session *)dk3sto_it_next(job->isess))) {
        if(!(sp->ec)) {
	  wb = dk3socket_send(sp->ss,(void *)buffer,rb,0L,0L,NULL,job->app);
	  if((size_t)wb != rb) {
	    sp->ec = 1;
	    job->exval = DKNET_EXIT_ERROR_NETWORK;
	    /* ERROR While sending data over network! */
	    if(job->app) {
	      dk3sf_sprintf3(sobu,dkT("%d"),((int)(sp->ss)));
	      dk3app_log_3(job->app, DK3_LL_ERROR, job->msg, 30, 31, sobu);
	    }
	  }
	}
      }
    }
  } while(rb > 0);
  /* PROGRESS: Finished sending data. */
  dk3app_log_1(job->app, DK3_LL_PROGRESS, job->msg, 26);
  dk3app_set_stderr_log_level(job->app, job->llerr);
}



/**	Run sender with opened file (either stdin or specified file).
	@param	job	Job structure.
*/
static
void
dknet_run_sender_with_file(dknet_job *job)
{
  dknet_session	*sp;
  job->exval = DKNET_EXIT_ERROR_MEMORY;
  job->ssess = dk3sto_open_app(job->app);
  if(job->ssess) {
    job->isess = dk3sto_it_open(job->ssess);
    if(job->isess) {
      /*
      	Accept clients and transfer data.
      */
      job->exval = DKNET_EXIT_ERROR_NETWORK;
      if(dknet_accept_clients(job)) {
        dknet_transfer_data(job);
      }
      /*
      	Clean up.
      */
      dk3sto_it_reset(job->isess);
      while(NULL != (sp = (dknet_session *)dk3sto_it_next(job->isess))) {
        if(INVALID_SOCKET != sp->ss) {
	  dk3socket_eat_input(sp->ss, job->app);
	  dk3socket_close(sp->ss, NULL, job->app);
	  sp->ss = INVALID_SOCKET;
	}
	sp->ec = 0;
        dk3_delete(sp)
      }
      dk3sto_it_close(job->isess);
    }
    dk3sto_close(job->ssess);
  } job->ssess = NULL; job->isess = NULL;
}



/**	Listen for incoming connection requests, send data.
	@param	job	Job structure.
*/
static
void
dknet_real_sender(dknet_job *job)
{
#if DK3_ON_WINDOWS
  int oldmode = 0;
#endif
  

#line 1157 "dknet.ctr"
#if DK3_ON_WINDOWS
  if(!(job->rfn)) {
    oldmode = _setmode(0, _O_BINARY);
  }
#endif
  if(job->rfn) {
    job->fipo = dk3sf_fopen_app(job->rfn, dk3app_not_localized(36), job->app);
    if(job->fipo) {
      dknet_run_sender_with_file(job);
      fclose(job->fipo); job->fipo = NULL;
    } else {
      /* ERROR: Failed to open input file! */
      job->exval = DKNET_EXIT_ERROR_IO;
    }
  } else {
    dknet_run_sender_with_file(job);
  }
#if DK3_ON_WINDOWS
  if(!(job->rfn)) {
    _setmode(0, oldmode);
  }
#endif
  

#line 1180 "dknet.ctr"
}



/**	Connect to server, receive data and write to output or file.
	@param	job	Job structure.
*/
static
void
dknet_real_receiver(dknet_job *job)
{
  char			 bu[1460];		/* Buffer. */
  FILE			*fipo = NULL;		/* Output file. */
  dk3_socket_t		 sock;			/* Network socket. */
  unsigned long		 flushcount = 0UL;	/* Blocks found. */
#if DK3_ON_WINDOWS
  int			 oldmode = 0;		/* Old stdout mode. */
#endif
  int			 firstpass = 1;		/* Flag: First pass in loop. */
  int			 res;			/* Network read result. */
  int			 mustflush;		/* Flag: Must flush. */
  char			 chr;			/* Character to send. */
  

#line 1203 "dknet.ctr"
#if DK3_ON_WINDOWS
  if(!(job->rfn)) {
    oldmode = _setmode(_fileno(stdout), _O_BINARY);
  }
#endif
  chr = 0x00;
  if(job->stt) { chr = 0x01; }
  job->exval = DKNET_EXIT_ERROR_NETWORK;
  sock = dk3socket_dkchar_open_net_stream_client(
    job->hn, job->nport, 0, 0L, 0L, NULL, job->app
  );
  if(INVALID_SOCKET != sock) {			

#line 1215 "dknet.ctr"
    res = dk3socket_send(sock, (void *)(&chr), 1, 0L, 0L, NULL, job->app);
    if(1 == res) {				

#line 1217 "dknet.ctr"
      res = dk3socket_shutdown(sock,DK3_TCPIP_SHUTDOWN_WRITE,NULL,job->app);
      if(res) {					

#line 1219 "dknet.ctr"
        job->exval = DKNET_EXIT_OK;
        if(job->llerr < DK3_LL_PROGRESS) {
          dk3app_set_stderr_log_level(job->app, DK3_LL_PROGRESS);
        }
	/* PROGRESS: Start of transmission. */
	dk3app_log_1(job->app, DK3_LL_PROGRESS, job->msg, 27);
	flushcount = 0UL;
        do {
	  mustflush = 0;
          res = dk3socket_recv(sock, bu, sizeof(bu), 0L, 0L, NULL, job->app);
          if(res > 0) {				

#line 1230 "dknet.ctr"
	    if(job->flush) {
	      flushcount++;
	      if(flushcount >= job->flush) {
	        mustflush = 1;
		flushcount = 0;
	      }
	    }
            if(firstpass) {
              firstpass = 0;
              if(job->rfn) {
                fipo = dk3sf_fopen_app(
      	          job->rfn, dk3app_not_localized(53), job->app
      	        );
      	        if(!(fipo)) {
      	          /* ERROR: Failed to open output file! */
      	          job->exval = DKNET_EXIT_ERROR_IO;
      	        }
              }
            }
            if(job->rfn) {
              if(fipo) {
                if(dk3sf_fwrite_app(bu, 1, res, fipo, job->app)) {
		  if(mustflush) {
		    fflush(fipo);
		  }
		} else {
      	          /* ERROR: Failed to write data. */
      	          job->exval = DKNET_EXIT_ERROR_IO;
      	        }
              }
            } else {
              if(dk3sf_fwrite_app(bu, 1, res, stdout, job->app)) {
	        if(mustflush) {
		  fflush(stdout);
		}
	      } else {
                /* ERROR: Not all bytes written successfully. */
                job->exval = DKNET_EXIT_ERROR_IO;
              }
            }
          } else {				

#line 1271 "dknet.ctr"
          }
        } while(res > 0);
	if(job->rfn) {
	  if(job->fipo) {
	    if(!(mustflush)) {
	      fflush(job->fipo);
	    }
	  }
	} else {
	  if(!(mustflush)) {
	    fflush(stdout);
	  }
	}
	if(DKNET_EXIT_OK == job->exval) {
	  /* PROGRESS: End of transmission. */
	  dk3app_log_1(job->app, DK3_LL_PROGRESS, job->msg, 28);
	}
        dk3app_set_stderr_log_level(job->app, job->llerr);
        if(job->rfn) {
          if(fipo) {
            if(!dk3sf_fclose_fn_app(fipo, job->rfn, job->app)) {
              job->exval = DKNET_EXIT_ERROR_IO;
            }
          }
        }
      } else {			

#line 1297 "dknet.ctr"
        /* ERROR: Socket write shutdown failed! */
	job->exval = DKNET_EXIT_ERROR_NETWORK;
      }
    } else {			

#line 1301 "dknet.ctr"
      /* ERROR Failed to send initial byte! */
      job->exval = DKNET_EXIT_ERROR_NETWORK;
    }
  } else {			

#line 1305 "dknet.ctr"
    /* ERROR: Failed to open socket! */
    job->exval = DKNET_EXIT_ERROR_NETWORK;
  }
#if DK3_ON_WINDOWS
  if(!(job->rfn)) {
    _setmode(_fileno(stdout), oldmode);
  }
#endif
  

#line 1314 "dknet.ctr"
}



/**	Process one file name.
	@param	job	Job structure.
	@param	fsend	Flag: Send this file.
*/
static
void
dknet_process_filename(dknet_job *job, int fsend)
{
  dkChar		 bu[DK3_MAX_PATH];
  dk3_dir_t		*pdir = NULL;
  

#line 1329 "dknet.ctr"
  job->exval = DKNET_EXIT_ERROR_OPTIONS;
  if(dk3str_len(job->fn) < DK3_SIZEOF(bu,dkChar)) {
    dk3str_cpy(bu, job->fn);
    dk3str_correct_filename(bu);
    if(dk3sf_must_expand(bu)) {		

#line 1334 "dknet.ctr"
      pdir = dk3dir_fne_open_app(bu, job->app);
      if(pdir) {			

#line 1336 "dknet.ctr"
        if(dk3dir_get_number_of_files(pdir) > 0) {
	  if(1 == dk3dir_get_number_of_files(pdir)) {
	    if(dk3dir_get_next_file(pdir)) {
	      job->rfn = dk3dir_get_fullname(pdir);
	      if(job->rfn) {		

#line 1341 "dknet.ctr"
	        if(fsend) {
		  dknet_real_sender(job);
		} else {
		  dknet_real_receiver(job);
		}
	      } else {			

#line 1347 "dknet.ctr"
	        /* ERROR: Bug, must not happen! */
	      }
	    } else {			

#line 1350 "dknet.ctr"
	      /* ERROR: Bug, must not happen! */
	    }
	  } else {			

#line 1353 "dknet.ctr"
	    dk3app_log_i3(job->app, DK3_LL_ERROR, 168, 169, bu);
	    job->exval = DKNET_EXIT_ERROR_OPTIONS;
	  }
	} else {			

#line 1357 "dknet.ctr"
	  dk3app_log_i3(job->app, DK3_LL_ERROR, 215, 216, bu);
	  job->exval = DKNET_EXIT_ERROR_OPTIONS;
	}
        dk3dir_close(pdir);
      } else {				

#line 1362 "dknet.ctr"
        job->exval = DKNET_EXIT_ERROR_MEMORY;
      }
    } else {				

#line 1365 "dknet.ctr"
      job->rfn = bu;
      if(fsend) {
        dknet_real_sender(job);
      } else {
        dknet_real_receiver(job);
      }
    }
  } else {				

#line 1373 "dknet.ctr"
  } 

#line 1374 "dknet.ctr"
}



/**	Listen for incoming connection requests, send data.
	@param	job	Job structure.
*/
static
void
dknet_sender(dknet_job *job)
{
  if(job->fn) {
    dknet_process_filename(job, 1);
  } else {
    dknet_real_sender(job);
  }
}



/**	Connect to server, receive data and write to output or file.
	@param	job	Job structure.
*/
static
void
dknet_receiver(dknet_job *job)
{
  if(job->fn) {
    dknet_process_filename(job, 0);
  } else {
    dknet_real_receiver(job);
  }
}



/**	Continue after initializing application and localized texts.
	@param	job	Job structure.
*/
static
void
dknet_run_with_app_and_messages(dknet_job *job)
{
  dkChar const * const	*ptr;
  

#line 1419 "dknet.ctr"
  if(dknet_process_command_line_arguments(job)) {
    if((job->cmd) & (DKNET_CMD_HELP | DKNET_CMD_VERSION | DKNET_CMD_LICENSE)) {
      if((job->cmd) & DKNET_CMD_VERSION) {
        dk3sf_initialize_stdout();
	dk3sf_fputs(dknet_noloc[3], stdout);
	dk3sf_fputs(dknet_noloc[4], stdout);
	dk3sf_fputs(dknet_version, stdout);
	dk3sf_fputc(dkT('\n'), stdout);
      }
      if((job->cmd) & DKNET_CMD_LICENSE) {
        dk3sf_initialize_stdout();
	ptr = dknet_license_text;
	while(*ptr) {
	  dk3sf_fputs(*(ptr++), stdout);
	  dk3sf_fputc(dkT('\n'), stdout);
	}
      }
      if((job->cmd) & DKNET_CMD_HELP) {
        dk3app_help(job->app, dknet_noloc[2], dknet_help_text);
      }
      job->exval = DKNET_EXIT_OK;
    } else {
      if(DKNET_CMD_SEND == job->cmd) {
        dknet_sender(job);
      } else {
        if(DKNET_CMD_RECEIVE == job->cmd) {
	  dknet_receiver(job);
	} else {
	  /* ERROR: Neither sender nor receiver! */
	  dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 18);
	}
      }
    }
  } else {
    /* Show help text */
    dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 19);
  }
  dknet_job_cleanup_command_line_processing(job);
  

#line 1458 "dknet.ctr"
}



/**	Entry point of the program.
	@param	argc	Number of command line arguments.
	@param	argv	Command line arguments array.
	@return	0 on success, any other value indicates an error.
*/
DK3_MAIN
{
  dknet_job		 job;
  int			 exval = 0;	/* Exit code. */
  

#line 1472 "dknet.ctr"
  

#line 1473 "dknet.ctr"
  dknet_job_init(&job);
  job.app = dk3app_open_command(
    argc, (dkChar const * const *)argv, dknet_noloc[0]
  );
  if(job.app) {
    job.llerr = dk3app_get_stderr_log_level(job.app);
    job.msg = dk3app_messages(
      job.app, dknet_noloc[1], (dkChar const **)dknet_loc
    );
    if(job.msg) {
      if(dk3socket_up(NULL, job.app)) {
        dknet_run_with_app_and_messages(&job);
	dk3socket_down(NULL, job.app);
      } else {
        /* ERROR: Failed to initialize WinSock! */
	job.exval = DKNET_EXIT_ERROR_WINSOCK;
      }
    } else {			

#line 1491 "dknet.ctr"
    }
    dk3app_close(job.app); job.app = NULL;
  } else {
    /* ERROR: Memory */
    fputs("dknet: ERROR: Not enough memory!\n", stderr);
    fflush(stderr);
    job.exval =  DKNET_EXIT_ERROR_MEMORY;
  }
  dknet_job_cleanup(&job);
  exval = job.exval;
  

#line 1502 "dknet.ctr"
  

#line 1503 "dknet.ctr"
  exit(exval); return exval;
}


#else
/* DK3_HAVE_SELECT || DK3_ON_WINDOWS */

/**	Entry point of the program.
	@param	argc	Number of command line arguments.
	@param	argv	Command line arguments array.
	@return	0 on success, any other value indicates an error.
*/
DK3_MAIN
{
  fputs("dknet: ERROR: No select() function available!\n", stderr);
  fflush(stderr);
}

#endif
/* DK3_HAVE_SELECT */

