/* Copyright (c) 1997, 1998, 1999 Thorsten Kukuk
   Author: Thorsten Kukuk <kukuk@suse.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 <string.h>
#include <locale.h>
#include <libintl.h>
#include <rpcsvc/nis.h>

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

static u_long
searchaccess (char *str)
{
  static char buf[NIS_MAXNAMELEN];
  char *cptr;
  u_long result;
  int i;
  int n, o, g, w;

  cptr = strstr (str, "access=");
  if (cptr == NULL)
    return 0;

  cptr += 7;                    /* points to the begin of the access string */
  i = 0;
  while (cptr[i] != '\0' && cptr[i] != ':')
    ++i;
  if (i == 0)                   /* only "access=" ? */
    return 0;

  strncpy (buf, cptr, i);

  result = n = o = g = w = 0;
  cptr = buf;
  while (*cptr != '\0')
    {
      switch (*cptr)
        {
        case 'n':
          n = 1;
          break;
        case 'o':
          o = 1;
          break;
        case 'g':
          g = 1;
          break;
        case 'w':
          w = 1;
          break;
        case 'a':
          o = g = w = 1;
          break;
        case '-':
          ++cptr;               /* Remove "=" from beginning */
          while (*cptr != '\0' && *cptr != ',')
            {
              switch (*cptr)
                {
                case 'r':
                  if (n)
                    result = result & ~(NIS_READ_ACC << 24);
                  if (o)
                    result = result & ~(NIS_READ_ACC << 16);
                  if (g)
                    result = result & ~(NIS_READ_ACC << 8);
                  if (w)
                    result = result & ~(NIS_READ_ACC);
                  break;
                case 'm':
                  if (n)
                    result = result & ~(NIS_MODIFY_ACC << 24);
                  if (o)
                    result = result & ~(NIS_MODIFY_ACC << 16);
                  if (g)
                    result = result & ~(NIS_MODIFY_ACC << 8);
                  if (w)
                    result = result & ~(NIS_MODIFY_ACC);
                  break;
                case 'c':
                  if (n)
                    result = result & ~(NIS_CREATE_ACC << 24);
                  if (o)
                    result = result & ~(NIS_CREATE_ACC << 16);
                  if (g)
                    result = result & ~(NIS_CREATE_ACC << 8);
                  if (w)
                    result = result & ~(NIS_CREATE_ACC);
                  break;
                case 'd':
                  if (n)
                    result = result & ~(NIS_DESTROY_ACC << 24);
                  if (o)
                    result = result & ~(NIS_DESTROY_ACC << 16);
                  if (g)
                    result = result & ~(NIS_DESTROY_ACC << 8);
                  if (w)
                    result = result & ~(NIS_DESTROY_ACC);
                  break;
                default:
                  fprintf (stderr, _("Parse error in \"%s\"\n"), buf);
                  return 0;
                }
              ++cptr;
            }
          break;
        case '+':
          ++cptr;               /* Remove "=" from beginning */
          while (*cptr != '\0' && *cptr != ',')
            {
              switch (*cptr)
                {
                case 'r':
                  if (n)
                    result = result | (NIS_READ_ACC << 24);
                  if (o)
                    result = result | (NIS_READ_ACC << 16);
                  if (g)
                    result = result | (NIS_READ_ACC << 8);
                  if (w)
                    result = result | (NIS_READ_ACC);
                  break;
                case 'm':
                  if (n)
                    result = result | (NIS_MODIFY_ACC << 24);
                  if (o)
                    result = result | (NIS_MODIFY_ACC << 16);
                  if (g)
                    result = result | (NIS_MODIFY_ACC << 8);
                  if (w)
                    result = result | (NIS_MODIFY_ACC);
                  break;
                case 'c':
                  if (n)
                    result = result | (NIS_CREATE_ACC << 24);
                  if (o)
                    result = result | (NIS_CREATE_ACC << 16);
                  if (g)
                    result = result | (NIS_CREATE_ACC << 8);
                  if (w)
                    result = result | (NIS_CREATE_ACC);
                  break;
                case 'd':
                  if (n)
                    result = result | (NIS_DESTROY_ACC << 24);
                  if (o)
                    result = result | (NIS_DESTROY_ACC << 16);
                  if (g)
                    result = result | (NIS_DESTROY_ACC << 8);
                  if (w)
                    result = result | (NIS_DESTROY_ACC);
                  break;
                default:
                  fprintf (stderr, _("Parse error in \"%s\"\n"), buf);
                  return 0;
                }
              ++cptr;
            }
          break;
        case '=':
          ++cptr;               /* Remove "=" from beginning */
          /* Clear */
          if (n)
            result = result & ~((NIS_READ_ACC + NIS_MODIFY_ACC +
                                 NIS_CREATE_ACC + NIS_DESTROY_ACC) << 24);

          if (o)
            result = result & ~((NIS_READ_ACC + NIS_MODIFY_ACC +
                                 NIS_CREATE_ACC + NIS_DESTROY_ACC) << 16);
          if (g)
            result = result & ~((NIS_READ_ACC + NIS_MODIFY_ACC +
                                 NIS_CREATE_ACC + NIS_DESTROY_ACC) << 8);
          if (w)
            result = result & ~(NIS_READ_ACC + NIS_MODIFY_ACC +
                                NIS_CREATE_ACC + NIS_DESTROY_ACC);
          while (*cptr != '\0' && *cptr != ',')
            {
              switch (*cptr)
                {
                case 'r':
                  if (n)
                    result = result | (NIS_READ_ACC << 24);
                  if (o)
                    result = result | (NIS_READ_ACC << 16);
                  if (g)
                    result = result | (NIS_READ_ACC << 8);
                  if (w)
                    result = result | (NIS_READ_ACC);
                  break;
                case 'm':
                  if (n)
                    result = result | (NIS_MODIFY_ACC << 24);
                  if (o)
                    result = result | (NIS_MODIFY_ACC << 16);
                  if (g)
                    result = result | (NIS_MODIFY_ACC << 8);
                  if (w)
                    result = result | (NIS_MODIFY_ACC);
                  break;
                case 'c':
                  if (n)
                    result = result | (NIS_CREATE_ACC << 24);
                  if (o)
                    result = result | (NIS_CREATE_ACC << 16);
                  if (g)
                    result = result | (NIS_CREATE_ACC << 8);
                  if (w)
                    result = result | (NIS_CREATE_ACC);
                  break;
                case 'd':
                  if (n)
                    result = result | (NIS_DESTROY_ACC << 24);
                  if (o)
                    result = result | (NIS_DESTROY_ACC << 16);
                  if (g)
                    result = result | (NIS_DESTROY_ACC << 8);
                  if (w)
                    result = result | (NIS_DESTROY_ACC);
                  break;
                default:
                  fprintf (stderr, _("Parse error in \"%s\"\n"), buf);
                  return 0;
                }
              ++cptr;
            }
          break;
        default:
          fprintf (stderr, _("Parse error in \"%s\"\n"), buf);
          return 0;
        }
      if (*cptr != '\0')
	++cptr;
    }

  return result;
}

/* Print the version information.  */
static inline void
print_version (void)
{
  fprintf (stdout, "nistest (%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: nistest [-LMP] [-a rights] ([-t type] object | indexedname)\n"), stdout);
}

static void
print_help (void)
{
  print_usage ();
  fputs (_("nistest  -  return the state of the NIS+ namespace\n\n"),
         stdout);

  fputs (_("  -L             Follow links\n"), stdout);
  fputs (_("  -M             Query master server only\n"), stdout);
  fputs (_("  -P             Follow concatenation path\n"), stdout);
  fputs (_("  -a rights      Check for this access rights\n"), stdout);
  fputs (_("  -t type        Test, if object is from this type\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 = "nistest";

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

int
main (int argc, char *argv[])
{
  int follow_link = 0;
  int follow_path = 0;
  int master_only = 0;
  int test_rights = 0;
  int test_type = 0;
  u_long rights = 0;
  u_long flags = 0;
  zotypes type = NIS_BOGUS_OBJ;

  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'},
	{NULL, 0, NULL, '\0'}
      };

      c = getopt_long (argc, argv, "LMPa:t:", long_options, &option_index);
      if (c == (-1))
	break;
      switch (c)
	{
	case 'L':
	  follow_link = 1;
	  break;
	case 'P':
	  if (follow_link)
	    follow_path = 1;
	  else
	    {
	      fputs (_("You could use -P only after -L\n"), stderr);
	      return 2;
	    }
	  break;
	case 'M':
	  master_only = 1;
	  break;
	case 't':
	  test_type = 1;
	  switch (optarg[0])
	    {
	    case 'B':
	      type = NIS_BOGUS_OBJ;
	      break;
	    case 'D':
	      type = NIS_DIRECTORY_OBJ;
	      break;
	    case 'G':
	      type = NIS_GROUP_OBJ;
	      break;
	    case 'T':
	      type = NIS_TABLE_OBJ;
	      break;
	    case 'L':
	      type = NIS_LINK_OBJ;
	      break;
	    case 'P':
	      type = NIS_PRIVATE_OBJ;
	      break;
	    default:
	      fprintf (stderr, _("Unknwon type: %s\n"), optarg);
	      return 2;
	    }
	  break;
	case 'a':
	  {
	    char buf[strlen (optarg) + 9], *cp;

	    memset (buf, '\0', sizeof (buf));
	    cp = stpcpy (buf, "access=");
	    strcat (cp, optarg);
	    test_rights = 1;
	    rights = searchaccess (buf);
	  }
	  break;
        case '\253':
          print_help ();
          return 0;
        case '\255':
          print_version ();
          return 0;
        case '\254':
          print_usage ();
          return 0;
        default:
          print_error ();
	  return 2;
	}
    }

  argc -= optind;
  argv += optind;

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

  if (follow_link)
    flags += FOLLOW_LINKS;
  if (follow_path)
    flags += FOLLOW_PATH;
  if (master_only)
    flags += MASTER_ONLY;
  if (argv[0][strlen (argv[0]) - 1] != '.')
    flags += EXPAND_NAME;

  if (argv[0][0] == '[')	/* Indexed names! */
    {
      nis_result *res;

      if (test_type)
	{
	  fputs (_("You could not used -t type with indexed names!\n"),
		 stderr);
	  print_error ();
	  return 2;
	}

      res = nis_list (argv[0], flags, NULL, NULL);

      if (res == NULL ||
	  (res->status != NIS_SUCCESS && res->status != NIS_S_SUCCESS))
	return 1;

      if (test_rights)
	if ((rights & res->objects.objects_val->zo_access) != rights)
	  return 1;

      return 0;
    }
  else
    {
      nis_result *res;

      res = nis_lookup (argv[0], flags);
      if (res == NULL ||
	  (res->status != NIS_SUCCESS && res->status != NIS_S_SUCCESS))
	return 1;

      if (test_type)
	if (__type_of (res->objects.objects_val) != type)
	  return 1;

      if (test_rights)
	if ((rights & res->objects.objects_val->zo_access) != rights)
	  return 1;

      return 0;
    }

  return 2;
}
