#ifndef _GPG_H
#define _GPG_H

#include <stdint.h>
#include <getopt.h>
#include <stdbool.h>

#define COMMAND_MAX_LEN 1024

struct command_hdr {
    uint32_t len;
    char command[COMMAND_MAX_LEN];
};

#define MAX_FDS 16
#define MAX_FD_VALUE 1024

enum {
    opt_always_trust = 257,
    opt_attribute_fd,
    opt_batch,
    opt_cert_digest_algo,
    opt_cert_notation,
    opt_charset,
    opt_cipher_algo,
    opt_clearsign,
    opt_command_fd,
    opt_comment,
    opt_compress_algo,
    opt_default_recipient,
    opt_default_recipient_self,
    opt_digest_algo,
    opt_disable_cipher_algo,
    opt_disable_mdc,
    opt_disable_pubkey_algo,
    opt_display,
    opt_display_charset,
    opt_emit_version,
    opt_enable_progress_filter,
    opt_encrypt_to,
    opt_exit_on_status_write_error,
    opt_export,
    opt_export_ssh,
    opt_fingerprint,
    opt_fixed_list_mode,
    opt_force_mdc,
    opt_force_v3_sigs,
    opt_force_v4_certs,
    opt_gnupg,
    opt_hidden_encrypt_to,
    opt_list_config,
    opt_list_only,
    opt_list_options,
    opt_list_sigs,
    opt_logger_fd,
    opt_keyid_format,
    opt_max_output,
    opt_no_auto_check_trustdb,
    opt_no_comments,
    opt_no_default_recipient,
    opt_no_emit_version,
    opt_no_encrypt_to,
    opt_no_force_v3_sigs,
    opt_no_force_v4_certs,
    opt_no_greeting,
    opt_no_secmem_warning,
    opt_no_sk_comments,
    opt_no_skip_hidden_recipients,
    opt_no_throw_keyids,
    opt_no_tty,
    opt_no_verbose,
    opt_openpgp,
    opt_passphrase_fd,
    opt_personal_cipher_preferences,
    opt_personal_compress_preferences,
    opt_personal_digest_preferences,
    opt_pgp2,
    opt_pgp6,
    opt_pgp7,
    opt_pgp8,
    opt_rfc1991,
    opt_rfc2440,
    opt_rfc4880,
    opt_s2k_cipher_algo,
    opt_s2k_count,
    opt_s2k_digest_algo,
    opt_s2k_mode,
    opt_sender,
    opt_set_filename,
    opt_sig_notation,
    opt_skip_hidden_recipients,
    opt_status_fd,
    opt_store,
    opt_throw_keyids,
    opt_trust_model,
    opt_trusted_key,
    opt_try_all_secrets,
    opt_try_secret_key,
    opt_unwrap,
    opt_use_agent,
    opt_verify,
    opt_verify_options,
    opt_version,
    opt_with_colons,
    opt_with_fingerprint,
    opt_with_keygrip,
    opt_yes
};

int parse_options(int argc, char *argv[], int *input_fds,
        int *input_fds_count, int *output_fds,
        int *output_fds_count, int is_client);
int prepare_pipes_and_run(const char *run_file, char **run_argv, int *input_fds,
        int input_fds_count, int *output_fds,
        int output_fds_count);

static const int gpg_allowed_options[] = {
    'b',
    'a',
    'c',
    'd',
    'e',
    'k',
    'K',
    'n',
    'N',
    'o',
    'q',
    'r',
    'R',
    's',
    't',
    'u',
    'v',
    opt_always_trust,
    opt_batch,
    opt_cert_notation,
    opt_charset,
    opt_clearsign,
    opt_command_fd,
    opt_comment,
    opt_compress_algo,
    opt_default_recipient_self,
    opt_digest_algo,
    opt_disable_mdc,
    opt_display_charset,
    opt_emit_version,
    opt_enable_progress_filter,
    opt_encrypt_to,
    opt_exit_on_status_write_error,
    opt_export,
    opt_export_ssh,
    opt_fingerprint,
    opt_fixed_list_mode,
    opt_force_mdc,
    opt_force_v3_sigs,
    opt_force_v4_certs,
    opt_gnupg,
    opt_hidden_encrypt_to,
    opt_list_config,
    opt_list_only,
    opt_list_options,
    opt_list_sigs,
    opt_logger_fd,
    opt_keyid_format,
    opt_max_output,
    opt_no_auto_check_trustdb,
    opt_no_comments,
    opt_no_comments,
    opt_no_default_recipient,
    opt_no_emit_version,
    opt_no_encrypt_to,
    opt_no_force_v3_sigs,
    opt_no_force_v4_certs,
    opt_no_greeting,
    opt_no_secmem_warning,
    opt_no_sk_comments,
    opt_no_skip_hidden_recipients,
    opt_no_throw_keyids,
    opt_no_tty,
    opt_no_verbose,
    opt_openpgp,
    opt_personal_cipher_preferences,
    opt_personal_compress_preferences,
    opt_personal_digest_preferences,
    opt_pgp2,
    opt_pgp6,
    opt_pgp7,
    opt_pgp8,
    opt_rfc1991,
    opt_rfc2440,
    opt_rfc4880,
    opt_s2k_cipher_algo,
    opt_s2k_count,
    opt_s2k_digest_algo,
    opt_s2k_mode,
    opt_sender,
    opt_set_filename,
    opt_sig_notation,
    opt_skip_hidden_recipients,
    opt_status_fd,
    opt_store,
    opt_throw_keyids,
    opt_trust_model,
    opt_trusted_key,
    opt_try_all_secrets,
    opt_try_secret_key,
    opt_unwrap,
    opt_use_agent,
    opt_verify,
    opt_verify_options,
    opt_version,
    opt_with_colons,
    opt_with_fingerprint,
    opt_with_keygrip,
    opt_yes,
    0
};

/*
 * Options that define command to perform. There can be only one of those, and
 * the command define how non-option arguments are interpreted (either file
 * path, or user id).
 */
struct gpg_command_opt {
    int opt;
    bool userid_args;
};
static const struct gpg_command_opt gpg_commands[] = {
    {'K', true},
    {'b', false},
    {'c', false},
    {'d', false},
    {'e', false},
    {'k', true},
    {'s', false},
    {opt_clearsign, false},
    {opt_export, true},
    {opt_export_ssh, true},
    {opt_fingerprint, true},
    {opt_list_config, false},
    {opt_list_sigs, true},
    {opt_store, false},
    {opt_verify, false},
    {0, false},
};

static const char gpg_short_options[] = "bacdekKnN:qr:R:stu:";

static const struct option gpg_long_options[] = {
    {"always-trust", 0, 0, opt_always_trust},
    {"armor", 0, 0, 'a'},
    {"batch", 0, 0, opt_batch},
    {"cert-digest-algo", 1, 0, opt_cert_digest_algo},
    {"cert-notation", 1, 0, opt_cert_notation},
    {"charset", 1, 0, opt_charset},
    {"cipher-algo", 1, 0, opt_cipher_algo},
    {"clearsign", 0, 0, opt_clearsign},
    {"command-fd", 1, 0, opt_command_fd},
    {"comment", 1, 0, opt_comment},
    {"compress-algo", 1, 0, opt_compress_algo},
    {"decrypt", 0, 0, 'd'},
    {"default-recipient", 1, 0, opt_default_recipient},
    {"default-recipient-self", 0, 0, opt_default_recipient_self},
    {"detach-sign", 0, 0, 'b'},
    {"digest-algo", 1, 0, opt_digest_algo},
    {"disable-cipher-algo", 1, 0, opt_disable_cipher_algo},
    {"disable-mdc", 0, 0, opt_disable_mdc},
    {"disable-pubkey-algo", 1, 0, opt_disable_pubkey_algo},
    {"display", 1, 0, opt_display},
    {"display-charset", 1, 0, opt_display_charset},
    {"dry-run", 0, 0, 'n'},
    {"emit-version", 0, 0, opt_emit_version},
    {"enable-progress-filter", 0, 0, opt_enable_progress_filter},
    {"encrypt", 0, 0, 'e'},
    {"encrypt-to", 1, 0, opt_encrypt_to},
    {"exit-on-status-write-error", 0, 0, opt_exit_on_status_write_error},
    {"export", 0, 0, opt_export},
    {"export-ssh-key", 0, 0, opt_export_ssh},
    {"fingerprint", 0, 0, opt_fingerprint},
    {"fixed-list-mode", 0, 0, opt_fixed_list_mode},
    {"force-mdc", 0, 0, opt_force_mdc},
    {"force-v3-sigs", 0, 0, opt_force_v3_sigs},
    {"force-v4-certs", 0, 0, opt_force_v4_certs},
    {"gnupg", 0, 0, opt_gnupg},
    {"hidden-encrypt-to", 1, 0, opt_hidden_encrypt_to},
    {"hidden-recipient", 1, 0, 'R'},
    {"list-config", 0, 0, opt_list_config},
    {"list-keys", 0, 0, 'k'},
    {"list-only", 0, 0, opt_list_only},
    {"list-options", 1, 0, opt_list_options},
    {"list-public-keys", 0, 0, 'k'},
    {"list-secret-keys", 0, 0, 'K'},
    {"list-sigs", 0, 0, opt_list_sigs},
    {"local-user", 1, 0, 'u'},
    {"logger-fd", 1, 0, opt_logger_fd},
    {"keyid-format", 1, 0, opt_keyid_format},
    {"max-output", 1, 0, opt_max_output},
    {"no-auto-check-trustdb", 0, 0, opt_no_auto_check_trustdb},
    {"no-comments", 0, 0, opt_no_comments},
    {"no-default-recipient", 0, 0, opt_no_default_recipient},
    {"no-encrypt-to", 0, 0, opt_no_encrypt_to},
    {"no-emit-version", 0, 0, opt_no_emit_version},
    {"no-force-v3-sigs", 0, 0, opt_no_force_v3_sigs},
    {"no-force-v4-certs", 0, 0, opt_no_force_v4_certs},
    {"no-greeting", 0, 0, opt_no_greeting},
    {"no-secmem-warning", 0, 0, opt_no_secmem_warning},
    {"no-sk-comments", 0, 0, opt_no_sk_comments},
    {"no-skip-hidden-recipients", 0, 0, opt_no_skip_hidden_recipients},
    {"no-throw-keyids", 0, 0, opt_no_throw_keyids},
    {"no-tty", 0, 0, opt_no_tty},
    {"no-verbose", 0, 0, opt_no_verbose},
    {"openpgp", 0, 0, opt_openpgp},
    {"output", 1, 0, 'o'},
    {"personal-cipher-preferences", 1, 0,
        opt_personal_cipher_preferences},
    {"personal-compress-preferences", 1, 0,
        opt_personal_compress_preferences},
    {"personal-digest-preferences", 1, 0,
        opt_personal_digest_preferences},
    {"pgp2", 0, 0, opt_pgp2},
    {"pgp6", 0, 0, opt_pgp6},
    {"pgp7", 0, 0, opt_pgp7},
    {"pgp8", 0, 0, opt_pgp8},
    {"quiet", 0, 0, 'q'},
    {"recipient", 1, 0, 'r'},
    {"rfc1991", 0, 0, opt_rfc1991},
    {"rfc2440", 0, 0, opt_rfc2440},
    {"rfc4880", 0, 0, opt_rfc4880},
    {"s2k-cipher-algo", 1, 0, opt_s2k_cipher_algo},
    {"s2k-count", 1, 0, opt_s2k_count},
    {"s2k-digest-algo", 1, 0, opt_s2k_digest_algo},
    {"s2k-mode", 1, 0, opt_s2k_mode},
    {"sender", 1, 0, opt_sender},
    {"sig-notation", 1, 0, opt_sig_notation},
    {"sign", 0, 0, 's'},
    {"set-filename", 1, 0, opt_set_filename},
    {"set-notation", 1, 0, 'N'},
    {"skip-hidden-recipients", 0, 0, opt_skip_hidden_recipients},
    {"status-fd", 1, 0, opt_status_fd},
    {"store", 0, 0, opt_store},
    {"symmetric", 0, 0, 'c'},
    {"textmode", 0, 0, 't'},
    {"throw-keyids", 0, 0, opt_throw_keyids},
    {"trust-model", 1, 0, opt_trust_model},
    {"trusted-key", 1, 0, opt_trusted_key},
    {"try-secret-key", 1, 0, opt_try_secret_key},
    {"try-all-secrets", 0, 0, opt_try_all_secrets},
    {"unwrap", 0, 0, opt_unwrap},
    {"use-agent", 0, 0, opt_use_agent},
    {"verify", 0, 0, opt_verify},
    {"verify-options", 1, 0, opt_verify_options},
    {"verbose", 0, 0, 'v'},
    {"version", 0, 0, opt_version},
    {"with-colons", 0, 0, opt_with_colons},
    {"with-fingerprint", 0, 0, opt_with_fingerprint},
    {"with-keygrip", 0, 0, opt_with_keygrip},
    {"yes", 0, 0, opt_yes},
    {0, 0, 0, 0}
};

#endif				/* _GPG_H */
