#if !defined(lint) && !defined(__INSIGHT__)
static char sos__rcsid[] = "writeconf.c,v 1.1.1.1 1995/06/16 21:10:48 seth Exp";
static char sos__copyright[] = "Copyright (c) 1994, 1995 SOS Corporation";
static char sos__contact[] = "SOS Corporation <sos-info@soscorp.com> +1 800 SOS UNIX";
#endif /* not lint */

/*
 * ++Copyright Released Product++
 *
 * Copyright (c) 1994, 1995 Sources of Supply Corporation ("SOS").
 * All rights reserved.
 *
 * The SOS Released Product License Agreement specifies the terms and
 * conditions for redistribution.  You may find the License Agreement
 * in the file LICENSE.
 *
 * SOS Corporation
 * 461 5th Ave.; 16th floor
 * New York, NY 10017
 *
 * +1 800 SOS UNIX
 * <sos-info@soscorp.com>
 *
 * --Copyright Released Product--
 */

/*
 * Write brimstone internal ACL structures out to disk
 *
 * Reading mechinism forces multipass method of outputting data (yuk!)
 *
 * Note, this is NOT NOT NOT what the GUI uses.  Go figure.
 */

#include "sos.h"
#include "interface.h"
#include "readconf.h"


static int CopySub(FILE *out, dict_h Tbl, struct ht_args *Size, int (*writefun)(FILE *out, void *t));
static int CopySubR(FILE *, dict_h, struct ht_args *, int (*writefun)(FILE *out, void *t),dict_h, int);
static int CopyUserSub(FILE *out, dict_h Tbl, struct ht_args *Size);
static int writeTime(FILE *out, void *t);
static int writeDate(FILE *out, void *t);
static int writeAddr(FILE *out, void *t);
static int writeServ(FILE *out, void *t);
static int writeGroup(FILE *out, void *t);
static void DestroyHT(dict_h Tbl);



/*
 * Write the config file out to the listed file
 */
int
copyout(char *filename)
{
  int ret;
  FILE *out;
    
  if ((out = fopen(filename,"w")) == NULL)
    {
      sprintf(bs_auth_extended,"Cannot write output config files %s",filename);
      return(AUTH_ERROR);
    }

  /* Output flags and advisory notices */
  fprintf(out,"%%timesize %d\n",TimeSize.ht_table_entries);
  fprintf(out,"%%datesize %d\n",DateSize.ht_table_entries);
  fprintf(out,"%%addrsize %d\n",AddrSize.ht_table_entries);
  fprintf(out,"%%servsize %d\n",ServSize.ht_table_entries);
  fprintf(out,"%%groupsize %d\n",GroupSize.ht_table_entries);
  fprintf(out,"%%usersize %d\n",UserSize.ht_table_entries);

  /* Output Time ACLs */
  fprintf(out,"%%%% # Define Time ACLs\n");
  if ((ret = CopySub(out,TimeTbl,&TimeSize,writeTime)) != AUTH_SUCCEED)
    {
      fclose(out);
      unlink(filename);
      return (ret);
    }

  /* Output Date ACLs */
  fprintf(out,"%%%% # Define Date ACLs\n");
  if ((ret = CopySub(out,DateTbl,&DateSize,writeDate)) != AUTH_SUCCEED)
    {
      fclose(out);
      unlink(filename);
      return (ret);
    }

  /* Output Addr ACLs */
  fprintf(out,"%%%% # Define Addr ACLs\n");
  if ((ret = CopySub(out,AddrTbl,&AddrSize,writeAddr)) != AUTH_SUCCEED)
    {
      fclose(out);
      unlink(filename);
      return (ret);
    }

  /* Output Serv ACLs */
  fprintf(out,"%%%% # Define Serv ACLs\n");
  if ((ret = CopySub(out,ServTbl,&ServSize,writeServ)) != AUTH_SUCCEED)
    {
      fclose(out);
      unlink(filename);
      return (ret);
    }

  /* Output Group ACLs */
  fprintf(out,"%%%% # Define Group ACLs\n");
  if ((ret = CopySub(out,GroupTbl,&GroupSize,writeGroup)) != AUTH_SUCCEED)
    {
      fclose(out);
      unlink(filename);
      return (ret);
    }

  /* Output User ACLs */
  fprintf(out,"%%%% # Define Users\n");
  if ((ret = CopyUserSub(out,UserTbl,&UserSize)) != AUTH_SUCCEED)
    {
      fclose(out);
      unlink(filename);
      return (ret);
    }

  /* SUCCEED!! */
  fclose(out);
  return(AUTH_SUCCEED);
}



/*
 * Create temporary tables so that recursive version can store usage information
 */
static int
CopySub(FILE *out, dict_h Tbl, struct ht_args *Size, int (*writefun)(FILE *out, void *t))
{
  dict_h OutTbl;
  struct ht_args OutSize;
  int ret;

  memcpy((char *)&OutSize,(char *)Size,sizeof(OutSize));

  if ((OutTbl = ht_create(mystrcmp,mykeycmp,DICT_UNIQUE_KEYS,NULL,&OutSize)) == NULL)
    {
      sprintf(bs_auth_extended,"Cannot create temp hash table");
      return (AUTH_ERROR);
    }

  if (ht_insert_uniq(OutTbl,FIRSTANY,NULL) == DICT_ERR)
    {
      sprintf(bs_auth_extended,"Cannot add default entry ANY (%d)",dict_errno);
      return(AUTH_ERROR);
    }

  ret = CopySubR(out,Tbl,Size,writefun,OutTbl,0);
  DestroyHT(OutTbl);

  return(ret);
}



/*
 * Recursive version--go down eliminating indirect entries
 */
static int
CopySubR(FILE *out, dict_h Tbl, struct ht_args *Size, int (*writefun)(FILE *out, void *t),
	 dict_h OutTbl, int outcount)
{
  dict_h CacheTbl;
  struct ht_args CacheSize;
  dict_obj htcur;
  dict_obj llcur;
  int ret, init;
  int myoutcount = outcount;
  struct FirstLevel_t *f;
  struct element_t *e;

  if (bs_debug)
    {
      fprintf(stderr,"--CopySubR going down after %d\n",outcount);
    }

  memcpy((char *)&CacheSize,(char *)Size,sizeof(CacheSize));

  /* Create Cache table for unresolved entries */
  if ((CacheTbl = ht_create(mystrcmp,mykeycmp,DICT_UNIQUE_KEYS,NULL,&CacheSize)) == NULL)
    {
      sprintf(bs_auth_extended,"Cannot create temp hash table");
      return (AUTH_ERROR);
    }

  /* For every entry in hash table */
  for(htcur = ht_minimum(Tbl);htcur != NULL;htcur = ht_successor(Tbl,htcur))
    {
      f = (struct FirstLevel_t *)htcur;

      /* MAGIC COOKIE */
      if (!strcmp(f->key,"ANY"))
	continue;

      /* See if we have any unresolved references */
      for(llcur = dll_maximum(f->info);llcur != NULL;llcur = dll_predecessor(f->info,llcur))
	{
	  e = (struct element_t *)llcur;

	  if (e->meta && !ht_search(OutTbl,e->ptr.meta))
	    break;		/* Unresolve reference */
	}

      if (llcur != NULL)
	{			/* Unresolved reference */
	  if (bs_debug) fprintf(stderr,"  Unresolved reference %s (%s)\n",f->key,e->ptr.meta);
	  if (ht_insert_uniq(CacheTbl,htcur,NULL) == DICT_ERR)
	    {
	      sprintf(bs_auth_extended,"Wild error:  how can %s not be inserted?",f->key);
	      DestroyHT(CacheTbl);
	      return(AUTH_ERROR);
	    }
	  continue;		/* Can not print this out */
	}

      /* Print out record */
      fprintf(out,"%s = ",f->key);
      init = 0;
      for(llcur = dll_maximum(f->info);llcur != NULL;llcur = dll_predecessor(f->info,llcur))
	{
	  e = (struct element_t *)llcur;

	  if (init) fprintf(out,", "); init=1;
	  if (e->neg) fprintf(out,"-");
	  if (e->meta)
	    {
	      fprintf(out,"*%s",e->ptr.meta);
	      continue;
	    }
	  if ((ret = (*writefun)(out,e->ptr.generic)) != AUTH_SUCCEED)
	    {
	      DestroyHT(CacheTbl);
	      return(ret);
	    }
	}

      /* Done! */
      fprintf(out,"\n");

      if (bs_debug) fprintf(stderr,"Resolved reference to %s\n",f->key);
      if (ht_insert_uniq(OutTbl,htcur,NULL) == DICT_ERR)
	{
	  sprintf(bs_auth_extended,"Wild error:  how can %s not be inserted?",f->key);
	  DestroyHT(CacheTbl);
	  return(AUTH_ERROR);
	}
      myoutcount++;
    }

  if (ht_minimum(CacheTbl))
    {				/* Sigh--we have unresolved references */
      if (myoutcount <= outcount)
	{			/* Uh-oh we have not made progress */
	  sprintf(bs_auth_extended,"Failed to make forward progress during CopyOut");
	  DestroyHT(CacheTbl);
	  return(AUTH_ERROR);
	}

      /* RECURSE */
      ret = CopySubR(out,CacheTbl,Size,writefun,OutTbl,myoutcount);
      DestroyHT(CacheTbl);
      return(ret);
    }

  /* Really done this time */
  DestroyHT(CacheTbl);
  return (AUTH_SUCCEED);
}



/*
 * Write out a user information
 */
static int
CopyUserSub(FILE *out, dict_h Tbl, struct ht_args *Size)
{
  dict_obj htcur;
  struct userinfo_t *user;

  /* For every entry in hash table */
  for(htcur = ht_minimum(Tbl);htcur != NULL;htcur = ht_successor(Tbl,htcur))
    {
      user = (struct userinfo_t *)htcur;
      /* Always quote--saves having to test it */
      fprintf(out,"%s = %d:%s:\"%s\":*%s:%d:%d:%d:\"%s\":\"%s\":\"%s\":\"%s\"\n",
	      user->user, user->ena, user->auth, user->acode, user->group, 
	      user->create,  user->last,  user->expire, 
	      user->contact,  user->responsible,  user->GCOS,  user->comment);
    }

  return(AUTH_SUCCEED);
}



/*
 * Note--write will NEVER write out ranges that wrap, instead it will print two subranges
 */
static int
writeTime(FILE *out, void *vt)
{
  struct timeinfo_t *t = (struct timeinfo_t *)vt;
  char *days[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
  int x, save = -1;
  int init;

  fprintf(out,"(");

  /* Print out day(s) of week */
  init = 0;
  for (x=0;x < 7;x++)
    {
      if (t->day & (1 << x))
	{
	  if (save < 0)
	    save = x;
	}
      else
	{
	  if (save >= 0)
	    {
	      if (x-save > 1)
		fprintf(out,"%s%s-%s",init?",":"",days[save],days[x-1]);
	      else
		fprintf(out,"%s%s",init?",":"",days[save]);
	      init = 1;
	      save = -1;
	    }
	}
    }
  if (save >= 0)
    {
      if (x-save > 1)
	fprintf(out,"%s%s-%s",init?",":"",days[save],days[x-1]);
      else
	fprintf(out,"%s%s",init?",":"",days[save]);
    }

  fprintf(out,"/");

  /* Print out hour(s) of day */
  init = 0;
  for (x=0;x < 24;x++)
    {
      if (t->hour & (1 << x))
	{
	  if (save < 0)
	    save = x;
	}
      else
	{
	  if (save >= 0)
	    {
	      if (x-save > 1)
		fprintf(out,"%s%d-%d",init?",":"",save,x);
	      else
		fprintf(out,"%s%d",init?",":"",save);
	      init = 1;
	      save = -1;
	    }
	}
    }
  if (save >= 0)
    {
      if (x-save > 1)
	fprintf(out,"%s%d-%d",init?",":"",save,x);
      else
	fprintf(out,"%s%d",init?",":"",save);
    }

  fprintf(out,")");
  return(AUTH_SUCCEED);
}



/*
 * write a date format
 */
static int
writeDate(FILE *out, void *vt)
{
  struct dateinfo_t *t = (struct dateinfo_t *)vt;
  struct tm *utime;
  time_t clock;

  clock = t->days * 86400;

  utime = gmtime(&clock);

  fprintf(out,"(%d/%d/%d)",utime->tm_mon + 1,utime->tm_mday,utime->tm_year + 1900);

  return(AUTH_SUCCEED);
}



/*
 * Write a formatted hostmask
 */
static int
writeAddr(FILE *out, void *vt)
{
  struct addrinfo_t *t = (struct addrinfo_t *)vt;

  fprintf(out,"(%s,",inet_ntoa(t->Primary));
  fprintf(out,"%s)",inet_ntoa(t->Mask));

  return(AUTH_SUCCEED);
}



/*
 * Write a formatted service name
 */
static int
writeServ(FILE *out, void *vt)
{
  struct servinfo_t *t = (struct servinfo_t *)vt;
  struct servent *serv;
  
  if (serv = getservbyport(t->service, "tcp"))
    fprintf(out,"(\"%s\")",serv->s_name);
  else
    fprintf(out,"(%d)",t->service);

  return(AUTH_SUCCEED);
}



/*
 * Write a formatted group line
 */
static int
writeGroup(FILE *out, void *vt)
{
  struct groupinfo_t *t = (struct groupinfo_t *)vt;

  fprintf(out,"(*%s,*%s,*%s,*%s,*%s,*%s)",
	  t->metatime, t->metadate,
	  t->srcmetaaddr, t->srcmetaserv,

	  t->dstmetaaddr, t->dstmetaserv);

  return(AUTH_SUCCEED);
}



/*
 * Delete a hash table
 */
static void
DestroyHT(dict_h Tbl)
{
  dict_obj htcur;

    /* We delete as we go along, so we are always at minimum */
  for(htcur = ht_minimum(Tbl);htcur != NULL;htcur = ht_minimum(Tbl))
    ht_delete(Tbl,htcur);
  ht_destroy(Tbl);
}
