/* Copyright (c) 1996, 1997, 1998 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 <stdio.h>
#include <limits.h>
#include <string.h>
#include <locale.h>
#include <libintl.h>
#include <rpcsvc/nis.h>

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

#ifdef NISCHMOD
#define PROGNAME "nischmod"
#define ARG1 "mode"
#define PROG_INFO _("nischmod - change access rights on a NIS+ object\n")
#endif
#ifdef NISCHGRP
#define PROGNAME "nischgrp"
#define ARG1 "group"
#define PROG_INFO _("nischgrp - change the group owner of a NIS+ object\n")
#endif
#ifdef NISCHTTL
#define PROGNAME "nischttl"
#define ARG1 "time"
#define PROG_INFO _("nischttl - change the time to live value of a NIS+ object\n")
#endif
#ifdef NISCHOWN
#define PROGNAME "nischown"
#define ARG1 "owner"
#define PROG_INFO _("nischown - change the owner of a NIS+ object\n")
#endif

/* Print the version information.  */
static inline void
print_version (void)
{
  fprintf (stdout, "%s (%s) %s\n", PROGNAME, 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)
{
  fprintf (stdout, _("Usage: %s [-ALPf] %s name ...\n"), PROGNAME, ARG1);
}

static void
print_help (void)
{
  print_usage ();
  fputs (PROG_INFO, stdout);

  fputs (_("  -A             Modify all entries in all tables\n"), stdout);
  fputs (_("  -L             Follow links to change the object permissions\n"),
	 stdout);
  fputs (_("  -P             Follow the concatenation path within a named table\n"),
	 stdout);
  fputs (_("  -f, --force    Force the operation and fail silently on not succeed\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)
{
  fprintf (stderr,
           _("Try `%s --help' or `%s --usage' for more information.\n"),
           PROGNAME, PROGNAME);
}

int
main (int argc, char *argv[])
{
  u_long flags = EXPAND_NAME;
#ifdef NISCHMOD
  char *access;
#endif
#ifdef NISCHTTL
  char *ttl;
#endif
#ifdef NISCHGRP
  char *groupname = NULL;
#endif
#ifdef NISCHOWN
  char *ownername = NULL;
#endif
  int force = 0;
  int i;

  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'}
      };

#ifdef NISCHMOD
      c = getopt_long (argc, argv, "uALPfrmcd", long_options, &option_index);
#else
      c = getopt_long (argc, argv, "uALPf", long_options, &option_index);
#endif
      if (c == (-1))
	break;
      switch (c)
	{
	case 'A':
	  flags |= FOLLOW_PATH|ALL_RESULTS;
	  break;
	case 'f':
	  force++;
	  break;
	case 'L':
	  flags |= FOLLOW_LINKS;
	  break;
	case 'P':
	  flags |= FOLLOW_PATH;
	  break;
#ifdef NISCHMOD
	case 'r': case 'm': case 'c': case 'd':
	  /* special hack for the new modes */
	  if (argv[optind - 1][0] == '-' &&
	      argv[optind - 1][1] == c &&
	      argv[optind - 1][2] == '\0')
	    optind--;
	  goto done;
	  break;
#endif
        case '\253':
          print_help ();
          return 0;
        case '\255':
          print_version ();
          return 0;
        case '\254':
          print_usage ();
          return 0;
        default:
          print_error ();
          return 1;
	}
    }
#ifdef NISCHMOD
 done:
#endif
  argc -= optind;
  argv += optind;

  if (argc < 2)
    {
      fprintf (stderr, _("%s: To few arguments\n"), PROGNAME);
      print_error ();
      return 1;
    }

#ifdef NISCHMOD
  access = calloc (1, strlen (argv[0]) + 10);
  sprintf (access, "access=%s", argv[0]);
#endif
#ifdef NISCHTTL
  ttl = calloc (1, strlen (argv[0]) + 6);
  sprintf (ttl, "ttl=%s", argv[0]);
#endif
#ifdef NISCHGRP
  if (argv[0][strlen (argv[0])-1] != '.')
    {
      nis_name *grps = nis_getnames (argv[0]);

      i = 0;
      while (grps[i] != 0)
	{
	  if (nis_verifygroup (grps[i]) == NIS_SUCCESS)
	    groupname = strdup (grps[i]);
	  ++i;
	}
      nis_freenames (grps);
      if (groupname == NULL)
	{
	  fputs (_("Couldn't find group, please use fully qualified group name.\n")
		 , stdout);
	  return 1;
	}
    }
  else
    groupname = argv[0];
#endif
#ifdef NISCHOWN
  if (argv[0][strlen (argv[0])-1] != '.')
    {
      ownername = malloc (strlen (argv[0]) + strlen (nis_local_directory ()) +
			  10);
      sprintf (ownername, "%s.%s", argv[0], nis_local_directory ());
    }
  else
    ownername = argv[0];
#endif

  for (i = 1; i < argc; ++i)
    {
      char buf[NIS_MAXNAMELEN + 1];
      nis_result *res, *mres;
      int indexed;
      u_int j;

      if (strchr (argv[i], '[') == NULL)
	{
	  indexed = 0;
	  res = nis_lookup (argv[i], flags);
	}
      else
	{
	  indexed = 1;
	  res = nis_list (argv[i], flags, NULL, NULL);
	}
      if (res->status != NIS_SUCCESS)
	{
	  fprintf (stderr, "%s: %s", argv[i], nis_sperrno (res->status));
	  nis_freeresult (res);
	  continue;
	}
      for (j = 0; j < res->objects.objects_len; ++j)
	{
	  nis_object *obj =
	    nis_clone_object (&res->objects.objects_val[j], NULL);

#ifdef NISCHMOD
	  obj->zo_access =
	    __nis_default_access (access, obj->zo_access);
	  if (obj->zo_access == ULONG_MAX)
	    {
	      fprintf (stderr, _("Can't parse access rights \"%s\".\n"),
		       argv[0]);
	    }
#endif
#ifdef NISCHGRP
	  free (obj->zo_group);
	  obj->zo_group = strdup (groupname);
#endif
#ifdef NISCHOWN
	  free (obj->zo_owner);
	  obj->zo_owner = strdup (ownername);
#endif
#ifdef NISCHTTL
	  obj->zo_ttl = __nis_default_ttl (ttl);
	  if (__type_of (obj) == NIS_DIRECTORY_OBJ)
	    obj->DI_data.do_ttl = obj->zo_ttl;
#endif
	  snprintf (buf, NIS_MAXNAMELEN, "%s.%s",
		    NIS_RES_OBJECT (res)->zo_name,
		    NIS_RES_OBJECT (res)->zo_domain);
	  if (indexed)
	    mres = nis_modify_entry (buf, obj, MOD_SAMEOBJ);
	  else
	    mres = nis_modify (buf, obj);
	  nis_free_object (obj);
	  if (mres->status != NIS_SUCCESS)
	    {
	      fprintf (stderr, _("failed to modify %s: %s"), argv[i],
		       nis_sperrno (mres->status));
	      nis_freeresult (mres);
	      continue;
	    }
	}
      nis_freeresult (res);
    }
  return 0;
}
