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

#include <locale.h>
#include <libintl.h>
#include <rpcsvc/nis.h>
#include "nis_db.h"
#include "nis_xdr.h"
#include "nisd.h"
#include "log_msg.h"

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

/* We create a new table. As parameter we expect the short
   name of the table, not the fully qualified one */
db_status
db_create_dir (const_nis_name name)
{
  table_obj dir_table;
  table_col dir_col[2];

  if (db_table_exists (name) == DB_SUCCESS)
    return DB_NOTUNIQUE;

  dir_table.ta_type = "directory_tbl";
  dir_table.ta_maxcol = 2;
  dir_table.ta_sep = ' ';
  dir_table.ta_path = "";

  dir_col[0].tc_name = "IN_DIRECTORY";
  dir_col[0].tc_flags = TA_SEARCHABLE;
  dir_col[0].tc_rights = DEFAULT_RIGHTS;

  dir_col[1].tc_name = "xdr_nis_object";
  dir_col[1].tc_flags = TA_BINARY | TA_XDR;
  dir_col[1].tc_rights = DEFAULT_RIGHTS;

  dir_table.ta_cols.ta_cols_len = 2;
  dir_table.ta_cols.ta_cols_val = (table_col *)&dir_col;

  return db_create_table (name, &dir_table);
}


#define OBJ_VAL(PTR,O,C) \
 PTR->objects.objects_val[O]->en_cols.en_cols_val[C].ec_value.ec_value_val
#define OBJ_LEN(PTR,O,C) \
 PTR->objects.objects_val[O]->en_cols.en_cols_val[C].ec_value.ec_value_len

/* Note: must be free()'ed later! */
/* XXX */
static inline nis_object *
nis_decode_nis_obj (char *addr, u_long size)
{
  XDR xdrs;
  nis_object *obj;

  if ((obj = calloc (1, sizeof (nis_object))) == NULL)
    return NULL;

  xdrmem_create (&xdrs, addr, size, XDR_DECODE);
  if (!xdr_nis_object (&xdrs, obj))
    {
      xdr_destroy (&xdrs);
      free (obj);
      return NULL;
  }
  xdr_destroy (&xdrs);

  return obj;
}

nis_result *
db_lookup (const_nis_name name)
{
  DATABASE_CLOCK_DECLS;
  char *lname, *db_name;
  nis_attr attr;
  db_result *db_res;
  nis_result *res;
  db_status db_stat;

  start_clock (DATABASE_CLOCK);

  res = calloc (1, sizeof (nis_result));
  if (res == NULL)
    return NULL;

  /* Sometimes we are asked to look up the root object.
     The root object is stored in a file by itself rather
     than as part of a directory, so we have to handle it
     specially. */

  if (nis_dir_cmp (name, root_obj->DI_data.do_name) == SAME_NAME)
    {
      start_clock (DATABASE_CLOCK);

      if (root_obj == NULL)
	db_stat = DB_NOTFOUND;
      else
	{
	  NIS_RES_OBJECT (res) = nis_clone_object (root_obj, NULL);
	  NIS_RES_NUMOBJ (res) = 1;
	  db_stat = DB_SUCCESS;
	}

      res->status = db2nis_error (db_stat);
      res->dticks = stop_clock (DATABASE_CLOCK);

      return res;
    }

  /* XXX not thread safe */
  db_name = nis_name_of (name);
  lname = nis_leaf_of (name);

  /* We search the object, so truncate the object name from the
     db_name and use the rest as table name. */
  if (strcmp (db_name, lname ) == 0)
    db_name = strdup ("root_dir");
  else
    {
      char *cp;

      cp = strchr (db_name, '.');
      if (cp == NULL)
	{
	  res->status = NIS_NAMEUNREACHABLE;
	  res->dticks = stop_clock (DATABASE_CLOCK);
	  return res;
	}
      ++cp;
      db_name = strdup (cp);
    }

  db_stat = db_table_exists (db_name);

  if (db_stat != DB_SUCCESS)
    {
      res->status = db2nis_error (db_stat);
      res->dticks = stop_clock (DATABASE_CLOCK);
      return res;
    }

  attr.zattr_ndx = "IN_DIRECTORY";
  attr.zattr_val.zattr_val_val = lname;

  attr.zattr_val.zattr_val_len = strlen (lname);

  db_res = db_list_entries (db_name, 1, &attr);
  /*free (db_name);*/

  if (db_res == NULL)
    {
      res->status = NIS_NOMEMORY;
      res->dticks = stop_clock (DATABASE_CLOCK);
      return res;
    }

  if (db_res->status != DB_SUCCESS)
    {
      res->status = db2nis_error (db_res->status);
      db_free_result (db_res);
      res->dticks = stop_clock (DATABASE_CLOCK);
      return res;
    }

  NIS_RES_NUMOBJ(res) = 1;
  NIS_RES_OBJECT(res) = nis_decode_nis_obj(OBJ_VAL(db_res, 0, 1),
					   OBJ_LEN(db_res, 0, 1));

  res->status = db2nis_error (db_res->status);
  db_free_result (db_res);
  res->dticks = stop_clock(DATABASE_CLOCK);

  return res;
}
