/*
  File autogenerated by gengetopt version 2.23
  generated with the following command:
  gengetopt --unamed-opts=HOST [PORT] --no-handle-version --no-handle-help --input gsasl.ggo --file-name gsasl_cmd 

  The developers of gengetopt consider the fixed text that goes in all
  gengetopt output files to be in the public domain:
  we make no copyright claims on it.
*/

/* If we use autoconf.  */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifndef FIX_UNUSED
#define FIX_UNUSED(X) (void) (X) /* avoid warnings for unused params */
#endif

#include <getopt.h>

#include "gsasl_cmd.h"

const char *gengetopt_args_info_purpose = "Authenticate user to a server using Simple Authentication and\nSecurity Layer.  Currently IMAP and SMTP servers are supported.  This\nis a command line interface for the GNU SASL library.";

const char *gengetopt_args_info_usage = "Usage: " CMDLINE_PARSER_PACKAGE " [OPTION]... [HOST [PORT]]...";

const char *gengetopt_args_info_versiontext = "";

const char *gengetopt_args_info_description = "";

const char *gengetopt_args_info_help[] = {
  "  -h, --help                    Print help and exit",
  "  -V, --version                 Print version and exit",
  "\nCommands:",
  "  -c, --client                  Act as client.  (default=on)",
  "  -s, --server                  Act as server.  (default=off)",
  "      --client-mechanisms       Write name of supported client mechanisms\n                                  separated by space to stdout.  (default=off)",
  "      --server-mechanisms       Write name of supported server mechanisms\n                                  separated by space to stdout.  (default=off)",
  "  -k, --mkpasswd                Derive password. Provide --mechanism as\n                                  SCRAM-SHA-1 or SCRAM-SHA-256.  The required\n                                  inputs are password (through --password or\n                                  read from terminal) and optional inputs are\n                                  iteration count (through --iteration-count,\n                                  or defaulting to 65536) and salt (through\n                                  --salt, or generated randomly).  The output\n                                  is a string of the form\n                                  \"{mech}count,salt,stored-key,server-key[,salted-password]\"\n                                  where \"mech\" is the mechanism, \"count\" is\n                                  the number of times password was hashed,\n                                  \"salt\" is the provided/generated\n                                  base64-encoded salt, \"stored-key\" and\n                                  \"server-key\" are the two derived and\n                                  base64-encoded server-side keys.  When\n                                  --verbose is provided, \"salted-password\"\n                                  will be included as the hex-encoded\n                                  PBKDF2-derived password.  (default=off)",
  "\nNetwork options:",
  "      --connect=HOST[:PORT]     Connect to TCP server and negotiate on stream\n                                  instead of stdin/stdout. PORT is the protocol\n                                  service, or an integer denoting the port, and\n                                  defaults to 143 (imap) if not specified. Also\n                                  sets the --hostname default.",
  "\nGeneric options:",
  "  -d, --application-data        After authentication, read data from stdin and\n                                  run it through the mechanism's security layer\n                                  and print it base64 encoded to stdout. The\n                                  default is to terminate after authentication.\n                                  (default=on)",
  "      --imap                    Use a IMAP-like logon procedure (client only).\n                                  Also sets the --service default to 'imap'.\n                                  (default=off)",
  "      --smtp                    Use a SMTP-like logon procedure (client only).\n                                  Also sets the --service default to 'smtp'.\n                                  (default=off)",
  "  -m, --mechanism=STRING        Mechanism to use.",
  "      --no-client-first         Disallow client to send data first (client\n                                  only).  (default=off)",
  "\nSASL mechanism options (they are prompted for when required):",
  "  -n, --anonymous-token=STRING  Token for anonymous authentication, usually\n                                  mail address (ANONYMOUS only).",
  "  -a, --authentication-id=STRING\n                                Identity of credential owner.",
  "  -z, --authorization-id=STRING Identity to request service for.",
  "  -p, --password=STRING         Password for authentication (insecure for\n                                  non-testing purposes).",
  "  -r, --realm=STRING            Realm. Defaults to hostname.",
  "      --passcode=NUMBER         Passcode for authentication (SECURID only).",
  "      --service=STRING          Set the requested service name (should be a\n                                  registered GSSAPI host based service name).",
  "      --hostname=STRING         Set the name of the server with the requested\n                                  service.",
  "      --service-name=STRING     Set the generic server name in case of a\n                                  replicated server (DIGEST-MD5 only).",
  "      --enable-cram-md5-validate\n                                Validate CRAM-MD5 challenge and response\n                                  interactively.  (default=off)",
  "      --disable-cleartext-validate\n                                Disable cleartext validate hook, forcing server\n                                  to prompt for password.  (default=off)",
  "      --quality-of-protection=TYPE\n                                How application payload will be protected.\n                                  'qop-auth' means no protection, 'qop-int'\n                                  means integrity protection, 'qop-conf' means\n                                  integrity and confidentialiy protection.\n                                  Currently only used by DIGEST-MD5, where the\n                                  default is 'qop-int'.",
  "      --iteration-count=NUMBER  Indicate PBKDF2 hash iteration count (SCRAM\n                                  only).  (default=`65536')",
  "      --salt=B64DATA            Indicate PBKDF2 salt as base64-encoded string\n                                  (SCRAM only).",
  "\nSTARTTLS options:",
  "      --starttls                Force use of STARTTLS.  The default is to use\n                                  STARTTLS when available.  (default=off)",
  "      --no-starttls             Unconditionally disable STARTTLS.\n                                  (default=off)",
  "      --no-cb                   Don't use channel bindings from TLS.\n                                  (default=off)",
  "      --x509-ca-file=FILE       File containing one or more X.509 Certificate\n                                  Authorities certificates in PEM format, used\n                                  to verify the certificate received from the\n                                  server.  If not specified, verification uses\n                                  system trust settings.  If FILE is the empty\n                                  string, don't fail on X.509 server\n                                  certificates verification errors.",
  "      --x509-cert-file=FILE     File containing client X.509 certificate in PEM\n                                  format.  Used together with --x509-key-file\n                                  to specify the certificate/key pair.",
  "      --x509-key-file=FILE      Private key for the client X.509 certificate in\n                                  PEM format.  Used together with\n                                  --x509-key-file to specify the\n                                  certificate/key pair.",
  "      --priority=STRING         Cipher priority string.",
  "\nOther options:",
  "      --verbose                 Produce verbose output.  (default=off)",
  "      --quiet                   Don't produce any diagnostic output.\n                                  (default=off)",
    0
};

typedef enum {ARG_NO
  , ARG_FLAG
  , ARG_STRING
  , ARG_INT
} cmdline_parser_arg_type;

static
void clear_given (struct gengetopt_args_info *args_info);
static
void clear_args (struct gengetopt_args_info *args_info);

static int
cmdline_parser_internal (int argc, char **argv, struct gengetopt_args_info *args_info,
                        struct cmdline_parser_params *params, const char *additional_error);


static char *
gengetopt_strdup (const char *s);

static
void clear_given (struct gengetopt_args_info *args_info)
{
  args_info->help_given = 0 ;
  args_info->version_given = 0 ;
  args_info->client_given = 0 ;
  args_info->server_given = 0 ;
  args_info->client_mechanisms_given = 0 ;
  args_info->server_mechanisms_given = 0 ;
  args_info->mkpasswd_given = 0 ;
  args_info->connect_given = 0 ;
  args_info->application_data_given = 0 ;
  args_info->imap_given = 0 ;
  args_info->smtp_given = 0 ;
  args_info->mechanism_given = 0 ;
  args_info->no_client_first_given = 0 ;
  args_info->anonymous_token_given = 0 ;
  args_info->authentication_id_given = 0 ;
  args_info->authorization_id_given = 0 ;
  args_info->password_given = 0 ;
  args_info->realm_given = 0 ;
  args_info->passcode_given = 0 ;
  args_info->service_given = 0 ;
  args_info->hostname_given = 0 ;
  args_info->service_name_given = 0 ;
  args_info->enable_cram_md5_validate_given = 0 ;
  args_info->disable_cleartext_validate_given = 0 ;
  args_info->quality_of_protection_given = 0 ;
  args_info->iteration_count_given = 0 ;
  args_info->salt_given = 0 ;
  args_info->starttls_given = 0 ;
  args_info->no_starttls_given = 0 ;
  args_info->no_cb_given = 0 ;
  args_info->x509_ca_file_given = 0 ;
  args_info->x509_cert_file_given = 0 ;
  args_info->x509_key_file_given = 0 ;
  args_info->priority_given = 0 ;
  args_info->verbose_given = 0 ;
  args_info->quiet_given = 0 ;
}

static
void clear_args (struct gengetopt_args_info *args_info)
{
  FIX_UNUSED (args_info);
  args_info->client_flag = 1;
  args_info->server_flag = 0;
  args_info->client_mechanisms_flag = 0;
  args_info->server_mechanisms_flag = 0;
  args_info->mkpasswd_flag = 0;
  args_info->connect_arg = NULL;
  args_info->connect_orig = NULL;
  args_info->application_data_flag = 1;
  args_info->imap_flag = 0;
  args_info->smtp_flag = 0;
  args_info->mechanism_arg = NULL;
  args_info->mechanism_orig = NULL;
  args_info->no_client_first_flag = 0;
  args_info->anonymous_token_arg = NULL;
  args_info->anonymous_token_orig = NULL;
  args_info->authentication_id_arg = NULL;
  args_info->authentication_id_orig = NULL;
  args_info->authorization_id_arg = NULL;
  args_info->authorization_id_orig = NULL;
  args_info->password_arg = NULL;
  args_info->password_orig = NULL;
  args_info->realm_arg = NULL;
  args_info->realm_orig = NULL;
  args_info->passcode_arg = NULL;
  args_info->passcode_orig = NULL;
  args_info->service_arg = NULL;
  args_info->service_orig = NULL;
  args_info->hostname_arg = NULL;
  args_info->hostname_orig = NULL;
  args_info->service_name_arg = NULL;
  args_info->service_name_orig = NULL;
  args_info->enable_cram_md5_validate_flag = 0;
  args_info->disable_cleartext_validate_flag = 0;
  args_info->quality_of_protection_arg = NULL;
  args_info->quality_of_protection_orig = NULL;
  args_info->iteration_count_arg = 65536;
  args_info->iteration_count_orig = NULL;
  args_info->salt_arg = NULL;
  args_info->salt_orig = NULL;
  args_info->starttls_flag = 0;
  args_info->no_starttls_flag = 0;
  args_info->no_cb_flag = 0;
  args_info->x509_ca_file_arg = NULL;
  args_info->x509_ca_file_orig = NULL;
  args_info->x509_cert_file_arg = NULL;
  args_info->x509_cert_file_orig = NULL;
  args_info->x509_key_file_arg = NULL;
  args_info->x509_key_file_orig = NULL;
  args_info->priority_arg = NULL;
  args_info->priority_orig = NULL;
  args_info->verbose_flag = 0;
  args_info->quiet_flag = 0;
  
}

static
void init_args_info(struct gengetopt_args_info *args_info)
{


  args_info->help_help = gengetopt_args_info_help[0] ;
  args_info->version_help = gengetopt_args_info_help[1] ;
  args_info->client_help = gengetopt_args_info_help[3] ;
  args_info->server_help = gengetopt_args_info_help[4] ;
  args_info->client_mechanisms_help = gengetopt_args_info_help[5] ;
  args_info->server_mechanisms_help = gengetopt_args_info_help[6] ;
  args_info->mkpasswd_help = gengetopt_args_info_help[7] ;
  args_info->connect_help = gengetopt_args_info_help[9] ;
  args_info->application_data_help = gengetopt_args_info_help[11] ;
  args_info->imap_help = gengetopt_args_info_help[12] ;
  args_info->smtp_help = gengetopt_args_info_help[13] ;
  args_info->mechanism_help = gengetopt_args_info_help[14] ;
  args_info->no_client_first_help = gengetopt_args_info_help[15] ;
  args_info->anonymous_token_help = gengetopt_args_info_help[17] ;
  args_info->authentication_id_help = gengetopt_args_info_help[18] ;
  args_info->authorization_id_help = gengetopt_args_info_help[19] ;
  args_info->password_help = gengetopt_args_info_help[20] ;
  args_info->realm_help = gengetopt_args_info_help[21] ;
  args_info->passcode_help = gengetopt_args_info_help[22] ;
  args_info->service_help = gengetopt_args_info_help[23] ;
  args_info->hostname_help = gengetopt_args_info_help[24] ;
  args_info->service_name_help = gengetopt_args_info_help[25] ;
  args_info->enable_cram_md5_validate_help = gengetopt_args_info_help[26] ;
  args_info->disable_cleartext_validate_help = gengetopt_args_info_help[27] ;
  args_info->quality_of_protection_help = gengetopt_args_info_help[28] ;
  args_info->iteration_count_help = gengetopt_args_info_help[29] ;
  args_info->salt_help = gengetopt_args_info_help[30] ;
  args_info->starttls_help = gengetopt_args_info_help[32] ;
  args_info->no_starttls_help = gengetopt_args_info_help[33] ;
  args_info->no_cb_help = gengetopt_args_info_help[34] ;
  args_info->x509_ca_file_help = gengetopt_args_info_help[35] ;
  args_info->x509_cert_file_help = gengetopt_args_info_help[36] ;
  args_info->x509_key_file_help = gengetopt_args_info_help[37] ;
  args_info->priority_help = gengetopt_args_info_help[38] ;
  args_info->verbose_help = gengetopt_args_info_help[40] ;
  args_info->quiet_help = gengetopt_args_info_help[41] ;
  
}

void
cmdline_parser_print_version (void)
{
  printf ("%s %s\n",
     (strlen(CMDLINE_PARSER_PACKAGE_NAME) ? CMDLINE_PARSER_PACKAGE_NAME : CMDLINE_PARSER_PACKAGE),
     CMDLINE_PARSER_VERSION);

  if (strlen(gengetopt_args_info_versiontext) > 0)
    printf("\n%s\n", gengetopt_args_info_versiontext);
}

static void print_help_common(void)
{
	size_t len_purpose = strlen(gengetopt_args_info_purpose);
	size_t len_usage = strlen(gengetopt_args_info_usage);

	if (len_usage > 0) {
		printf("%s\n", gengetopt_args_info_usage);
	}
	if (len_purpose > 0) {
		printf("%s\n", gengetopt_args_info_purpose);
	}

	if (len_usage || len_purpose) {
		printf("\n");
	}

	if (strlen(gengetopt_args_info_description) > 0) {
		printf("%s\n\n", gengetopt_args_info_description);
	}
}

void
cmdline_parser_print_help (void)
{
  int i = 0;
  print_help_common();
  while (gengetopt_args_info_help[i])
    printf("%s\n", gengetopt_args_info_help[i++]);
}

void
cmdline_parser_init (struct gengetopt_args_info *args_info)
{
  clear_given (args_info);
  clear_args (args_info);
  init_args_info (args_info);

  args_info->inputs = 0;
  args_info->inputs_num = 0;
}

void
cmdline_parser_params_init(struct cmdline_parser_params *params)
{
  if (params)
    { 
      params->override = 0;
      params->initialize = 1;
      params->check_required = 1;
      params->check_ambiguity = 0;
      params->print_errors = 1;
    }
}

struct cmdline_parser_params *
cmdline_parser_params_create(void)
{
  struct cmdline_parser_params *params = 
    (struct cmdline_parser_params *)malloc(sizeof(struct cmdline_parser_params));
  cmdline_parser_params_init(params);  
  return params;
}

static void
free_string_field (char **s)
{
  if (*s)
    {
      free (*s);
      *s = 0;
    }
}


static void
cmdline_parser_release (struct gengetopt_args_info *args_info)
{
  unsigned int i;
  free_string_field (&(args_info->connect_arg));
  free_string_field (&(args_info->connect_orig));
  free_string_field (&(args_info->mechanism_arg));
  free_string_field (&(args_info->mechanism_orig));
  free_string_field (&(args_info->anonymous_token_arg));
  free_string_field (&(args_info->anonymous_token_orig));
  free_string_field (&(args_info->authentication_id_arg));
  free_string_field (&(args_info->authentication_id_orig));
  free_string_field (&(args_info->authorization_id_arg));
  free_string_field (&(args_info->authorization_id_orig));
  free_string_field (&(args_info->password_arg));
  free_string_field (&(args_info->password_orig));
  free_string_field (&(args_info->realm_arg));
  free_string_field (&(args_info->realm_orig));
  free_string_field (&(args_info->passcode_arg));
  free_string_field (&(args_info->passcode_orig));
  free_string_field (&(args_info->service_arg));
  free_string_field (&(args_info->service_orig));
  free_string_field (&(args_info->hostname_arg));
  free_string_field (&(args_info->hostname_orig));
  free_string_field (&(args_info->service_name_arg));
  free_string_field (&(args_info->service_name_orig));
  free_string_field (&(args_info->quality_of_protection_arg));
  free_string_field (&(args_info->quality_of_protection_orig));
  free_string_field (&(args_info->iteration_count_orig));
  free_string_field (&(args_info->salt_arg));
  free_string_field (&(args_info->salt_orig));
  free_string_field (&(args_info->x509_ca_file_arg));
  free_string_field (&(args_info->x509_ca_file_orig));
  free_string_field (&(args_info->x509_cert_file_arg));
  free_string_field (&(args_info->x509_cert_file_orig));
  free_string_field (&(args_info->x509_key_file_arg));
  free_string_field (&(args_info->x509_key_file_orig));
  free_string_field (&(args_info->priority_arg));
  free_string_field (&(args_info->priority_orig));
  
  
  for (i = 0; i < args_info->inputs_num; ++i)
    free (args_info->inputs [i]);

  if (args_info->inputs_num)
    free (args_info->inputs);

  clear_given (args_info);
}


static void
write_into_file(FILE *outfile, const char *opt, const char *arg, const char *values[])
{
  FIX_UNUSED (values);
  if (arg) {
    fprintf(outfile, "%s=\"%s\"\n", opt, arg);
  } else {
    fprintf(outfile, "%s\n", opt);
  }
}


int
cmdline_parser_dump(FILE *outfile, struct gengetopt_args_info *args_info)
{
  int i = 0;

  if (!outfile)
    {
      fprintf (stderr, "%s: cannot dump options to stream\n", CMDLINE_PARSER_PACKAGE);
      return EXIT_FAILURE;
    }

  if (args_info->help_given)
    write_into_file(outfile, "help", 0, 0 );
  if (args_info->version_given)
    write_into_file(outfile, "version", 0, 0 );
  if (args_info->client_given)
    write_into_file(outfile, "client", 0, 0 );
  if (args_info->server_given)
    write_into_file(outfile, "server", 0, 0 );
  if (args_info->client_mechanisms_given)
    write_into_file(outfile, "client-mechanisms", 0, 0 );
  if (args_info->server_mechanisms_given)
    write_into_file(outfile, "server-mechanisms", 0, 0 );
  if (args_info->mkpasswd_given)
    write_into_file(outfile, "mkpasswd", 0, 0 );
  if (args_info->connect_given)
    write_into_file(outfile, "connect", args_info->connect_orig, 0);
  if (args_info->application_data_given)
    write_into_file(outfile, "application-data", 0, 0 );
  if (args_info->imap_given)
    write_into_file(outfile, "imap", 0, 0 );
  if (args_info->smtp_given)
    write_into_file(outfile, "smtp", 0, 0 );
  if (args_info->mechanism_given)
    write_into_file(outfile, "mechanism", args_info->mechanism_orig, 0);
  if (args_info->no_client_first_given)
    write_into_file(outfile, "no-client-first", 0, 0 );
  if (args_info->anonymous_token_given)
    write_into_file(outfile, "anonymous-token", args_info->anonymous_token_orig, 0);
  if (args_info->authentication_id_given)
    write_into_file(outfile, "authentication-id", args_info->authentication_id_orig, 0);
  if (args_info->authorization_id_given)
    write_into_file(outfile, "authorization-id", args_info->authorization_id_orig, 0);
  if (args_info->password_given)
    write_into_file(outfile, "password", args_info->password_orig, 0);
  if (args_info->realm_given)
    write_into_file(outfile, "realm", args_info->realm_orig, 0);
  if (args_info->passcode_given)
    write_into_file(outfile, "passcode", args_info->passcode_orig, 0);
  if (args_info->service_given)
    write_into_file(outfile, "service", args_info->service_orig, 0);
  if (args_info->hostname_given)
    write_into_file(outfile, "hostname", args_info->hostname_orig, 0);
  if (args_info->service_name_given)
    write_into_file(outfile, "service-name", args_info->service_name_orig, 0);
  if (args_info->enable_cram_md5_validate_given)
    write_into_file(outfile, "enable-cram-md5-validate", 0, 0 );
  if (args_info->disable_cleartext_validate_given)
    write_into_file(outfile, "disable-cleartext-validate", 0, 0 );
  if (args_info->quality_of_protection_given)
    write_into_file(outfile, "quality-of-protection", args_info->quality_of_protection_orig, 0);
  if (args_info->iteration_count_given)
    write_into_file(outfile, "iteration-count", args_info->iteration_count_orig, 0);
  if (args_info->salt_given)
    write_into_file(outfile, "salt", args_info->salt_orig, 0);
  if (args_info->starttls_given)
    write_into_file(outfile, "starttls", 0, 0 );
  if (args_info->no_starttls_given)
    write_into_file(outfile, "no-starttls", 0, 0 );
  if (args_info->no_cb_given)
    write_into_file(outfile, "no-cb", 0, 0 );
  if (args_info->x509_ca_file_given)
    write_into_file(outfile, "x509-ca-file", args_info->x509_ca_file_orig, 0);
  if (args_info->x509_cert_file_given)
    write_into_file(outfile, "x509-cert-file", args_info->x509_cert_file_orig, 0);
  if (args_info->x509_key_file_given)
    write_into_file(outfile, "x509-key-file", args_info->x509_key_file_orig, 0);
  if (args_info->priority_given)
    write_into_file(outfile, "priority", args_info->priority_orig, 0);
  if (args_info->verbose_given)
    write_into_file(outfile, "verbose", 0, 0 );
  if (args_info->quiet_given)
    write_into_file(outfile, "quiet", 0, 0 );
  

  i = EXIT_SUCCESS;
  return i;
}

int
cmdline_parser_file_save(const char *filename, struct gengetopt_args_info *args_info)
{
  FILE *outfile;
  int i = 0;

  outfile = fopen(filename, "w");

  if (!outfile)
    {
      fprintf (stderr, "%s: cannot open file for writing: %s\n", CMDLINE_PARSER_PACKAGE, filename);
      return EXIT_FAILURE;
    }

  i = cmdline_parser_dump(outfile, args_info);
  fclose (outfile);

  return i;
}

void
cmdline_parser_free (struct gengetopt_args_info *args_info)
{
  cmdline_parser_release (args_info);
}

/** @brief replacement of strdup, which is not standard */
char *
gengetopt_strdup (const char *s)
{
  char *result = 0;
  if (!s)
    return result;

  result = (char*)malloc(strlen(s) + 1);
  if (result == (char*)0)
    return (char*)0;
  strcpy(result, s);
  return result;
}

int
cmdline_parser (int argc, char **argv, struct gengetopt_args_info *args_info)
{
  return cmdline_parser2 (argc, argv, args_info, 0, 1, 1);
}

int
cmdline_parser_ext (int argc, char **argv, struct gengetopt_args_info *args_info,
                   struct cmdline_parser_params *params)
{
  int result;
  result = cmdline_parser_internal (argc, argv, args_info, params, 0);

  if (result == EXIT_FAILURE)
    {
      cmdline_parser_free (args_info);
      exit (EXIT_FAILURE);
    }
  
  return result;
}

int
cmdline_parser2 (int argc, char **argv, struct gengetopt_args_info *args_info, int override, int initialize, int check_required)
{
  int result;
  struct cmdline_parser_params params;
  
  params.override = override;
  params.initialize = initialize;
  params.check_required = check_required;
  params.check_ambiguity = 0;
  params.print_errors = 1;

  result = cmdline_parser_internal (argc, argv, args_info, &params, 0);

  if (result == EXIT_FAILURE)
    {
      cmdline_parser_free (args_info);
      exit (EXIT_FAILURE);
    }
  
  return result;
}

int
cmdline_parser_required (struct gengetopt_args_info *args_info, const char *prog_name)
{
  FIX_UNUSED (args_info);
  FIX_UNUSED (prog_name);
  return EXIT_SUCCESS;
}


static char *package_name = 0;

/**
 * @brief updates an option
 * @param field the generic pointer to the field to update
 * @param orig_field the pointer to the orig field
 * @param field_given the pointer to the number of occurrence of this option
 * @param prev_given the pointer to the number of occurrence already seen
 * @param value the argument for this option (if null no arg was specified)
 * @param possible_values the possible values for this option (if specified)
 * @param default_value the default value (in case the option only accepts fixed values)
 * @param arg_type the type of this option
 * @param check_ambiguity @see cmdline_parser_params.check_ambiguity
 * @param override @see cmdline_parser_params.override
 * @param no_free whether to free a possible previous value
 * @param multiple_option whether this is a multiple option
 * @param long_opt the corresponding long option
 * @param short_opt the corresponding short option (or '-' if none)
 * @param additional_error possible further error specification
 */
static
int update_arg(void *field, char **orig_field,
               unsigned int *field_given, unsigned int *prev_given, 
               char *value, const char *possible_values[],
               const char *default_value,
               cmdline_parser_arg_type arg_type,
               int check_ambiguity, int override,
               int no_free, int multiple_option,
               const char *long_opt, char short_opt,
               const char *additional_error)
{
  char *stop_char = 0;
  const char *val = value;
  int found;
  char **string_field;
  FIX_UNUSED (field);

  stop_char = 0;
  found = 0;

  if (!multiple_option && prev_given && (*prev_given || (check_ambiguity && *field_given)))
    {
      if (short_opt != '-')
        fprintf (stderr, "%s: `--%s' (`-%c') option given more than once%s\n", 
               package_name, long_opt, short_opt,
               (additional_error ? additional_error : ""));
      else
        fprintf (stderr, "%s: `--%s' option given more than once%s\n", 
               package_name, long_opt,
               (additional_error ? additional_error : ""));
      return 1; /* failure */
    }

  FIX_UNUSED (default_value);
    
  if (field_given && *field_given && ! override)
    return 0;
  if (prev_given)
    (*prev_given)++;
  if (field_given)
    (*field_given)++;
  if (possible_values)
    val = possible_values[found];

  switch(arg_type) {
  case ARG_FLAG:
    *((int *)field) = !*((int *)field);
    break;
  case ARG_INT:
    if (val) *((int *)field) = strtol (val, &stop_char, 0);
    break;
  case ARG_STRING:
    if (val) {
      string_field = (char **)field;
      if (!no_free && *string_field)
        free (*string_field); /* free previous string */
      *string_field = gengetopt_strdup (val);
    }
    break;
  default:
    break;
  };

  /* check numeric conversion */
  switch(arg_type) {
  case ARG_INT:
    if (val && !(stop_char && *stop_char == '\0')) {
      fprintf(stderr, "%s: invalid numeric value: %s\n", package_name, val);
      return 1; /* failure */
    }
    break;
  default:
    ;
  };

  /* store the original value */
  switch(arg_type) {
  case ARG_NO:
  case ARG_FLAG:
    break;
  default:
    if (value && orig_field) {
      if (no_free) {
        *orig_field = value;
      } else {
        if (*orig_field)
          free (*orig_field); /* free previous string */
        *orig_field = gengetopt_strdup (value);
      }
    }
  };

  return 0; /* OK */
}


int
cmdline_parser_internal (
  int argc, char **argv, struct gengetopt_args_info *args_info,
                        struct cmdline_parser_params *params, const char *additional_error)
{
  int c;	/* Character of the parsed option.  */

  int error_occurred = 0;
  struct gengetopt_args_info local_args_info;
  
  int override;
  int initialize;
  int check_required;
  int check_ambiguity;
  
  package_name = argv[0];
  
  /* TODO: Why is this here? It is not used anywhere. */
  override = params->override;
  FIX_UNUSED(override);

  initialize = params->initialize;
  check_required = params->check_required;

  /* TODO: Why is this here? It is not used anywhere. */
  check_ambiguity = params->check_ambiguity;
  FIX_UNUSED(check_ambiguity);

  if (initialize)
    cmdline_parser_init (args_info);

  cmdline_parser_init (&local_args_info);

  optarg = 0;
  optind = 0;
  opterr = params->print_errors;
  optopt = '?';

  while (1)
    {
      int option_index = 0;

      static struct option long_options[] = {
        { "help",	0, NULL, 'h' },
        { "version",	0, NULL, 'V' },
        { "client",	0, NULL, 'c' },
        { "server",	0, NULL, 's' },
        { "client-mechanisms",	0, NULL, 0 },
        { "server-mechanisms",	0, NULL, 0 },
        { "mkpasswd",	0, NULL, 'k' },
        { "connect",	1, NULL, 0 },
        { "application-data",	0, NULL, 'd' },
        { "imap",	0, NULL, 0 },
        { "smtp",	0, NULL, 0 },
        { "mechanism",	1, NULL, 'm' },
        { "no-client-first",	0, NULL, 0 },
        { "anonymous-token",	1, NULL, 'n' },
        { "authentication-id",	1, NULL, 'a' },
        { "authorization-id",	1, NULL, 'z' },
        { "password",	1, NULL, 'p' },
        { "realm",	1, NULL, 'r' },
        { "passcode",	1, NULL, 0 },
        { "service",	1, NULL, 0 },
        { "hostname",	1, NULL, 0 },
        { "service-name",	1, NULL, 0 },
        { "enable-cram-md5-validate",	0, NULL, 0 },
        { "disable-cleartext-validate",	0, NULL, 0 },
        { "quality-of-protection",	1, NULL, 0 },
        { "iteration-count",	1, NULL, 0 },
        { "salt",	1, NULL, 0 },
        { "starttls",	0, NULL, 0 },
        { "no-starttls",	0, NULL, 0 },
        { "no-cb",	0, NULL, 0 },
        { "x509-ca-file",	1, NULL, 0 },
        { "x509-cert-file",	1, NULL, 0 },
        { "x509-key-file",	1, NULL, 0 },
        { "priority",	1, NULL, 0 },
        { "verbose",	0, NULL, 0 },
        { "quiet",	0, NULL, 0 },
        { 0,  0, 0, 0 }
      };

      c = getopt_long (argc, argv, "hVcskdm:n:a:z:p:r:", long_options, &option_index);

      if (c == -1) break;	/* Exit from `while (1)' loop.  */

      switch (c)
        {
        case 'h':	/* Print help and exit.  */
        
        
          if (update_arg( 0 , 
               0 , &(args_info->help_given),
              &(local_args_info.help_given), optarg, 0, 0, ARG_NO,
              check_ambiguity, override, 0, 0,
              "help", 'h',
              additional_error))
            goto failure;
          cmdline_parser_free (&local_args_info);
          return 0;
        
          break;
        case 'V':	/* Print version and exit.  */
        
        
          if (update_arg( 0 , 
               0 , &(args_info->version_given),
              &(local_args_info.version_given), optarg, 0, 0, ARG_NO,
              check_ambiguity, override, 0, 0,
              "version", 'V',
              additional_error))
            goto failure;
          cmdline_parser_free (&local_args_info);
          return 0;
        
          break;
        case 'c':	/* Act as client..  */
        
        
          if (update_arg((void *)&(args_info->client_flag), 0, &(args_info->client_given),
              &(local_args_info.client_given), optarg, 0, 0, ARG_FLAG,
              check_ambiguity, override, 1, 0, "client", 'c',
              additional_error))
            goto failure;
        
          break;
        case 's':	/* Act as server..  */
        
        
          if (update_arg((void *)&(args_info->server_flag), 0, &(args_info->server_given),
              &(local_args_info.server_given), optarg, 0, 0, ARG_FLAG,
              check_ambiguity, override, 1, 0, "server", 's',
              additional_error))
            goto failure;
        
          break;
        case 'k':	/* Derive password. Provide --mechanism as SCRAM-SHA-1 or SCRAM-SHA-256.  The required inputs are password (through --password or read from terminal) and optional inputs are iteration count (through --iteration-count, or defaulting to 65536) and salt (through --salt, or generated randomly).  The output is a string of the form \"{mech}count,salt,stored-key,server-key[,salted-password]\" where \"mech\" is the mechanism, \"count\" is the number of times password was hashed, \"salt\" is the provided/generated base64-encoded salt, \"stored-key\" and \"server-key\" are the two derived and base64-encoded server-side keys.  When --verbose is provided, \"salted-password\" will be included as the hex-encoded PBKDF2-derived password..  */
        
        
          if (update_arg((void *)&(args_info->mkpasswd_flag), 0, &(args_info->mkpasswd_given),
              &(local_args_info.mkpasswd_given), optarg, 0, 0, ARG_FLAG,
              check_ambiguity, override, 1, 0, "mkpasswd", 'k',
              additional_error))
            goto failure;
        
          break;
        case 'd':	/* After authentication, read data from stdin and run it through the mechanism's security layer and print it base64 encoded to stdout. The default is to terminate after authentication..  */
        
        
          if (update_arg((void *)&(args_info->application_data_flag), 0, &(args_info->application_data_given),
              &(local_args_info.application_data_given), optarg, 0, 0, ARG_FLAG,
              check_ambiguity, override, 1, 0, "application-data", 'd',
              additional_error))
            goto failure;
        
          break;
        case 'm':	/* Mechanism to use..  */
        
        
          if (update_arg( (void *)&(args_info->mechanism_arg), 
               &(args_info->mechanism_orig), &(args_info->mechanism_given),
              &(local_args_info.mechanism_given), optarg, 0, 0, ARG_STRING,
              check_ambiguity, override, 0, 0,
              "mechanism", 'm',
              additional_error))
            goto failure;
        
          break;
        case 'n':	/* Token for anonymous authentication, usually mail address (ANONYMOUS only)..  */
        
        
          if (update_arg( (void *)&(args_info->anonymous_token_arg), 
               &(args_info->anonymous_token_orig), &(args_info->anonymous_token_given),
              &(local_args_info.anonymous_token_given), optarg, 0, 0, ARG_STRING,
              check_ambiguity, override, 0, 0,
              "anonymous-token", 'n',
              additional_error))
            goto failure;
        
          break;
        case 'a':	/* Identity of credential owner..  */
        
        
          if (update_arg( (void *)&(args_info->authentication_id_arg), 
               &(args_info->authentication_id_orig), &(args_info->authentication_id_given),
              &(local_args_info.authentication_id_given), optarg, 0, 0, ARG_STRING,
              check_ambiguity, override, 0, 0,
              "authentication-id", 'a',
              additional_error))
            goto failure;
        
          break;
        case 'z':	/* Identity to request service for..  */
        
        
          if (update_arg( (void *)&(args_info->authorization_id_arg), 
               &(args_info->authorization_id_orig), &(args_info->authorization_id_given),
              &(local_args_info.authorization_id_given), optarg, 0, 0, ARG_STRING,
              check_ambiguity, override, 0, 0,
              "authorization-id", 'z',
              additional_error))
            goto failure;
        
          break;
        case 'p':	/* Password for authentication (insecure for non-testing purposes)..  */
        
        
          if (update_arg( (void *)&(args_info->password_arg), 
               &(args_info->password_orig), &(args_info->password_given),
              &(local_args_info.password_given), optarg, 0, 0, ARG_STRING,
              check_ambiguity, override, 0, 0,
              "password", 'p',
              additional_error))
            goto failure;
        
          break;
        case 'r':	/* Realm. Defaults to hostname..  */
        
        
          if (update_arg( (void *)&(args_info->realm_arg), 
               &(args_info->realm_orig), &(args_info->realm_given),
              &(local_args_info.realm_given), optarg, 0, 0, ARG_STRING,
              check_ambiguity, override, 0, 0,
              "realm", 'r',
              additional_error))
            goto failure;
        
          break;

        case 0:	/* Long option with no short option */
          /* Write name of supported client mechanisms separated by space to stdout..  */
          if (strcmp (long_options[option_index].name, "client-mechanisms") == 0)
          {
          
          
            if (update_arg((void *)&(args_info->client_mechanisms_flag), 0, &(args_info->client_mechanisms_given),
                &(local_args_info.client_mechanisms_given), optarg, 0, 0, ARG_FLAG,
                check_ambiguity, override, 1, 0, "client-mechanisms", '-',
                additional_error))
              goto failure;
          
          }
          /* Write name of supported server mechanisms separated by space to stdout..  */
          else if (strcmp (long_options[option_index].name, "server-mechanisms") == 0)
          {
          
          
            if (update_arg((void *)&(args_info->server_mechanisms_flag), 0, &(args_info->server_mechanisms_given),
                &(local_args_info.server_mechanisms_given), optarg, 0, 0, ARG_FLAG,
                check_ambiguity, override, 1, 0, "server-mechanisms", '-',
                additional_error))
              goto failure;
          
          }
          /* Connect to TCP server and negotiate on stream instead of stdin/stdout. PORT is the protocol service, or an integer denoting the port, and defaults to 143 (imap) if not specified. Also sets the --hostname default..  */
          else if (strcmp (long_options[option_index].name, "connect") == 0)
          {
          
          
            if (update_arg( (void *)&(args_info->connect_arg), 
                 &(args_info->connect_orig), &(args_info->connect_given),
                &(local_args_info.connect_given), optarg, 0, 0, ARG_STRING,
                check_ambiguity, override, 0, 0,
                "connect", '-',
                additional_error))
              goto failure;
          
          }
          /* Use a IMAP-like logon procedure (client only). Also sets the --service default to 'imap'..  */
          else if (strcmp (long_options[option_index].name, "imap") == 0)
          {
          
          
            if (update_arg((void *)&(args_info->imap_flag), 0, &(args_info->imap_given),
                &(local_args_info.imap_given), optarg, 0, 0, ARG_FLAG,
                check_ambiguity, override, 1, 0, "imap", '-',
                additional_error))
              goto failure;
          
          }
          /* Use a SMTP-like logon procedure (client only). Also sets the --service default to 'smtp'..  */
          else if (strcmp (long_options[option_index].name, "smtp") == 0)
          {
          
          
            if (update_arg((void *)&(args_info->smtp_flag), 0, &(args_info->smtp_given),
                &(local_args_info.smtp_given), optarg, 0, 0, ARG_FLAG,
                check_ambiguity, override, 1, 0, "smtp", '-',
                additional_error))
              goto failure;
          
          }
          /* Disallow client to send data first (client only)..  */
          else if (strcmp (long_options[option_index].name, "no-client-first") == 0)
          {
          
          
            if (update_arg((void *)&(args_info->no_client_first_flag), 0, &(args_info->no_client_first_given),
                &(local_args_info.no_client_first_given), optarg, 0, 0, ARG_FLAG,
                check_ambiguity, override, 1, 0, "no-client-first", '-',
                additional_error))
              goto failure;
          
          }
          /* Passcode for authentication (SECURID only)..  */
          else if (strcmp (long_options[option_index].name, "passcode") == 0)
          {
          
          
            if (update_arg( (void *)&(args_info->passcode_arg), 
                 &(args_info->passcode_orig), &(args_info->passcode_given),
                &(local_args_info.passcode_given), optarg, 0, 0, ARG_STRING,
                check_ambiguity, override, 0, 0,
                "passcode", '-',
                additional_error))
              goto failure;
          
          }
          /* Set the requested service name (should be a registered GSSAPI host based service name)..  */
          else if (strcmp (long_options[option_index].name, "service") == 0)
          {
          
          
            if (update_arg( (void *)&(args_info->service_arg), 
                 &(args_info->service_orig), &(args_info->service_given),
                &(local_args_info.service_given), optarg, 0, 0, ARG_STRING,
                check_ambiguity, override, 0, 0,
                "service", '-',
                additional_error))
              goto failure;
          
          }
          /* Set the name of the server with the requested service..  */
          else if (strcmp (long_options[option_index].name, "hostname") == 0)
          {
          
          
            if (update_arg( (void *)&(args_info->hostname_arg), 
                 &(args_info->hostname_orig), &(args_info->hostname_given),
                &(local_args_info.hostname_given), optarg, 0, 0, ARG_STRING,
                check_ambiguity, override, 0, 0,
                "hostname", '-',
                additional_error))
              goto failure;
          
          }
          /* Set the generic server name in case of a replicated server (DIGEST-MD5 only)..  */
          else if (strcmp (long_options[option_index].name, "service-name") == 0)
          {
          
          
            if (update_arg( (void *)&(args_info->service_name_arg), 
                 &(args_info->service_name_orig), &(args_info->service_name_given),
                &(local_args_info.service_name_given), optarg, 0, 0, ARG_STRING,
                check_ambiguity, override, 0, 0,
                "service-name", '-',
                additional_error))
              goto failure;
          
          }
          /* Validate CRAM-MD5 challenge and response interactively..  */
          else if (strcmp (long_options[option_index].name, "enable-cram-md5-validate") == 0)
          {
          
          
            if (update_arg((void *)&(args_info->enable_cram_md5_validate_flag), 0, &(args_info->enable_cram_md5_validate_given),
                &(local_args_info.enable_cram_md5_validate_given), optarg, 0, 0, ARG_FLAG,
                check_ambiguity, override, 1, 0, "enable-cram-md5-validate", '-',
                additional_error))
              goto failure;
          
          }
          /* Disable cleartext validate hook, forcing server to prompt for password..  */
          else if (strcmp (long_options[option_index].name, "disable-cleartext-validate") == 0)
          {
          
          
            if (update_arg((void *)&(args_info->disable_cleartext_validate_flag), 0, &(args_info->disable_cleartext_validate_given),
                &(local_args_info.disable_cleartext_validate_given), optarg, 0, 0, ARG_FLAG,
                check_ambiguity, override, 1, 0, "disable-cleartext-validate", '-',
                additional_error))
              goto failure;
          
          }
          /* How application payload will be protected. 'qop-auth' means no protection, 'qop-int' means integrity protection, 'qop-conf' means integrity and confidentialiy protection.  Currently only used by DIGEST-MD5, where the default is 'qop-int'..  */
          else if (strcmp (long_options[option_index].name, "quality-of-protection") == 0)
          {
          
          
            if (update_arg( (void *)&(args_info->quality_of_protection_arg), 
                 &(args_info->quality_of_protection_orig), &(args_info->quality_of_protection_given),
                &(local_args_info.quality_of_protection_given), optarg, 0, 0, ARG_STRING,
                check_ambiguity, override, 0, 0,
                "quality-of-protection", '-',
                additional_error))
              goto failure;
          
          }
          /* Indicate PBKDF2 hash iteration count (SCRAM only)..  */
          else if (strcmp (long_options[option_index].name, "iteration-count") == 0)
          {
          
          
            if (update_arg( (void *)&(args_info->iteration_count_arg), 
                 &(args_info->iteration_count_orig), &(args_info->iteration_count_given),
                &(local_args_info.iteration_count_given), optarg, 0, "65536", ARG_INT,
                check_ambiguity, override, 0, 0,
                "iteration-count", '-',
                additional_error))
              goto failure;
          
          }
          /* Indicate PBKDF2 salt as base64-encoded string (SCRAM only)..  */
          else if (strcmp (long_options[option_index].name, "salt") == 0)
          {
          
          
            if (update_arg( (void *)&(args_info->salt_arg), 
                 &(args_info->salt_orig), &(args_info->salt_given),
                &(local_args_info.salt_given), optarg, 0, 0, ARG_STRING,
                check_ambiguity, override, 0, 0,
                "salt", '-',
                additional_error))
              goto failure;
          
          }
          /* Force use of STARTTLS.  The default is to use STARTTLS when available..  */
          else if (strcmp (long_options[option_index].name, "starttls") == 0)
          {
          
          
            if (update_arg((void *)&(args_info->starttls_flag), 0, &(args_info->starttls_given),
                &(local_args_info.starttls_given), optarg, 0, 0, ARG_FLAG,
                check_ambiguity, override, 1, 0, "starttls", '-',
                additional_error))
              goto failure;
          
          }
          /* Unconditionally disable STARTTLS..  */
          else if (strcmp (long_options[option_index].name, "no-starttls") == 0)
          {
          
          
            if (update_arg((void *)&(args_info->no_starttls_flag), 0, &(args_info->no_starttls_given),
                &(local_args_info.no_starttls_given), optarg, 0, 0, ARG_FLAG,
                check_ambiguity, override, 1, 0, "no-starttls", '-',
                additional_error))
              goto failure;
          
          }
          /* Don't use channel bindings from TLS..  */
          else if (strcmp (long_options[option_index].name, "no-cb") == 0)
          {
          
          
            if (update_arg((void *)&(args_info->no_cb_flag), 0, &(args_info->no_cb_given),
                &(local_args_info.no_cb_given), optarg, 0, 0, ARG_FLAG,
                check_ambiguity, override, 1, 0, "no-cb", '-',
                additional_error))
              goto failure;
          
          }
          /* File containing one or more X.509 Certificate Authorities certificates in PEM format, used to verify the certificate received from the server.  If not specified, verification uses system trust settings.  If FILE is the empty string, don't fail on X.509 server certificates verification errors..  */
          else if (strcmp (long_options[option_index].name, "x509-ca-file") == 0)
          {
          
          
            if (update_arg( (void *)&(args_info->x509_ca_file_arg), 
                 &(args_info->x509_ca_file_orig), &(args_info->x509_ca_file_given),
                &(local_args_info.x509_ca_file_given), optarg, 0, 0, ARG_STRING,
                check_ambiguity, override, 0, 0,
                "x509-ca-file", '-',
                additional_error))
              goto failure;
          
          }
          /* File containing client X.509 certificate in PEM format.  Used together with --x509-key-file to specify the certificate/key pair..  */
          else if (strcmp (long_options[option_index].name, "x509-cert-file") == 0)
          {
          
          
            if (update_arg( (void *)&(args_info->x509_cert_file_arg), 
                 &(args_info->x509_cert_file_orig), &(args_info->x509_cert_file_given),
                &(local_args_info.x509_cert_file_given), optarg, 0, 0, ARG_STRING,
                check_ambiguity, override, 0, 0,
                "x509-cert-file", '-',
                additional_error))
              goto failure;
          
          }
          /* Private key for the client X.509 certificate in PEM format.  Used together with --x509-key-file to specify the certificate/key pair..  */
          else if (strcmp (long_options[option_index].name, "x509-key-file") == 0)
          {
          
          
            if (update_arg( (void *)&(args_info->x509_key_file_arg), 
                 &(args_info->x509_key_file_orig), &(args_info->x509_key_file_given),
                &(local_args_info.x509_key_file_given), optarg, 0, 0, ARG_STRING,
                check_ambiguity, override, 0, 0,
                "x509-key-file", '-',
                additional_error))
              goto failure;
          
          }
          /* Cipher priority string..  */
          else if (strcmp (long_options[option_index].name, "priority") == 0)
          {
          
          
            if (update_arg( (void *)&(args_info->priority_arg), 
                 &(args_info->priority_orig), &(args_info->priority_given),
                &(local_args_info.priority_given), optarg, 0, 0, ARG_STRING,
                check_ambiguity, override, 0, 0,
                "priority", '-',
                additional_error))
              goto failure;
          
          }
          /* Produce verbose output..  */
          else if (strcmp (long_options[option_index].name, "verbose") == 0)
          {
          
          
            if (update_arg((void *)&(args_info->verbose_flag), 0, &(args_info->verbose_given),
                &(local_args_info.verbose_given), optarg, 0, 0, ARG_FLAG,
                check_ambiguity, override, 1, 0, "verbose", '-',
                additional_error))
              goto failure;
          
          }
          /* Don't produce any diagnostic output..  */
          else if (strcmp (long_options[option_index].name, "quiet") == 0)
          {
          
          
            if (update_arg((void *)&(args_info->quiet_flag), 0, &(args_info->quiet_given),
                &(local_args_info.quiet_given), optarg, 0, 0, ARG_FLAG,
                check_ambiguity, override, 1, 0, "quiet", '-',
                additional_error))
              goto failure;
          
          }
          
          break;
        case '?':	/* Invalid option.  */
          /* `getopt_long' already printed an error message.  */
          goto failure;

        default:	/* bug: option not considered.  */
          fprintf (stderr, "%s: option unknown: %c%s\n", CMDLINE_PARSER_PACKAGE, c, (additional_error ? additional_error : ""));
          abort ();
        } /* switch */
    } /* while */



	FIX_UNUSED(check_required);

  cmdline_parser_release (&local_args_info);

  if ( error_occurred )
    return (EXIT_FAILURE);

  if (optind < argc)
    {
      int i = 0 ;
      int found_prog_name = 0;
      /* whether program name, i.e., argv[0], is in the remaining args
         (this may happen with some implementations of getopt,
          but surely not with the one included by gengetopt) */

      i = optind;
      while (i < argc)
        if (argv[i++] == argv[0]) {
          found_prog_name = 1;
          break;
        }
      i = 0;

      args_info->inputs_num = argc - optind - found_prog_name;
      args_info->inputs =
        (char **)(malloc ((args_info->inputs_num)*sizeof(char *))) ;
      while (optind < argc)
        if (argv[optind++] != argv[0])
          args_info->inputs[ i++ ] = gengetopt_strdup (argv[optind-1]) ;
    }

  return 0;

failure:
  
  cmdline_parser_release (&local_args_info);
  return (EXIT_FAILURE);
}
/* vim: set ft=c noet ts=8 sts=8 sw=8 tw=80 nojs spell : */
