/* 
   Unix SMB/Netbios implementation.
   Version 1.9.
   NBT netbios routines to synchronise browse lists
   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.
   
*/

/* We *must have REPLACE_GETPASS defined here before the includes. */
#define REPLACE_GETPASS
#include "includes.h"

extern int ClientNMB;
extern int ClientDGRAM;

extern int DEBUGLEVEL;

extern pstring myname;

extern int name_type;
extern int max_protocol;
extern struct in_addr dest_ip;
extern int pid;
extern int gid;
extern int uid;
extern int mid;
extern BOOL got_pass;
extern BOOL have_ip;
extern pstring workgroup;
extern pstring service;
extern pstring desthost;
extern BOOL connect_as_ipc;

/****************************************************************************
fudge for getpass function
****************************************************************************/
char *getsmbpass(char *pass)
{
	return "dummy"; /* return anything: it should be ignored anyway */
}

/****************************************************************************
adds information retrieved from a NetServerEnum call
****************************************************************************/
static BOOL add_info(struct subnet_record *d, struct work_record *work, int servertype)
{
  char *rparam = NULL;
  char *rdata = NULL;
  int rdrcnt,rprcnt;
  char *p;
  pstring param;
  int uLevel = 1;
  int count = -1;
  
  /* now send a SMBtrans command with api ServerEnum? */
  p = param;
  SSVAL(p,0,0x68); /* api number */
  p += 2;
  strcpy(p,"WrLehDz");
  p = skip_string(p,1);
  
  strcpy(p,"B16BBDz");
  
  p = skip_string(p,1);
  SSVAL(p,0,uLevel);
  SSVAL(p,2,BUFFER_SIZE - SAFETY_MARGIN); /* buf length */
  p += 4;
  SIVAL(p,0,servertype);
  p += 4;
  
  pstrcpy(p, work->work_group);
  p = skip_string(p,1);
  
  if (cli_call_api(PTR_DIFF(p,param),0, 8,BUFFER_SIZE - SAFETY_MARGIN,
		   &rprcnt,&rdrcnt, param,NULL,
		   &rparam,&rdata))
    {
      int res = SVAL(rparam,0);
      int converter=SVAL(rparam,2);
      int i;
      
      if (res == 0)
	{
	  count=SVAL(rparam,4);
	  p = rdata;
	  
	  for (i = 0;i < count;i++, p += 26)
	    {
	      char *sname = p;
	      uint32 stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
	      int comment_offset = IVAL(p,22) & 0xFFFF;
	      char *cmnt = comment_offset?(rdata+comment_offset-converter):"";
	      
	      struct work_record *w = work;
	      
	      DEBUG(4, ("\t%-16.16s     %08x    %s\n", sname, stype, cmnt));
	      
	      if (stype & SV_TYPE_DOMAIN_ENUM)
		{
		  /* creates workgroup on remote subnet */
		  if ((w = find_workgroupstruct(d,sname,True)))
		    {
		      announce_request(w, d->bcast_ip);
		    }
		}
	      
          if (w)
	        add_server_entry(d,w,sname,stype,lp_max_ttl(),cmnt,False);
	    }
	}
    }
  
  if (rparam) free(rparam);
  if (rdata) free(rdata);
  
  return(True);
}


/*******************************************************************
  synchronise browse lists with another browse server.

  log in on the remote server's SMB port to their IPC$ service,
  do a NetServerEnum and update our server and workgroup databases.
  ******************************************************************/
void sync_browse_lists(struct subnet_record *d, struct work_record *work,
		char *name, int nm_type, struct in_addr ip, BOOL local)
{
  uint32 local_type = local ? SV_TYPE_LOCAL_LIST_ONLY : 0;

  if (!d || !work ) return;

  if(d != wins_subnet) {
      DEBUG(0,
        ("sync_browse_lists: ERROR sync requested on non-WINS subnet.\n"));
      return;
  }

  pid = getpid();
  uid = getuid();
  gid = getgid();
  mid = pid + 100;
  name_type = nm_type;
  
  got_pass = True;
  
  DEBUG(0,("sync_browse_lists: Sync browse lists with %s for %s %s\n",
	    name, work->work_group, inet_ntoa(ip)));
  
  strcpy(workgroup,work->work_group);
  fstrcpy(desthost,name);
  dest_ip = ip;
  
  if (zero_ip(dest_ip)) return;
  have_ip = True;
  
  connect_as_ipc = True;
  
  /* connect as server and get domains, then servers */
  
  sprintf(service,"\\\\%s\\IPC$", name);
  strupper(service);
  
  if (cli_open_sockets(SMB_PORT))
    {
      if (cli_send_login(NULL,NULL,True,True))
      {
	    add_info(d, work, local_type|SV_TYPE_DOMAIN_ENUM);
        if(local)
          add_info(d, work, SV_TYPE_LOCAL_LIST_ONLY);
        else
          add_info(d, work, SV_TYPE_ALL);
      }
      
    close_sockets();
  }
}
