#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#define _GNU_SOURCE

#include <stdio.h>
#include <rpcsvc/nis.h>
#include <locale.h>
#include <libintl.h>

#include "nisaddent.h"

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

#define TABSIZE 8

static void
tabpad (int n)
{
  int i, rest;

  if (n < 0)
    rest = 1;
  else {
    rest = n / TABSIZE;
    if (rest <= 1)
      rest++;
  }

  for (i = 0; i < rest; i++)
    putchar ('\t');
}

int 
ent_pos (char *en_name, addinfo_t *addinfo)
{
  int i;

  for (i = 0; i < INFO_MAXCOL (addinfo); i++)
    if (strcmp (en_name, INFO_COLNAME (addinfo, i)) == 0)
      return i;

  fprintf (stderr, _("%s.%s has no column named: %s\n"), 
		     addinfo->obj->zo_name, addinfo->obj->zo_domain, en_name);
  return INFO_MAXCOL (addinfo);
}

int
dump (struct addinfo_t *addinfo)
{
  char sname[NIS_MAXNAMELEN + 3 + 1];
  nis_result *res;
  int status;

  snprintf (sname, NIS_MAXNAMELEN + 3,
	    "[],%s.%s", addinfo->obj->zo_name, addinfo->obj->zo_domain);
  res = nis_list (sname, addinfo->flags, NULL, NULL);
  status = res->status;
  switch (status)
    {
    case NIS_SUCCESS:
    case NIS_S_SUCCESS:
      break;

    case NIS_PARTIAL:
    case NIS_NOTFOUND:
      fputs (_("nisaddent: Not found.\n"), stderr);
      return 1;
      break;
    case NIS_TRYAGAIN:
      fputs (_("nisaddent: NIS+ server busy, try again later.\n"), stderr);
      return 1;
      break;
    case NIS_PERMISSION:
      fputs (_("nisaddent: insufficent permission to look at sevices table\n"),
	     stderr);
      return 1;
      break;
    default:
      fprintf (stderr, _("nisaddent: error looking at sevices table, NIS+ error: %s\n"),
	       nis_sperrno (status));
      return 1;
      break;
    }

  status = addinfo->dump (res, addinfo);
  nis_freeresult (res);

  return status;
}


int
dump_generic (nis_result *res, struct addinfo_t *addinfo)
{
  int row, pos, comment_row;
  u_int col;
  nis_object *obj;

  comment_row = ent_pos ("comment", addinfo);

  for (col = 0; col < NIS_RES_NUMOBJ (res); col++)
    {
      obj = NIS_RES_OBJECT (res) + col;
      for (pos = 0; pos < INFO_MAXCOL (addinfo); pos++)
	{
	  row = addinfo->order[pos];
	  if (ENTRY_LEN (obj, row) > 0)
	    {
	      if (row == comment_row)
		printf ("# %s", ENTRY_VAL (obj, row));
	      else
		{
		  printf ("%s", ENTRY_VAL (obj, row));
		  tabpad (addinfo->width[pos] - ENTRY_LEN (obj, row));
		}
	    }
	}
      putchar ('\n');
    }
  return 1;
}

int
dump_colon (nis_result *res, struct addinfo_t *addinfo)
{
  int row, pos, passwd_row, shadow_row;
  u_int col;
  nis_object *obj;

  passwd_row = ent_pos ("passwd", addinfo);
  shadow_row = ent_pos ("shadow", addinfo);

  for (col = 0; col < NIS_RES_NUMOBJ (res); col++)
    {
      obj = NIS_RES_OBJECT (res) + col;
      pos = 0;
      while (1)
	{
	  row = addinfo->order[pos];
	  if (row == passwd_row && 
	      ENTRY_LEN (obj, row) == 0 && 
	      shadow_row != INFO_MAXCOL (addinfo))
	    putchar ('x');
	  if (ENTRY_LEN (obj, row) > 0)
	    printf ("%s", ENTRY_VAL (obj, row));

	  if (pos >= INFO_MAXCOL (addinfo) - 1 - 
	      (shadow_row != INFO_MAXCOL (addinfo)))
	    break;
	  putchar (':');
	  /* putchar (INFO_TA (addinfo).ta_sep); */
	  pos++;
	}
      putchar ('\n');
    }
  return 1;
}

int
dump_mltcn (nis_result *res, struct addinfo_t *addinfo)
{
  int row, pos, cname_row, name_row, comment_row, len;
  u_int col, done_i;
  nis_object *obj, *cnt_obj;

  cname_row = ent_pos ("cname", addinfo);
  name_row = ent_pos ("name", addinfo);
  comment_row = ent_pos ("comment", addinfo);

  for (col = 0; col < NIS_RES_NUMOBJ (res); col++)
    {
      obj = NIS_RES_OBJECT (res) + col;
      if (__type_of (obj) == BOGUS_OBJ)
	  continue;

      for (pos = 0; pos < INFO_MAXCOL (addinfo); pos++)
	{
	  row = addinfo->order[pos];
	  if (ENTRY_LEN (obj, row) < 1)
	    {
	      tabpad (addinfo->width[pos]); 
	      continue;
	    }

	  if (row == cname_row)
	    {
	      len = 0;
	      if (strcmp (ENTRY_VAL (obj, name_row), 
			  ENTRY_VAL (obj, cname_row)))
		{
		  printf ("%s ", ENTRY_VAL (obj, cname_row));
		  len += ENTRY_LEN (obj, cname_row) + 1;
		}

	      for (cnt_obj = obj + 1, done_i = col + 1; 
		   done_i < NIS_RES_NUMOBJ (res); 
		   done_i++, cnt_obj++)
		{
		  if (__type_of (cnt_obj) == BOGUS_OBJ)
		    continue;
		  if (strcmp (ENTRY_VAL (obj, name_row), 
			      ENTRY_VAL (cnt_obj, cname_row)) == 0)
		    {
		      printf ("%s ", ENTRY_VAL (cnt_obj, name_row));
		      len += ENTRY_LEN (cnt_obj, name_row) + 1;
		      __type_of (cnt_obj) = BOGUS_OBJ;
		    }
		  else if (strcmp (ENTRY_VAL (obj, name_row), 
				   ENTRY_VAL (cnt_obj, name_row)) == 0)
		    __type_of (cnt_obj) = BOGUS_OBJ;
		}
	      tabpad (addinfo->width[pos] - len); 
	    }
	  else if (row == comment_row)
	    printf ("# %s", ENTRY_VAL (obj, row));
	  else
	    {
	      printf ("%s", ENTRY_VAL (obj, row));
	      tabpad (addinfo->width[pos] - ENTRY_LEN (obj, row));
	    }
	}
      putchar ('\n');
    }
  return 1;
}

int
dump_serv (nis_result *res, struct addinfo_t *addinfo)
{
  int row, pos, len;
  u_int col, done_i;
  nis_object *obj, *cnt_obj;

  for (col = 0; col < NIS_RES_NUMOBJ (res); col++)
    {
      obj = NIS_RES_OBJECT (res) + col;
      if (__type_of (obj) == BOGUS_OBJ)
	  continue;

      for (pos = 0; pos < INFO_MAXCOL (addinfo); pos++)
	{
	  row = addinfo->order[pos];
	  if (ENTRY_LEN (obj, row) < 1)
	    {
	      tabpad (addinfo->width[pos]); 
	      continue;
	    }

	  switch (row)
	    {
	    case 0: /* cname */
	      len = 0;
	      if (strcmp (ENTRY_VAL (obj, 0), 
			  ENTRY_VAL (obj, 1)))
		{
		  printf ("%s ", ENTRY_VAL (obj, 0));
		  len += ENTRY_LEN (obj, 0) + 1;
		}

	      for (cnt_obj = obj + 1, done_i = col + 1;
		   done_i < NIS_RES_NUMOBJ (res); 
		   done_i++, cnt_obj++)
		{
		  if (__type_of (cnt_obj) == BOGUS_OBJ)
		    continue;
		  if (strcmp (ENTRY_VAL (obj, 1), 
			      ENTRY_VAL (cnt_obj, 0)) == 0 &&
		      strcmp (ENTRY_VAL (obj, 2), 
			      ENTRY_VAL (cnt_obj, 2)) == 0 &&
		      cnt_obj != obj)
		    {
		      printf ("%s ", ENTRY_VAL (cnt_obj, 1));
		      len += ENTRY_LEN (cnt_obj, 1) + 1;
		      __type_of (cnt_obj) = BOGUS_OBJ;
		    }
		  else if (strcmp (ENTRY_VAL (obj, 1), 
				   ENTRY_VAL (cnt_obj, 1)) == 0 &&
			   strcmp (ENTRY_VAL (obj, 2), 
				   ENTRY_VAL (cnt_obj, 2)) == 0)
		    __type_of (cnt_obj) = BOGUS_OBJ;
		}
	      tabpad (addinfo->width[pos] - len); 
	      break;
	    case 2: /* proto, look below */
	      break;
	    case 3: /* port */
	      printf ("%s/%s", ENTRY_VAL (obj, row), ENTRY_VAL (obj, 2));
	      tabpad (addinfo->width[1] + addinfo->width[2]
		      - ENTRY_LEN (obj, row) -  ENTRY_LEN (obj, 2));
	      break;
	    case 4: /* comment */
	      printf ("# %s", ENTRY_VAL (obj, row));
	      break;
	    default:
	      printf ("%s", ENTRY_VAL (obj, row));
	      tabpad (addinfo->width[pos] - ENTRY_LEN (obj, row));
	      break;
	    }
	}
      putchar ('\n');
    }
  return 1;
}
