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

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

static int d_flag = 0;
static int recursive_flag = 0;
static int printlong_flag = 0;
static int printgroup_flag = 0;
static int printmodtime_flag = 0;

static void
print_long (nis_object *obj)
{
  time_t tbuf;
  char buf[60];

  switch (__type_of (obj))
    {
    case NIS_NO_OBJ:
      printf ("N ");
      break;
    case NIS_DIRECTORY_OBJ:
      printf ("D ");
      break;
    case NIS_GROUP_OBJ:
      printf ("G ");
      break;
    case NIS_TABLE_OBJ:
      printf ("T ");
      break;
    case NIS_ENTRY_OBJ:
      printf ("E ");
      break;
    case NIS_LINK_OBJ:
      printf ("L ");
      break;
    case NIS_PRIVATE_OBJ:
      printf ("P ");
      break;
    case NIS_BOGUS_OBJ:
    default:
      printf ("B ");
      break;
    }
  nis_print_rights (obj->zo_access);
  if (printgroup_flag)
    printf (" %s ", obj->zo_group);
  else
    printf (" %s ", obj->zo_owner);
  if (printmodtime_flag)
    {
      tbuf = obj->zo_oid.ctime;
      sprintf (buf, "%s", ctime (&tbuf));
    }
  else
    {
      tbuf = obj->zo_oid.mtime;
      sprintf (buf, "%s", ctime (&tbuf));
    }
  buf[strlen (buf) - 1] = '\0';
  if (__type_of (obj) == NIS_DIRECTORY_OBJ)
    printf ("%s %s.%s\n", buf, obj->zo_name, obj->zo_domain);
  else
    printf ("%s %s\n", buf, obj->zo_name);
}

static void
ls (nis_name dir, u_long flags)
{
  nis_result *res;

  if (!d_flag)
  printf ("%s:\n", dir);

  res = nis_lookup (dir, flags);

  if (res == NULL ||
      (res->status != NIS_SUCCESS && res->status != NIS_S_SUCCESS))
    {
      if (res == NULL)
	fputs (_("Out of memory!\n"), stderr);
      else
	{
	  nis_perror (res->status, _("Can't list directory"));
	  nis_freeresult (res);
	}
      exit (1);
    }
  if (__type_of (res->objects.objects_val) == NIS_DIRECTORY_OBJ && !d_flag)
    {
      unsigned int i;

      nis_freeresult (res);
      res = nis_list (dir, flags, NULL, NULL);
      if (res == NULL || (res->status != NIS_SUCCESS &&
			  res->status != NIS_S_SUCCESS &&
			  res->status != NIS_PARTIAL))
	{
	  if (res == NULL)
	    fputs (_("Out of memory!\n"), stderr);
	  else
	    {
	      nis_perror (res->status, dir);
	      nis_freeresult (res);
	    }
	  exit (1);
	}
      if (res->status != NIS_PARTIAL)
	{
	  for (i = 0; i < res->objects.objects_len; ++i)
	    {
	      if (printlong_flag)
		print_long (&res->objects.objects_val[i]);
	      else
		printf ("%s\n", res->objects.objects_val[i].zo_name);
	    }

	  if (recursive_flag)
	    {
	      for (i = 0; i < res->objects.objects_len; ++i)
		if (res->objects.objects_val[i].zo_name != NULL)
		  {
		    char buf[strlen (dir) + 3 +
			    strlen (res->objects.objects_val[i].zo_name)];

		    strcpy (buf, res->objects.objects_val[i].zo_name);
		    strcat (buf, ".");
		    strcat (buf, dir);

		    if (ntohl(*(zotypes *)ENTRY_VAL (&res->objects.objects_val[i],0))
			== NIS_DIRECTORY_OBJ)
		      {
			fputs ("\n", stdout);
			ls (buf, flags);
		      }
		  }
	    }
	}
    }
  else if (printlong_flag)
    print_long (res->objects.objects_val);
  else
    printf ("%s\n", dir);

  nis_freeresult (res);
}

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

static inline  void
print_help (void)
{
  print_usage ();
  fputs (_("nisls - list the contents of a NIS+ directory\n\n"),
         stdout);

  fputs (_("  -d             Treat NIS+ directories like other objects\n"),
	 stdout);
  fputs (_("  -g             Show the group owner instead of principal\n"),
	 stdout);
  fputs (_("  -l             Show objects in long format\n"), stdout);
  fputs (_("  -L             Follow links\n"), stdout);
  fputs (_("  -m             Display modification instead of creating time\n"),
	 stdout);
  fputs (_("  -M             Query master server only\n"), stdout);
  fputs (_("  -R             List directories recursively\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 = "nisls";

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


int
main (int argc, char *argv[])
{
  int follow_links = 0;
  int master_only = 0;
  u_long flags = 0;

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

      c = getopt_long (argc, argv, "dglLmMR", long_options, &option_index);
      if (c == (-1))
	break;
      switch (c)
	{
	case 'd':
	  d_flag = 1;
	  break;
	case 'g':
	  printgroup_flag = 1;
	  break;
	case 'l':
	  printlong_flag = 1;
	  break;
	case 'L':
	  follow_links = 1;
	  break;
	case 'm':
	  printmodtime_flag = 1;
	  break;
	case 'M':
	  master_only = 1;
	  break;
	case 'R':
	  recursive_flag = 1;
	  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 (follow_links)
    flags += FOLLOW_LINKS;
  if (master_only)
    flags += MASTER_ONLY;
  if (argc > 0 && argv[0][strlen (argv[0]) - 1] != '.')
    flags += EXPAND_NAME;

  if (argc > 0)
    {
      int i;

      for (i = 0; i < argc; i++)
	ls (argv[i], flags);
    }
  else
    {
      nis_name *ptr;

      ptr = nis_getnames ("");
      if (ptr && ptr[0])
	ls (ptr[0] + 1, flags);
      nis_freenames (ptr);
    }

  return 0;
}
