/* gpgmail.c - A command line mail sending utility
 * Copyright (C) 2017 GnuPG e.V.
 *
 * This file is part of GnuPG.
 *
 * GnuPG is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * GnuPG is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <https://www.gnu.org/licenses/>.
 */

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

#include "../common/util.h"
#include "../common/status.h"
#include "../common/i18n.h"
#include "../common/sysutils.h"
#include "../common/init.h"
#include "../common/asshelp.h"
#include "../common/userids.h"
#include "../common/ccparray.h"
#include "../common/exectool.h"
#include "../common/mbox-util.h"
#include "../common/name-value.h"
#include "call-dirmngr.h"
#include "mime-maker.h"
#include "send-mail.h"
#include "gpgmail.h"


/* Constants to identify the commands and options. */
enum cmd_and_opt_values
  {
    aNull = 0,

    oAttach     = 'a',
    oBCC        = 'b',
    oCC         = 'c',
    oEnvFrom    = 'f',
    oDryRun     = 'n',
    oOutput     = 'o',
    oSubject    = 's',
    oTake       = 't',
    oQuiet      = 'q',
    oRecipient  = 'r',
    oLocalUser  = 'u',
    oVerbose	= 'v',

    oDebug      = 500,

    oEncrypt,
    oNoEncrypt,
    oSign,
    oNoSign,

    oGpgProgram,

    oDummy
  };


/* The list of commands and options. */
static ARGPARSE_OPTS opts[] = {
  ARGPARSE_group (301, ("@Options:\n ")),

  ARGPARSE_s_s (oAttach,   "attach",     N_("|FILE|attach FILE to the mail")),
  ARGPARSE_s_s (oSubject,  "subject",    N_("|TEXT|use TEXT for the subject")),
  ARGPARSE_s_s (oCC,       "cc",         N_("|ADDR|carbon copy to ADDR")),
  ARGPARSE_s_s (oBCC,      "bcc",        N_("|ADDR|blind carbon copy to ADDR")),
  ARGPARSE_s_n (oEncrypt,  "encrypt",    N_("force encryption")),
  ARGPARSE_s_n (oNoEncrypt,"no-encrypt", N_("disable encryption")),
  ARGPARSE_s_n (oSign,     "sign",       N_("force signing")),
  ARGPARSE_s_n (oNoSign,   "no-sign",    N_("disable signing")),
  ARGPARSE_s_s (oRecipient,"recipient",  N_("|USER-ID|encrypt for USER-ID")),
  ARGPARSE_s_s (oLocalUser,"local-user", N_("|USER-ID|sign with USER-ID")),

  ARGPARSE_s_n (oTake,     "take",       N_("take address from mail header")),
  ARGPARSE_s_n (oEnvFrom,  "env-from",   N_("|ADDR|use ADDR as envelope From")),

  ARGPARSE_s_n (oVerbose,   "verbose",   N_("print what is going on")),
  ARGPARSE_s_n (oQuiet,	    "quiet",     N_("be somewhat more quiet")),
  ARGPARSE_s_n (oDryRun,    "dry-run",   N_("do not actually send the mail")),
  ARGPARSE_s_s (oDebug,     "debug",     "@"),
  ARGPARSE_s_s (oGpgProgram,"gpg",      "@"),
  ARGPARSE_s_s (oOutput,    "output",    N_("|FILE|write the mail to FILE")),

  ARGPARSE_end ()
};


/* The list of supported debug flags.  */
static struct debug_flags_s debug_flags [] =
  {
    { DBG_MIME_VALUE   , "mime"    },
    { DBG_PARSER_VALUE , "parser"  },
    { DBG_CRYPTO_VALUE , "crypto"  },
    { DBG_MEMORY_VALUE , "memory"  },
    { DBG_MEMSTAT_VALUE, "memstat" },
    { DBG_IPC_VALUE    , "ipc"     },
    { DBG_EXTPROG_VALUE, "extprog" },
    { 0, NULL }
  };



/* Value of the option --fake-submission-addr.  */
const char *fake_submission_addr;


static void wrong_args (const char *text) GPGRT_ATTR_NORETURN;



/* Print usage information and provide strings for help. */
static const char *
my_strusage( int level )
{
  const char *p;

  switch (level)
    {
    case 11: p = "gpgmail (@GNUPG@)";
      break;
    case 13: p = VERSION; break;
    case 17: p = PRINTABLE_OS_NAME; break;
    case 19: p = ("Please report bugs to <@EMAIL@>.\n"); break;

    case 1:
    case 40:
      p = ("Usage: gpgmail [command] [options] [addresses] (-h for help)");
      break;
    case 41:
      p = ("Syntax: gpgmail [command] [options] [addresses]\n"
           "Send stdin as mail to the addresses.\n");
      break;

    default: p = NULL; break;
    }
  return p;
}


static void
wrong_args (const char *text)
{
  es_fprintf (es_stderr, _("usage: %s [options] %s\n"), strusage (11), text);
  exit (2);
}



/* Command line parsing.  */
static enum cmd_and_opt_values
parse_arguments (ARGPARSE_ARGS *pargs, ARGPARSE_OPTS *popts)
{
  enum cmd_and_opt_values cmd = 0;
  int no_more_options = 0;

  while (!no_more_options && optfile_parse (NULL, NULL, NULL, pargs, popts))
    {
      switch (pargs->r_opt)
        {
	case oQuiet:     opt.quiet = 1; break;
        case oVerbose:   opt.verbose++; break;
        case oDebug:
          if (parse_debug_flag (pargs->r.ret_str, &opt.debug, debug_flags))
            {
              pargs->r_opt = ARGPARSE_INVALID_ARG;
              pargs->err = ARGPARSE_PRINT_ERROR;
            }
          break;

        case oGpgProgram:
          opt.gpg_program = pargs->r.ret_str;
          break;
        case oOutput:
          opt.output = pargs->r.ret_str;
          break;

        default: pargs->err = 2; break;
	}
    }

  return cmd;
}



/* gpgmail main. */
int
main (int argc, char **argv)
{
  gpg_error_t err;
  ARGPARSE_ARGS pargs;
  enum cmd_and_opt_values cmd;

  gnupg_reopen_std ("gpgmail");
  set_strusage (my_strusage);
  log_set_prefix ("gpgmail", GPGRT_LOG_WITH_PREFIX);

  /* Make sure that our subsystems are ready.  */
  i18n_init();
  init_common_subsystems (&argc, &argv);

  assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
  setup_libassuan_logging (&opt.debug, NULL);

  /* Parse the command line. */
  pargs.argc  = &argc;
  pargs.argv  = &argv;
  pargs.flags = ARGPARSE_FLAG_KEEP;
  cmd = parse_arguments (&pargs, opts);

  if (log_get_errorcount (0))
    exit (2);

  /* Print a warning if an argument looks like an option.  */
  if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN))
    {
      int i;

      for (i=0; i < argc; i++)
        if (argv[i][0] == '-' && argv[i][1] == '-')
          log_info (_("NOTE: '%s' is not considered an option\n"), argv[i]);
    }

  /* Set defaults for non given options.  */
  if (!opt.gpg_program)
    opt.gpg_program = gnupg_module_name (GNUPG_MODULE_NAME_GPG);

  /* Tell call-dirmngr what options we want.  */
  set_dirmngr_options (opt.verbose, (opt.debug & DBG_IPC_VALUE), 1);

  /* Run the selected command.  */
  switch (cmd)
    {
    default:
      usage (1);
      err = 0;
      break;
    }

  return log_get_errorcount (0)? 1:0;
}


