/* Copyright (C) 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

#include <pwd.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#else
#include "lib/compat/getopt.h"
#endif
#include <locale.h>
#include <libintl.h>
#include <rpcsvc/nis.h>

#define _NEEDS_SPECINFO_DEF_
#include "nisaddent.h"

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

/* Print the version information.  */
static inline void
print_version (void)
{
  fprintf (stdout, "nisaddent (%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: nisaddent [-D defaults] [-Parv] [-t table] type [nisdomain]\n"),
	 stdout);
  fputs (_("       nisaddent [-D defaults] [-Pamprv] -f file [-t table] type [nisdomain]\n"),
	 stdout);
  fputs (_("       nisaddent [-D defaults] [-Pamrv] [-t table] -y ypdomain [-Y map] type [nisdomain]\n"),
	 stdout);
  fputs (_("       nisaddent -d [-AMq] [-t table] type [nisdomain]\n"), stdout);
}

static void
print_help (void)
{
  fputs (_("Usage: nisaddent [OPTION...] type [nisdomain]\n"), stdout);
  fputs (_("nisaddent - create NIS+ tables from corresponding files or NIS maps\n\n"),
	 stdout);

  fputs (_("  -a             Add the file or map to the NIS+ table\n"),
	 stdout);
  fputs (_("  -p             Don't ignore password field from passwd file\n"),
	 stdout);
  fputs (_("  -q             Dump tables in \"quick\" mode\n"), stdout);
  fputs (_("  -r             Delete at first all entries in the NIS+ table\n"),
	 stdout);
  fputs (_("  -m             Merge the file or map with the NIS+ table\n"),
	 stdout);
  fputs (_("  -d             Dump the NIS+ table to the standard output\n"),
	 stdout);
  fputs (_("  -f file        Specify that file should be used as input source\n"), stdout);
  fputs (_("  -y ypdomain    Use the appropriate NIS map from this NIS domain\n"), stdout);
  fputs (_("  -Y map         Use NIS map \"map\"  as input source\n"), stdout);
  fputs (_("  -t table       Specify that \"table\" should be the NIS+ table\n"), stdout);
  fputs (_("  -P             Follow concatenation path\n"), stdout);
  fputs (_("  -D defaults    Specifies a different set of defaults to be used\n"), stdout);
  fputs (_("  -v, --verbose  Verbose mode\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);

  fputs (_("\nSupported types are group, passwd and shadow.\n"), stdout);
}

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

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

static addinfo_t *
init_addinfo (addmode_t mode, char *entname, char *nisdomain, u_int flags,
	      char *defaults, char *tablename, char *rfrom, char *ypmap)
{
  static addinfo_t addinfo;
  char sname[NIS_MAXNAMELEN + 1], *leafname;
  nis_result *res;
  int i;

  if (strcmp (entname, "shadow") == 0)
    leafname = "passwd";
  else 
    leafname = entname;

  snprintf (sname, NIS_MAXNAMELEN, "%s.org_dir.%s", leafname, nisdomain);
  if (sname[strlen (sname) - 1] != '.')
    strcat (sname, ".");
  res = nis_lookup (sname, flags);
  if (res == NULL)
    {
      fputs (_("Out of memory!\n"), stderr);
      return NULL;
    }
  if (NIS_RES_STATUS (res) != NIS_SUCCESS)
    {
      nis_perror (res->status, _("Could not find table."));
      nis_freeresult (res);
      return NULL;
    }
  if (res->objects.objects_val->zo_data.zo_type != TABLE_OBJ)
    {
      fprintf (stderr, _("%s is not table object.\n"), sname);
      nis_freeresult (res);
      return NULL;
    }
  addinfo.obj = nis_clone_object (res->objects.objects_val, addinfo.obj);
  nis_freeresult (res);

  /* set parse and dump function */
  for (i = 0; specinfo[i].entname; i++)
    if (strcmp (entname, specinfo[i].entname) == 0)
      break;
  if (specinfo[i].entname == NULL)
    {
      fprintf (stderr,
	       _("Sorry, table [%s] is not implemented\n"), entname);
      nis_destroy_object (addinfo.obj);
      return NULL;
    }
  addinfo.parse = specinfo[i].parse;
  addinfo.dump = specinfo[i].dump;
  addinfo.order = specinfo[i].order;
  addinfo.width = specinfo[i].width;
  addinfo.mode = mode;
  addinfo.flags = flags;

  if (mode & IS_DUMP)
    return &addinfo;

  /* entry addition specific */
  /* set srchb and regent func */
  if (strcmp (entname, "shadow") == 0) /* compare twice */
    {
      addinfo.regent = regent_shadow;
      INFO_FLAGS (&addinfo, 0) &= TA_SEARCHABLE;
      INFO_FLAGS (&addinfo, 1) &= ~TA_SEARCHABLE;
      INFO_FLAGS (&addinfo, 2) &= ~TA_SEARCHABLE;
      INFO_FLAGS (&addinfo, 3) &= ~TA_SEARCHABLE;
      INFO_FLAGS (&addinfo, 4) &= ~TA_SEARCHABLE;
      INFO_FLAGS (&addinfo, 5) &= ~TA_SEARCHABLE;
      INFO_FLAGS (&addinfo, 6) &= ~TA_SEARCHABLE;
      INFO_FLAGS (&addinfo, 7) &= ~TA_SEARCHABLE;
    }
  else 
    {
      if (strcmp (entname, "passwd") == 0 && mode & ~USE_PASSWD)
	addinfo.regent = regent_passwd;
      else
	addinfo.regent = regent_generic;
    }
  
  /* set rfrom */
  if (mode & USE_YP)
    {
      if (ypmap)
	addinfo.aq_from.ypinfo.ypmap = ypmap;
      else
	addinfo.aq_from.ypinfo.ypmap = specinfo[i].ypmap;
      addinfo.aq_from.ypinfo.ypdomain = rfrom;
      addinfo.getline = getline_yp;
    }
  else if (mode & USE_FILE)
    {
      addinfo.aq_from.input = fopen (rfrom, "rb");
      if (addinfo.aq_from.input == NULL)
	{
	  fprintf (stderr, _("Could not open file: %s\n"), strerror (errno));
	  nis_destroy_object (addinfo.obj);
	  return NULL;
	}
      addinfo.getline = getline_file;
    }
  else 
    {
      addinfo.aq_from.input = stdin;
      addinfo.getline = getline_file;
    }
  
  if (defaults)
    {
      char *dtoken;
      
      while ((dtoken = strtok (defaults, ",")) != NULL)
	{
	  if (strncmp (dtoken, "ttl", 3) == 0)
	    addinfo.obj->zo_ttl = __nis_default_ttl (dtoken);
	  else if (strncmp (dtoken, "owner", 5) == 0)
	    addinfo.obj->zo_owner = __nis_default_owner (dtoken);
	  else if (strncmp (dtoken, "group", 5) == 0)
	    addinfo.obj->zo_group = __nis_default_group (dtoken);
	  else if (strncmp (dtoken, "access", 6) == 0 && 
		   strcmp (leafname, "passwd") != 0)
	    addinfo.obj->zo_access = __nis_default_access (dtoken, 0);
	  else
	    {
	      fprintf (stderr, _("No properties: %s.\n"), dtoken);
	      nis_destroy_object (addinfo.obj);
	      return NULL;
	    }
	  defaults = NULL;
	}
    }

  /* I don't know what is effected by after below */
  if (tablename)
    addinfo.obj->zo_data.objdata_u.ta_data.ta_type = tablename;

  return &addinfo;
}

int
main (int argc, char **argv)
{
  char *defaults = NULL, *rfrom = NULL, *ypmap = NULL, *tablename = NULL;
  char *nisdomain;
  u_int flags = EXPAND_NAME | FOLLOW_LINKS;
  int quick_dump = 0;
  addmode_t mode = NOT_SET;
  addinfo_t *addinfo;

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

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

      c = getopt_long (argc, argv, "D:Paprmvt:f:y:Y:dAMq", 
		       long_options, &option_index);
      if (c == (-1))
        break;
      switch (c)
        {
	case 'D':
	  defaults = optarg;
	  break;
	case 'a': 
	  /* Is the default, we set it for error checking, else ignore it */
	  mode |= MODIFY;
	  break;
	case 'p':
	  mode |= USE_PASSWD;
	  break;
	case 'r':
	  mode |= CREATE;
	  break;
	case 'm':
	  mode |= UPDATE;
	  break;
	case 'v':
	  mode |= VERBOSE;
	  break;
	case 't':
	  tablename = optarg;
	  break;
	case 'f':
	  rfrom = optarg;
	  mode |= USE_FILE;
	  break;
	case 'y':
	  rfrom = optarg;
	  mode |= USE_YP;
	  break;
	case 'Y':
	  ypmap = optarg;
	  break;
	case 'd':
	  mode |= IS_DUMP;
	  break;
	case 'P':
	  flags |= FOLLOW_PATH;
	  break;
	case 'A':
	  flags |= ALL_RESULTS;
	  break;
	case 'M':
	  flags |= MASTER_ONLY;
	  break;
	case 'q':
	  quick_dump = 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 ((defaults != NULL && 
       (mode & IS_DUMP || 
	flags & ALL_RESULTS || 
	flags & MASTER_ONLY || 
	quick_dump)
       ) ||
      (mode & USE_FILE && 
       (mode & IS_DUMP || 
	flags & ALL_RESULTS || 
	flags & MASTER_ONLY || 
	quick_dump || 
	ypmap != NULL || 
	mode & USE_YP)
       ) ||
      (argc < 1 || argc > 2))
    {
      fprintf (stderr, _("%s: Wrong number of arguments\n"), "nisaddent");
      print_error ();
      return 1;
    }
  
  if (defaults == NULL)
    defaults = getenv ("NIS_DEFAULTS");

  if (argc == 2)
    {  
      nisdomain = argv[1];
      /*
       * if (nisdomain[strlen (nisdomain) - 1] != '.' &&
       *     (tablename == NULL || tablename[strlen (tablename) - 1] != '.') &&
       *     getenv("NIS_PATH"))
       *     {
       *        what store and is stored by nis_getnames?
       *     }
       */
    }
  else
    nisdomain = nis_local_directory ();
  
  addinfo = init_addinfo (mode, argv[0], nisdomain, flags, defaults,
			  tablename, rfrom, ypmap);
  if (addinfo == NULL)
    exit (1);

  if (mode & IS_DUMP)
    return dump (addinfo);
  else
    return insert (addinfo);

  return 1;
}
