/* GNU Mailutils -- a suite of utilities for electronic mail
   Copyright (C) 2003, 2005, 2007, 2010-2012, 2014-2016 Free Software
   Foundation, Inc.

   GNU Mailutils 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, or (at your option)
   any later version.

   GNU Mailutils 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 GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>. */

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <mailutils/mailutils.h>
#include <mailutils/sys/prog_stream.h>

int
main (int argc, char *argv[])
{
  int rc;
  mu_stream_t stream, out;
  int read_stdin = 0;
  int i;
  int flags = MU_STREAM_READ;
  struct mu_prog_hints hints;
  int hint_flags = 0;
  char *progname = NULL;
  gid_t gid[20];
  size_t gn = 0;
  
  for (i = 1; i < argc; i++)
    {
      if (strcmp (argv[i], "--stdin") == 0)
	{
	  read_stdin = 1;
	  flags |= MU_STREAM_WRITE;
	}
      else if (strcmp (argv[i], "--chdir") == 0)
	{
	  hints.mu_prog_workdir = argv[i+1];
	  hint_flags |= MU_PROG_HINT_WORKDIR;
	  i++;
	}
      else if (strncmp (argv[i], "--limit", 7) == 0
	       && mu_isdigit (argv[i][7]))
	{
	  int n;

	  if (i + 1 == argc)
	    {
	      fprintf (stderr, "%s requires argument\n", argv[i]);
	      exit (1);
	    }
	  n = argv[i][7] - '0';
	  if (!(_mu_prog_limit_flags & MU_PROG_HINT_LIMIT(n)))
	    {
	      fprintf (stderr, "%s is not supported\n", argv[i]+2);
	      continue;
	    }
	  hint_flags |= MU_PROG_HINT_LIMIT(n);
	  hints.mu_prog_limit[n] = strtoul (argv[i+1], NULL, 10);
	  i++;
	}
      else if (strcmp (argv[i], "--prio") == 0)
	{
	  if (i + 1 == argc)
	    {
	      fprintf (stderr, "%s requires argument\n", argv[i]);
	      exit (1);
	    }
	  hint_flags |= MU_PROG_HINT_PRIO;
	  hints.mu_prog_prio = strtoul (argv[i+1], NULL, 10);
	  i++;
	}
      else if (strcmp (argv[i], "--exec") == 0)
	{
	  if (i + 1 == argc)
	    {
	      fprintf (stderr, "%s requires argument\n", argv[i]);
	      exit (1);
	    }
	  progname = argv[++i];
	}
      else if (strcmp (argv[i], "--errignore") == 0)
	hint_flags |= MU_PROG_HINT_IGNOREFAIL;
      else if (strcmp (argv[i], "--uid") == 0)
	{
	  if (i + 1 == argc)
	    {
	      fprintf (stderr, "%s requires argument\n", argv[i]);
	      exit (1);
	    }
	  hint_flags |= MU_PROG_HINT_UID;
	  hints.mu_prog_uid = strtoul (argv[i+1], NULL, 10);
	  i++;
	}
      else if (strcmp (argv[i], "--gid") == 0)
	{
	  mu_list_t list;
	  mu_iterator_t itr;
	  
	  if (i + 1 == argc)
	    {
	      fprintf (stderr, "%s requires argument\n", argv[i]);
	      exit (1);
	    }
	  mu_list_create (&list);
	  mu_list_set_destroy_item (list, mu_list_free_item);
	  rc = mu_string_split (argv[++i], ",", list);
	  if (mu_list_get_iterator (list, &itr) == 0)
	    {
	      for (mu_iterator_first (itr);
		   !mu_iterator_is_done (itr); mu_iterator_next (itr))
		{
	          char *p;

		  mu_iterator_current (itr, (void**)&p);
		  if (gn >= MU_ARRAY_SIZE (gid))
		    {
		      fprintf (stderr, "too many gids\n");
		      exit (1);
		    }
		  gid[gn++] = strtoul (p, NULL, 10);
		}
	      mu_iterator_destroy (&itr);
	    }
	  else
	    {
	      mu_diag_funcall (MU_DIAG_ERROR, "mu_list_get_iterator", NULL,
			       rc);
	      exit (1);
	    }
	  mu_list_destroy (&list);
	  hint_flags |= MU_PROG_HINT_GID;
	}
      else if (strcmp (argv[i], "--") == 0)
	{
	  i++;
	  break;
	}
      else
	break;
    }
  
  if (i == argc)
    {
      fprintf (stderr,
	       "Usage: %s [--stdin] [--chdir dir] [--limit{0-9} lim] [--prio N]\n"
	       "          [--exec progname] progname [args]\n", argv[0]);
      exit (1);
    }

  argc -= i;
  argv += i;

  if (!progname)
    progname = argv[0];
  
  if (read_stdin)
    {
      MU_ASSERT (mu_stdio_stream_create (&hints.mu_prog_input,
					 MU_STDIN_FD, 0));
      hint_flags |= MU_PROG_HINT_INPUT;
    }

  rc = mu_prog_stream_create (&stream, progname, argc, argv,
			      hint_flags, &hints, flags);
  if (hint_flags & MU_PROG_HINT_INPUT)
    /* Make sure closing/destroying stream will close/destroy input */
    mu_stream_unref (hints.mu_prog_input);

  if (rc)
    {
      fprintf (stderr, "%s: cannot create program filter stream: %s\n",
	       argv[0], mu_strerror (rc));
      exit (1);
    }
  
  MU_ASSERT (mu_stdio_stream_create (&out, MU_STDOUT_FD, 0));

  mu_stream_copy (out, stream, 0, NULL);
  mu_stream_close (stream);
  mu_stream_destroy (&stream);
  mu_stream_close (out);
  mu_stream_destroy (&out);
  return 0;
}