/* 
   Unix SMB/Netbios implementation.
   Version 1.9.
   NBT netbios routines and daemon - version 2
   Copyright (C) Andrew Tridgell 1994-1997
   
   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 of the License, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
   
   Revision History:

   14 jan 96: lkcl@pires.co.uk
   added multiple workgroup domain master support

   04 jul 96: lkcl@pires.co.uk
   created module namedbserver containing server database functions

*/

#include "includes.h"
#include "smb.h"

extern int ClientNMB;
extern int ClientDGRAM;

extern int DEBUGLEVEL;

extern pstring myname;
extern fstring myworkgroup;

/* this is our domain/workgroup/server database */
extern struct subnet_record *subnetlist;

extern BOOL updatedlists;


/*******************************************************************
  expire old servers in the serverlist
  time of -1 indicates everybody dies except those with time of 0
  remove_all_servers indicates everybody dies.
  ******************************************************************/
void remove_old_servers(struct work_record *work, time_t t,
					BOOL remove_all)
{
  struct server_record *s;
  struct server_record *nexts;
  
  /* expire old entries in the serverlist */
  for (s = work->serverlist; s; s = nexts)
    {
      if (remove_all || (s->death_time && (t == -1 || s->death_time < t)))
	{
	  DEBUG(3,("Removing dead server %s\n",s->serv.name));
	  updatedlists = True;
	  nexts = s->next;
	  
	  if (s->prev) s->prev->next = s->next;
	  if (s->next) s->next->prev = s->prev;
	  
	  if (work->serverlist == s) 
	    work->serverlist = s->next; 

	  free(s);
	}
      else
	{
	  nexts = s->next;
	}
    }
}


/***************************************************************************
  add a server into the list
  **************************************************************************/
static void add_server(struct work_record *work,struct server_record *s)
{
  struct server_record *s2;

  if (!work->serverlist) {
    work->serverlist = s;
    s->prev = NULL;
    s->next = NULL;
    return;
  }

  for (s2 = work->serverlist; s2->next; s2 = s2->next) ;

  s2->next = s;
  s->next = NULL;
  s->prev = s2;
}


/****************************************************************************
  find a server in a server list.
  **************************************************************************/
struct server_record *find_server(struct work_record *work, char *name)
{
	struct server_record *ret;
  
	if (!work) return NULL;

	for (ret = work->serverlist; ret; ret = ret->next)
	{
		if (strequal(ret->serv.name,name))
		{
			return ret;
		}
	}
    return NULL;
}


/****************************************************************************
  add a server entry
  ****************************************************************************/
struct server_record *add_server_entry(struct subnet_record *d, 
				       struct work_record *work,
				       char *name,int servertype, 
				       int ttl,char *comment,
				       BOOL replace)
{
  BOOL newentry=False;
  struct server_record *s;
  
  if (name[0] == '*')
  {
      return (NULL);
  }
  
  s = find_server(work, name);

  if (s && !replace)
  {
    DEBUG(4,("Not replacing %s\n",name));
    return(s);
  }
  
  if (!s || s->serv.type != servertype || !strequal(s->serv.comment, comment))
    updatedlists=True;

  if (!s)
  {
    newentry = True;
    s = (struct server_record *)malloc(sizeof(*s));
      
    if (!s) return(NULL);
      
    bzero((char *)s,sizeof(*s));
  }
  
  
  /* update the entry */
  StrnCpy(s->serv.name,name,sizeof(s->serv.name)-1);
  StrnCpy(s->serv.comment,comment,sizeof(s->serv.comment)-1);
  strupper(s->serv.name);
  s->serv.type  = servertype;
  s->death_time = servertype ? (ttl?time(NULL)+ttl*3:0) : (time(NULL)-1);
  
  /* for a domain entry, the comment field refers to the server name */
  
  if (s->serv.type & SV_TYPE_DOMAIN_ENUM) strupper(s->serv.comment);
  
  if (newentry)
    {
      add_server(work, s);
      
      DEBUG(3,("Added "));
    }
  else
    {
      DEBUG(3,("Updated "));
    }
  
  DEBUG(3,("server entry %s of type %x (%s) to %s %s\n",
	   name,servertype,comment,
	   work->work_group,inet_ntoa(d->bcast_ip)));
  
  return(s);
}


/*******************************************************************
  expire old servers in the serverlist
  ******************************************************************/
void expire_servers(time_t t)
{
  struct subnet_record *d;
  
  for (d = FIRST_SUBNET; d ; d = NEXT_SUBNET_INCLUDING_WINS(d))
    {
      struct work_record *work;
      
      for (work = d->workgrouplist; work; work = work->next)
	{
	  remove_old_servers(work, t, False);
	}
    }
}

