/* Copyright (c) 1997, 1998, 1999 Thorsten Kukuk
   Author: Thorsten Kukuk <kukuk@vt.uni-paderborn.de>

   This program 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 2, or (at your option)
   any later version.

   This program 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, write to the Free Software Foundation,
   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#define _GNU_SOURCE

#ifdef HAVE_GETOPT_H
#include <getopt.h>
#else
#include "lib/compat/getopt.h"
#endif
#include <ctype.h>
#include <locale.h>
#include <libintl.h>
#include <rpcsvc/nis.h>
#include <rpc/key_prot.h>
#include "nis_xdr.h"

#ifndef _
#define _(String) gettext (String)
#endif

/* Print the version information.  */
static inline void
print_version (void)
{
  fprintf (stdout, "nisrmdir (%s) %s\n", PACKAGE, VERSION);
  fprintf (stdout, gettext ("\
Copyright (C) %s Thorsten Kukuk.\n\
This is free software; see the source for copying conditions.  There is NO\n\
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
"), "1998");
  /* fprintf (stdout, _("Written by %s.\n"), "Thorsten Kukuk"); */
}

static inline void
print_usage (void)
{
  fputs (_("Usage: nisrmdir [-if] [-s hostname] dirname\n"), stdout);
}

static void
print_help (void)
{
  print_usage ();
  fputs (_("nisrmdir - remove NIS+ directories\n\n"), stdout);

  fputs (_("  -f, --force    Force the command to succeed\n"), stdout);
  fputs (_("  -i             Interactive mode\n"), stdout);
  fputs (_("  -s hostname    Remove \"hostname\" as replica\n"), stdout);
  fputs (_("  --help         Give this help list\n"), stdout);
  fputs (_("  --usage        Give a short usage message\n"), stdout);
  fputs (_("  --version      Print program version\n"), stdout);
}

static inline  void
print_error (void)
{
  const char *program = "nisrmdir";

  fprintf (stderr,
           _("Try `%s --help' or `%s --usage' for more information.\n"),
           program, program);
}

static int
yesno (void)
{
  char buf[128];
  int len = 0;
  int c;

  while ((c = getchar ()) != EOF && c != '\n')
    if ((len > 0 && len < 127) || (len == 0 && !isspace (c)))
      buf[len++] = c;
  buf[len] = '\0';

  return rpmatch (buf) == 1;
}

int
main (int argc, char *argv[])
{
  char fullname[NIS_MAXNAMELEN + 1];
  nis_result *res;
  char *replica = NULL;
  bool_t interactive = FALSE;
  bool_t force = FALSE;

  setlocale (LC_MESSAGES, "");
  bindtextdomain (PACKAGE, LOCALEDIR);
  textdomain (PACKAGE);

  while (1)
    {
      int c;
      int option_index = 0;
      static struct option long_options[] =
      {
	{"version", no_argument, NULL, '\255'},
	{"usage", no_argument, NULL, '\254'},
	{"help", no_argument, NULL, '\253'},
	{"force", no_argument, NULL, 'f'},
	{NULL, 0, NULL, '\0'}
      };

      c = getopt_long (argc, argv, "fis:", long_options, &option_index);
      if (c == EOF)
	break;
      switch (c)
	{
	case 's':
	  replica = optarg;
	  break;
	case 'i':
	  interactive = TRUE;
	  break;
	case 'f':
	  interactive = FALSE;
	  force = TRUE;
	  break;
        case '\253':
          print_help ();
          return 0;
        case '\255':
          print_version ();
          return 0;
        case '\254':
          print_usage ();
          return 0;
        default:
          print_error ();
          return 1;
        }
    }

  argc -= optind;
  argv += optind;

  if (argc != 1)
    {
      fprintf (stderr, _("%s: Wrong number of arguments\n"), "nisrmdir");
      print_error ();
      return 1;
    }

  res = nis_lookup (argv[0], MASTER_ONLY|EXPAND_NAME);

  if (res->status != NIS_SUCCESS)
    {
      fprintf (stderr, "%s: %s", argv[0], nis_sperrno(res->status));
      nis_freeresult(res);
      return 1;
    }

  if (__type_of(NIS_RES_OBJECT(res)) != NIS_DIRECTORY_OBJ)
    {
      fprintf (stderr, _("%s: is not a directory!\n"), argv[0]);
      nis_freeresult (res);
      return 1;
    }

  snprintf (fullname, NIS_MAXNAMELEN, "%s.%s",
	    NIS_RES_OBJECT (res)->zo_name,
	    NIS_RES_OBJECT (res)->zo_domain);

  if ((interactive || argv[0][strlen (argv[0]) -1] != '.') && !force)
    {
      fprintf (stdout, _("remove %s? "), fullname);
      if (!yesno ())
	{
	  nis_freeresult (res);
	  return 0;
	}
    }


  if (replica != NULL)
    {
      unsigned int i, count_serv, found = 0;
      nis_server *newserv, *oldserv, *repserv = NULL;
      nis_object *save;
      nis_result *tmpres;
      nis_name *names = NULL;
      nis_error rmstat;

      if (replica[strlen (replica) - 1] != '.')
	names = nis_getnames (replica);

      save = nis_clone_object (NIS_RES_OBJECT(res), NULL);

      newserv =
	calloc(1, sizeof(nis_server) *
	       (NIS_RES_OBJECT (res)->DI_data.do_servers.do_servers_len));
      oldserv = NIS_RES_OBJECT (res)->DI_data.do_servers.do_servers_val;
      count_serv = 0;
      for (i = 0; i < NIS_RES_OBJECT (res)->DI_data.do_servers.do_servers_len;
	   ++i)
	{
	  int is_same = 0;

	  if (names == NULL)
	    {
	      if (strcmp (replica, oldserv[i].name) == 0)
		is_same = 1;
	    }
	  else
	    {
	      unsigned int j = 0;
	      while (names[j] != NULL)
		{
		  if (strcmp (names[j], oldserv[i].name) == 0)
		    {
		      is_same = 1;
		      break;
		    }
		  ++j;
		}
	    }
	  if (is_same)
	    {
	      ++found;
	      repserv = &oldserv[i];
	    }
	  else
	    {
	      memcpy(&newserv[count_serv], &oldserv[i], sizeof(nis_server));
	      ++count_serv;
	    }
	}

      if (!found)
	{
	  if (!force)
	    fprintf (stderr, _("Host %s is not listed as a replica for %s\n"),
		     replica, fullname);
	  nis_freeresult (res);
	  free (newserv);
	  return 1;
        }

      if (found > 1)
	{
	  fprintf (stderr, _("%s is not unique, please use full host name.\n"),
		   replica);
	  nis_freeresult (res);
	  free (newserv);
	  return 1;
	}

      rmstat = nis_rmdir (fullname, repserv);
      if (rmstat != NIS_SUCCESS && !force)
	{
	  fprintf (stderr, _("cannot remove replica %s: %s\n"),
		   fullname, nis_sperrno(rmstat));
	  nis_freeresult (res);
	  free (newserv);
	  return 1;
	}
      xdr_free ((xdrproc_t)xdr_nis_server, (char *)repserv);
      free (repserv);

      NIS_RES_OBJECT (res)->DI_data.do_servers.do_servers_len -= found;
      NIS_RES_OBJECT (res)->DI_data.do_servers.do_servers_val = newserv;
      free (oldserv);

      tmpres = nis_modify (fullname, NIS_RES_OBJECT (res));
      nis_freeresult (res);
      res = tmpres;

      if (res->status != NIS_SUCCESS)
	{
	  fprintf (stderr, _("cannot remove replica: %s\n"),
		   nis_sperrno (res->status));
	  nis_freeresult (res);
	  nis_modify (fullname, save);
	  nis_destroy_object (save);
	  return 1;
	}
      nis_destroy_object (save);
    }
  else
    {
      nis_result *rres;
      nis_error rmstat;
      unsigned int i;

      for (i = 1; i < NIS_RES_OBJECT (res)->DI_data.do_servers.do_servers_len;
	   ++i)
	{
	  rmstat =  nis_rmdir (fullname,
	      &NIS_RES_OBJECT (res)->DI_data.do_servers.do_servers_val[i]);

	  if (rmstat != NIS_SUCCESS && !force)
	    {
	      unsigned int j;
	      fprintf (stderr, _("cannot remove replica %s: %s\n"),
	       NIS_RES_OBJECT (res)->DI_data.do_servers.do_servers_val[i].name,
		       nis_sperrno(rmstat));
	      /* Create the wrong deleted directories ! */
	      for (j = 1; j < i; ++j)
		nis_mkdir (fullname,
		 &NIS_RES_OBJECT (res)->DI_data.do_servers.do_servers_val[j]);
	      nis_freeresult (res);
	      return 1;
	    }
	}

      rres = nis_remove (fullname, NIS_RES_OBJECT (res));

      if (rres->status != NIS_SUCCESS)
	{
	  fprintf (stderr, _("cannot remove %s: %s\n"),
		   fullname, nis_sperrno (rres->status));
	  nis_freeresult (res);
	  return 1;
	}

      nis_freeresult (rres);

      rmstat =
	nis_rmdir (fullname,
		   NIS_RES_OBJECT (res)->DI_data.do_servers.do_servers_val);

      if (rmstat != NIS_SUCCESS)
	{
	  fprintf (stderr, "%s: %s\n", fullname , nis_sperrno (rmstat));
	  nis_add (fullname, NIS_RES_OBJECT (res));
	  nis_freeresult (res);
	  return 1;
	}
    }
  nis_freeresult (res);

  return 0;
}
