client.c: Changed shadowed variable.
[kai/samba.git] / source3 / client / client.c
index 504cb5a0bb4609ddfa88c6b2c4c078f54b50c96a..6d85bd8807fe4a5419b51d5f9f93544a280a83f2 100644 (file)
@@ -2,7 +2,7 @@
    Unix SMB/Netbios implementation.
    Version 1.9.
    SMB client
-   Copyright (C) Andrew Tridgell 1994-1995
+   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
@@ -24,7 +24,6 @@
 #endif
 
 #include "includes.h"
-#include "nameserv.h"
 
 #ifndef REGISTER
 #define REGISTER 0
@@ -34,15 +33,16 @@ pstring cur_dir = "\\";
 pstring cd_path = "";
 pstring service="";
 pstring desthost="";
-pstring myname = "";
+extern pstring myname;
+extern pstring myhostname;
 pstring password = "";
 pstring username="";
-pstring workgroup=WORKGROUP;
+pstring workgroup="";
+char *cmdstr="";
 BOOL got_pass = False;
 BOOL connect_as_printer = False;
 BOOL connect_as_ipc = False;
-extern struct in_addr bcast_ip;
-static BOOL got_bcast=False;
+extern struct in_addr ipzero;
 
 char cryptkey[8];
 BOOL doencrypt=False;
@@ -64,23 +64,34 @@ int max_protocol = PROTOCOL_NT1;
 time_t newer_than = 0;
 int archive_level = 0;
 
-extern struct in_addr myip;
-
 extern pstring debugf;
 extern int DEBUGLEVEL;
 
 BOOL translation = False;
 
+
+static BOOL send_trans_request(char *outbuf,int trans,
+                              char *name,int fid,int flags,
+                              char *data,char *param,uint16 *setup,
+                              int ldata,int lparam,int lsetup,
+                              int mdata,int mparam,int msetup);
+static BOOL receive_trans_response(char *inbuf,int trans,
+                                   int *data_len,int *param_len,
+                                  char **data,char **param);
+static int interpret_long_filename(int level,char *p,file_info *finfo);
+static void dir_action(char *inbuf,char *outbuf,int attribute,file_info *finfo,BOOL recurse_dir,void (*fn)(),BOOL longdir);
+static int interpret_short_filename(char *p,file_info *finfo);
+static BOOL call_api(int prcnt,int drcnt,
+                    int mprcnt,int mdrcnt,
+                    int *rprcnt,int *rdrcnt,
+                    char *param,char *data,
+                    char **rparam,char **rdata);
+static BOOL do_this_one(file_info *finfo);
+
 /* clitar bits insert */
-extern void cmd_tar();
-extern void cmd_block();
-extern void cmd_tarmode();
-extern void cmd_setmode();
 extern int blocksize;
 extern BOOL tar_inc;
 extern BOOL tar_reset;
-extern int process_tar();
-extern int tar_parseargs();
 /* clitar bits end */
  
 
@@ -125,17 +136,15 @@ int get_total_time_ms = 0;
 int put_total_size = 0;
 int put_total_time_ms = 0;
 
+/* totals globals */
+int dir_total = 0;
 
 extern int Client;
 
 #define USENMB
 
-#ifdef KANJI
 extern int coding_system;
-#define CNV_LANG(s) (coding_system == DOSV_CODE?s:dos_to_unix(s, False))
-#define CNV_INPUT(s) (coding_system == DOSV_CODE?s:unix_to_dos(s, True))
-static BOOL
-setup_term_code (char *code)
+static BOOL setup_term_code (char *code)
 {
     int new;
     new = interpret_coding_system (code, UNKNOWN_CODE);
@@ -145,24 +154,8 @@ setup_term_code (char *code)
     }
     return False;
 }
-#else
 #define CNV_LANG(s) dos2unix_format(s,False)
 #define CNV_INPUT(s) unix2dos_format(s,True)
-#endif
-
-static void send_logout(void );
-BOOL reopen_connection(char *inbuf,char *outbuf);
-static int do_long_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir);
-static int do_short_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir);
-static BOOL call_api(int prcnt,int drcnt,int mprcnt,int mdrcnt,
-                    int *rprcnt,int *rdrcnt,char *param,char *data,
-                    char **rparam,char **rdata);
-static BOOL send_trans_request(char *outbuf,int trans,
-                              char *name,int fid,int flags,
-                              char *data,char *param,uint16 *setup,
-                              int ldata,int lparam,int lsetup,
-                              int mdata,int mparam,int msetup);
-
 
 /****************************************************************************
 setup basics in a outgoing packet
@@ -172,7 +165,7 @@ void setup_pkt(char *outbuf)
   SSVAL(outbuf,smb_pid,pid);
   SSVAL(outbuf,smb_uid,uid);
   SSVAL(outbuf,smb_mid,mid);
-  if (Protocol > PROTOCOL_CORE)
+  if (Protocol > PROTOCOL_COREPLUS)
     {
       SCVAL(outbuf,smb_flg,0x8);
       SSVAL(outbuf,smb_flg2,0x1);
@@ -234,7 +227,8 @@ static int readfile(char *b, int size, int n, FILE *f)
          n++;
        }
       
-      b[i++] = c;
+      if(i < n)
+        b[i++] = c;
     }
   
   return(i);
@@ -281,6 +275,18 @@ static BOOL chkpath(char *path,BOOL report)
   *p++ = 4;
   strcpy(p,path2);
 
+#if 0
+  {
+         /* this little bit of code can be used to extract NT error codes.
+            Just feed a bunch of "cd foo" commands to smbclient then watch
+            in netmon (tridge) */
+         static int code=0;
+         SIVAL(outbuf, smb_rcls, code | 0xC0000000);
+         SSVAL(outbuf, smb_flg2, SVAL(outbuf, smb_flg2) | (1<<14));
+         code++;
+  }
+#endif
+
   send_smb(Client,outbuf);
   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
 
@@ -477,209 +483,188 @@ static void cmd_cd(char *inbuf,char *outbuf)
   ****************************************************************************/
 static void display_finfo(file_info *finfo)
 {
-  time_t t = finfo->mtime; /* the time is assumed to be passed as GMT */
-  DEBUG(0,("  %-30s%7.7s%10d  %s",
-          CNV_LANG(finfo->name),
+  if (do_this_one(finfo)) {
+    time_t t = finfo->mtime; /* the time is assumed to be passed as GMT */
+    DEBUG(0,("  %-30s%7.7s%10d  %s",
+          CNV_LANG(finfo->name),
           attrib_string(finfo->mode),
           finfo->size,
-          asctime(LocalTime(&t,GMT_TO_LOCAL))));
+          asctime(LocalTime(&t))));
+    dir_total += finfo->size;
+  }
 }
 
+
 /****************************************************************************
-  do a directory listing, calling fn on each file found
+  do a directory listing, calling fn on each file found. Use the TRANSACT2
+  call for long filenames
   ****************************************************************************/
-void do_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir)
-{
-  DEBUG(5,("do_dir(%s,%x,%s)\n",Mask,attribute,BOOLSTR(recurse_dir)));
-  if (Protocol >= PROTOCOL_LANMAN2)
-    {
-      if (do_long_dir(inbuf,outbuf,Mask,attribute,fn,recurse_dir) > 0)
-       return;
-    }
-
-  expand_mask(Mask,False);
-  do_short_dir(inbuf,outbuf,Mask,attribute,fn,recurse_dir);
-  return;
-}
-
-/*******************************************************************
-  decide if a file should be operated on
-  ********************************************************************/
-static BOOL do_this_one(file_info *finfo)
+static int do_long_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir)
 {
-  if (finfo->mode & aDIR) return(True);
-
-  if (newer_than && finfo->mtime < newer_than)
-    return(False);
-
-  if ((archive_level==1 || archive_level==2) && !(finfo->mode & aARCH))
-    return(False);
-
-  return(True);
-}
+  int max_matches = 512;
+  int info_level = Protocol<PROTOCOL_NT1?1:260; /* NT uses 260, OS/2 uses 2. Both accept 1. */
+  char *p;
+  pstring mask;
+  file_info finfo;
+  int i;
+  char *dirlist = NULL;
+  int dirlist_len = 0;
+  int total_received = 0;
+  BOOL First = True;
+  char *resp_data=NULL;
+  char *resp_param=NULL;
+  int resp_data_len = 0;
+  int resp_param_len=0;
 
-/****************************************************************************
-interpret a short filename structure
-The length of the structure is returned
-****************************************************************************/
-static int interpret_short_filename(char *p,file_info *finfo)
-{
-  finfo->mode = CVAL(p,21);
+  int ff_resume_key = 0;
+  int ff_searchcount=0;
+  int ff_eos=0;
+  int ff_lastname=0;
+  int ff_dir_handle=0;
+  int loop_count = 0;
 
-  /* this date is converted to GMT by make_unix_date */
-  finfo->ctime = make_unix_date(p+22);
-  finfo->mtime = finfo->atime = finfo->ctime;
-  finfo->size = IVAL(p,26);
-  strcpy(finfo->name,p+30);
-  
-  return(DIR_STRUCT_SIZE);
-}
+  uint16 setup;
+  pstring param;
 
-/****************************************************************************
-interpret a long filename structure - this is mostly guesses at the moment
-The length of the structure is returned
-The structure of a long filename depends on the info level. 260 is used
-by NT and 2 is used by OS/2
-****************************************************************************/
-static int interpret_long_filename(int level,char *p,file_info *finfo)
-{
-  if (finfo)
-    memcpy(finfo,&def_finfo,sizeof(*finfo));
+  strcpy(mask,Mask);
 
-  switch (level)
+  while (ff_eos == 0)
     {
-    case 1: /* OS/2 understands this */
-      if (finfo)
+      loop_count++;
+      if (loop_count > 200)
        {
-         /* these dates are converted to GMT by make_unix_date */
-         finfo->ctime = make_unix_date2(p+4);
-         finfo->atime = make_unix_date2(p+8);
-         finfo->mtime = make_unix_date2(p+12);
-         finfo->size = IVAL(p,16);
-         finfo->mode = CVAL(p,24);
-         strcpy(finfo->name,p+27);
+         DEBUG(0,("Error: Looping in FIND_NEXT??\n"));
+         break;
        }
-      return(28 + CVAL(p,26));
 
-    case 2: /* this is what OS/2 uses mostly */
-      if (finfo)
+      if (First)
        {
-         /* these dates are converted to GMT by make_unix_date */
-         finfo->ctime = make_unix_date2(p+4);
-         finfo->atime = make_unix_date2(p+8);
-         finfo->mtime = make_unix_date2(p+12);
-         finfo->size = IVAL(p,16);
-         finfo->mode = CVAL(p,24);
-         strcpy(finfo->name,p+31);
+         setup = TRANSACT2_FINDFIRST;
+         SSVAL(param,0,attribute); /* attribute */
+         SSVAL(param,2,max_matches); /* max count */
+         SSVAL(param,4,8+4+2); /* resume required + close on end + continue */
+         SSVAL(param,6,info_level); 
+         SIVAL(param,8,0);
+         strcpy(param+12,mask);
        }
-      return(32 + CVAL(p,30));
-
-      /* levels 3 and 4 are untested */
-    case 3:
-      if (finfo)
+      else
        {
-         /* these dates are probably like the other ones */
-         finfo->ctime = make_unix_date2(p+8);
-         finfo->atime = make_unix_date2(p+12);
-         finfo->mtime = make_unix_date2(p+16);
-         finfo->size = IVAL(p,20);
-         finfo->mode = CVAL(p,28);
-         strcpy(finfo->name,p+33);
+         setup = TRANSACT2_FINDNEXT;
+         SSVAL(param,0,ff_dir_handle);
+         SSVAL(param,2,max_matches); /* max count */
+         SSVAL(param,4,info_level); 
+         SIVAL(param,6,ff_resume_key); /* ff_resume_key */
+         SSVAL(param,10,8+4+2);        /* resume required + close on end + continue */
+         strcpy(param+12,mask);
+
+         DEBUG(5,("hand=0x%X resume=%d ff_lastname=%d mask=%s\n",
+                  ff_dir_handle,ff_resume_key,ff_lastname,mask));
        }
-      return(SVAL(p,4)+4);
+      /* ??? original code added 1 pad byte after param */
 
-    case 4:
-      if (finfo)
+      send_trans_request(outbuf,SMBtrans2,NULL,FID_UNUSED,0,
+                        NULL,param,&setup,
+                        0,12+strlen(mask)+1,1,
+                        BUFFER_SIZE,10,0);
+
+      if (!receive_trans_response(inbuf,SMBtrans2,
+                             &resp_data_len,&resp_param_len,
+                                 &resp_data,&resp_param))
        {
-         /* these dates are probably like the other ones */
-         finfo->ctime = make_unix_date2(p+8);
-         finfo->atime = make_unix_date2(p+12);
-         finfo->mtime = make_unix_date2(p+16);
-         finfo->size = IVAL(p,20);
-         finfo->mode = CVAL(p,28);
-         strcpy(finfo->name,p+37);
+         DEBUG(3,("FIND%s gave %s\n",First?"FIRST":"NEXT",smb_errstr(inbuf)));
+         break;
        }
-      return(SVAL(p,4)+4);
 
-    case 260: /* NT uses this, but also accepts 2 */
-      if (finfo)
+      /* parse out some important return info */
+      p = resp_param;
+      if (First)
        {
-         int ret = SVAL(p,0);
-         int namelen;
-         p += 4; /* next entry offset */
-         p += 4; /* fileindex */
+         ff_dir_handle = SVAL(p,0);
+         ff_searchcount = SVAL(p,2);
+         ff_eos = SVAL(p,4);
+         ff_lastname = SVAL(p,8);
+       }
+      else
+       {
+         ff_searchcount = SVAL(p,0);
+         ff_eos = SVAL(p,2);
+         ff_lastname = SVAL(p,6);
+       }
 
-         /* these dates appear to arrive in a weird way. It seems to
-            be localtime plus the serverzone given in the initial
-            connect. This is GMT when DST is not in effect and one
-            hour from GMT otherwise. Can this really be right??
+      if (ff_searchcount == 0) 
+       break;
 
-            I suppose this could be called kludge-GMT. Is is the GMT
-            you get by using the current DST setting on a different
-            localtime. It will be cheap to calculate, I suppose, as
-            no DST tables will be needed */
+      /* point to the data bytes */
+      p = resp_data;
 
-         finfo->ctime = interpret_long_date(p); p += 8;
-         finfo->atime = interpret_long_date(p); p += 8;
-         finfo->mtime = interpret_long_date(p); p += 8; p += 8;
-         finfo->size = IVAL(p,0); p += 8;
-         p += 8; /* alloc size */
-         finfo->mode = CVAL(p,0); p += 4;
-         namelen = IVAL(p,0); p += 4;
-         p += 4; /* EA size */
-         p += 2; /* short name len? */
-         p += 24; /* short name? */      
-         StrnCpy(finfo->name,p,namelen);
-         return(ret);
+      /* we might need the lastname for continuations */
+      if (ff_lastname > 0)
+       {
+         switch(info_level)
+           {
+           case 260:
+             ff_resume_key =0;
+             StrnCpy(mask,p+ff_lastname,resp_data_len-ff_lastname);
+             /* strcpy(mask,p+ff_lastname+94); */
+             break;
+           case 1:
+             strcpy(mask,p + ff_lastname + 1);
+             ff_resume_key = 0;
+             break;
+           }
        }
-      return(SVAL(p,0));
-    }
-
-  DEBUG(1,("Unknown long filename format %d\n",level));
-  return(SVAL(p,0));
-}
+      else
+       strcpy(mask,"");
+  
+      /* and add them to the dirlist pool */
+      dirlist = Realloc(dirlist,dirlist_len + resp_data_len);
 
+      if (!dirlist)
+       {
+         DEBUG(0,("Failed to expand dirlist\n"));
+         break;
+       }
 
+      /* put in a length for the last entry, to ensure we can chain entries 
+        into the next packet */
+      {
+       char *p2;
+       for (p2=p,i=0;i<(ff_searchcount-1);i++)
+         p2 += interpret_long_filename(info_level,p2,NULL);
+       SSVAL(p2,0,resp_data_len - PTR_DIFF(p2,p));
+      }
 
+      /* grab the data for later use */
+      memcpy(dirlist+dirlist_len,p,resp_data_len);
+      dirlist_len += resp_data_len;
 
-/****************************************************************************
-  act on the files in a dir listing
-  ****************************************************************************/
-static void dir_action(char *inbuf,char *outbuf,int attribute,file_info *finfo,BOOL recurse_dir,void (*fn)(),BOOL longdir)
-{
+      total_received += ff_searchcount;
 
-  if (!((finfo->mode & aDIR) == 0 && *fileselection && 
-       !mask_match(finfo->name,fileselection,False,False)) &&
-      !(recurse_dir && (strequal(finfo->name,".") || 
-                       strequal(finfo->name,".."))))
-    {
-      if (recurse_dir && (finfo->mode & aDIR))
-       {
-         pstring mask2;
-         pstring sav_dir;
-         strcpy(sav_dir,cur_dir);
-         strcat(cur_dir,finfo->name);
-         strcat(cur_dir,"\\");
-         strcpy(mask2,cur_dir);
+      if (resp_data) free(resp_data); resp_data = NULL;
+      if (resp_param) free(resp_param); resp_param = NULL;
 
-         if (!fn)
-           DEBUG(0,("\n%s\n",CNV_LANG(cur_dir)));
+      DEBUG(3,("received %d entries (eos=%d resume=%d)\n",
+              ff_searchcount,ff_eos,ff_resume_key));
 
-         strcat(mask2,"*");
+      First = False;
+    }
 
-         if (longdir)
-           do_long_dir(inbuf,outbuf,mask2,attribute,fn,True);      
-         else
-           do_dir(inbuf,outbuf,mask2,attribute,fn,True);
+  if (!fn)
+    for (p=dirlist,i=0;i<total_received;i++)
+      {
+       p += interpret_long_filename(info_level,p,&finfo);
+       display_finfo(&finfo);
+      }
 
-         strcpy(cur_dir,sav_dir);
-       }
-      else
-       {
-         if (fn && do_this_one(finfo))
-           fn(finfo);
-       }
+  for (p=dirlist,i=0;i<total_received;i++)
+    {
+      p += interpret_long_filename(info_level,p,&finfo);
+      dir_action(inbuf,outbuf,attribute,&finfo,recurse_dir,fn,True);
     }
+
+  /* free up the dirlist buffer */
+  if (dirlist) free(dirlist);
+  return(total_received);
 }
 
 
@@ -796,7 +781,7 @@ static int do_short_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (
       memcpy(p,status,21);
 
       send_smb(Client,outbuf);
-      receive_smb(Client,inbuf,CLIENT_TIMEOUT,False);
+      receive_smb(Client,inbuf,CLIENT_TIMEOUT);
 
       if (CVAL(inbuf,smb_rcls) != 0) 
        DEBUG(0,("Error closing search: %s\n",smb_errstr(inbuf)));      
@@ -820,249 +805,305 @@ static int do_short_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (
   return(num_received);
 }
 
+
+
 /****************************************************************************
-  receive a SMB trans or trans2 response allocating the necessary memory
+  do a directory listing, calling fn on each file found
   ****************************************************************************/
-static BOOL receive_trans_response(char *inbuf,int trans,
-                                   int *data_len,int *param_len,
-                                     char **data,char **param)
+void do_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir)
 {
-  int total_data=0;
-  int total_param=0;
-  int this_data,this_param;
-
-  *data_len = *param_len = 0;
-
-  receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-  show_msg(inbuf);
-
-  /* sanity check */
-  if (CVAL(inbuf,smb_com) != trans)
+  DEBUG(5,("do_dir(%s,%x,%s)\n",Mask,attribute,BOOLSTR(recurse_dir)));
+  if (Protocol >= PROTOCOL_LANMAN2)
     {
-      DEBUG(0,("Expected %s response, got command 0x%02x\n",
-              trans==SMBtrans?"SMBtrans":"SMBtrans2", CVAL(inbuf,smb_com)));
-      return(False);
+      if (do_long_dir(inbuf,outbuf,Mask,attribute,fn,recurse_dir) > 0)
+       return;
     }
-  if (CVAL(inbuf,smb_rcls) != 0)
-    return(False);
 
-  /* parse out the lengths */
-  total_data = SVAL(inbuf,smb_tdrcnt);
-  total_param = SVAL(inbuf,smb_tprcnt);
+  expand_mask(Mask,False);
+  do_short_dir(inbuf,outbuf,Mask,attribute,fn,recurse_dir);
+  return;
+}
 
-  /* allocate it */
-  *data = Realloc(*data,total_data);
-  *param = Realloc(*param,total_param);
+/*******************************************************************
+  decide if a file should be operated on
+  ********************************************************************/
+static BOOL do_this_one(file_info *finfo)
+{
+  if (finfo->mode & aDIR) return(True);
 
-  while (1)
-    {
-      this_data = SVAL(inbuf,smb_drcnt);
-      this_param = SVAL(inbuf,smb_prcnt);
-      if (this_data)
-       memcpy(*data + SVAL(inbuf,smb_drdisp),
-              smb_base(inbuf) + SVAL(inbuf,smb_droff),
-              this_data);
-      if (this_param)
-       memcpy(*param + SVAL(inbuf,smb_prdisp),
-              smb_base(inbuf) + SVAL(inbuf,smb_proff),
-              this_param);
-      *data_len += this_data;
-      *param_len += this_param;
+  if (newer_than && finfo->mtime < newer_than)
+    return(False);
 
-      /* parse out the total lengths again - they can shrink! */
-      total_data = SVAL(inbuf,smb_tdrcnt);
-      total_param = SVAL(inbuf,smb_tprcnt);
+  if ((archive_level==1 || archive_level==2) && !(finfo->mode & aARCH))
+    return(False);
 
-      if (total_data <= *data_len && total_param <= *param_len)
-       break;
+  return(True);
+}
 
-      receive_smb(Client,inbuf,CLIENT_TIMEOUT);
-      show_msg(inbuf);
 
-      /* sanity check */
-      if (CVAL(inbuf,smb_com) != trans)
-       {
-         DEBUG(0,("Expected %s response, got command 0x%02x\n",
-                  trans==SMBtrans?"SMBtrans":"SMBtrans2", CVAL(inbuf,smb_com)));
-         return(False);
-       }
-      if (CVAL(inbuf,smb_rcls) != 0)
-         return(False);
+/*****************************************************************************
+ Convert a character pointer in a call_api() response to a form we can use.
+ This function contains code to prevent core dumps if the server returns 
+ invalid data.
+*****************************************************************************/
+static char *fix_char_ptr(unsigned int datap, unsigned int converter, char *rdata, int rdrcnt)
+{
+if( datap == 0 )               /* turn NULL pointers */
+  {                            /* into zero length strings */
+  return "";
+  }
+else
+  {
+  unsigned int offset = datap - converter;
+
+  if( offset >= rdrcnt )
+    {
+      DEBUG(1,("bad char ptr: datap=%u, converter=%u, rdata=%lu, rdrcnt=%d>", datap, converter, (unsigned long)rdata, rdrcnt));
+    return "<ERROR>";
     }
-  
-  return(True);
+  else
+    {
+    return &rdata[offset];
+    }
+  }
 }
 
 /****************************************************************************
-  do a directory listing, calling fn on each file found. Use the TRANSACT2
-  call for long filenames
-  ****************************************************************************/
-static int do_long_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir)
+interpret a short filename structure
+The length of the structure is returned
+****************************************************************************/
+static int interpret_short_filename(char *p,file_info *finfo)
 {
-  int max_matches = 512;
-  int info_level = Protocol<PROTOCOL_NT1?1:260; /* NT uses 260, OS/2 uses 2. Both accept 1. */
-  char *p;
-  pstring mask;
-  file_info finfo;
-  int i;
-  char *dirlist = NULL;
-  int dirlist_len = 0;
-  int total_received = 0;
-  BOOL First = True;
-  char *resp_data=NULL;
-  char *resp_param=NULL;
-  int resp_data_len = 0;
-  int resp_param_len=0;
-
-  int ff_resume_key = 0;
-  int ff_searchcount=0;
-  int ff_eos=0;
-  int ff_lastname=0;
-  int ff_dir_handle=0;
-  int loop_count = 0;
+  finfo->mode = CVAL(p,21);
 
-  uint16 setup;
-  pstring param;
+  /* this date is converted to GMT by make_unix_date */
+  finfo->ctime = make_unix_date(p+22);
+  finfo->mtime = finfo->atime = finfo->ctime;
+  finfo->size = IVAL(p,26);
+  strcpy(finfo->name,p+30);
+  
+  return(DIR_STRUCT_SIZE);
+}
 
-  strcpy(mask,Mask);
+/****************************************************************************
+interpret a long filename structure - this is mostly guesses at the moment
+The length of the structure is returned
+The structure of a long filename depends on the info level. 260 is used
+by NT and 2 is used by OS/2
+****************************************************************************/
+static int interpret_long_filename(int level,char *p,file_info *finfo)
+{
+  if (finfo)
+    memcpy(finfo,&def_finfo,sizeof(*finfo));
 
-  while (ff_eos == 0)
+  switch (level)
     {
-      loop_count++;
-      if (loop_count > 200)
+    case 1: /* OS/2 understands this */
+      if (finfo)
        {
-         DEBUG(0,("ERROR: Looping in FIND_NEXT??\n"));
-         break;
+         /* these dates are converted to GMT by make_unix_date */
+         finfo->ctime = make_unix_date2(p+4);
+         finfo->atime = make_unix_date2(p+8);
+         finfo->mtime = make_unix_date2(p+12);
+         finfo->size = IVAL(p,16);
+         finfo->mode = CVAL(p,24);
+         strcpy(finfo->name,p+27);
        }
+      return(28 + CVAL(p,26));
 
-      if (First)
-       {
-         setup = TRANSACT2_FINDFIRST;
-         SSVAL(param,0,attribute); /* attribute */
-         SSVAL(param,2,max_matches); /* max count */
-         SSVAL(param,4,8+4+2); /* resume required + close on end + continue */
-         SSVAL(param,6,info_level); 
-         SIVAL(param,8,0);
-         strcpy(param+12,mask);
-       }
-      else
+    case 2: /* this is what OS/2 uses mostly */
+      if (finfo)
        {
-         setup = TRANSACT2_FINDNEXT;
-         SSVAL(param,0,ff_dir_handle);
-         SSVAL(param,2,max_matches); /* max count */
-         SSVAL(param,4,info_level); 
-         SIVAL(param,6,ff_resume_key); /* ff_resume_key */
-         SSVAL(param,10,8+4+2);        /* resume required + close on end + continue */
-         strcpy(param+12,mask);
-
-         DEBUG(5,("hand=0x%X resume=%d ff_lastname=%d mask=%s\n",
-                  ff_dir_handle,ff_resume_key,ff_lastname,mask));
+         /* these dates are converted to GMT by make_unix_date */
+         finfo->ctime = make_unix_date2(p+4);
+         finfo->atime = make_unix_date2(p+8);
+         finfo->mtime = make_unix_date2(p+12);
+         finfo->size = IVAL(p,16);
+         finfo->mode = CVAL(p,24);
+         strcpy(finfo->name,p+31);
        }
-      /* ??? original code added 1 pad byte after param */
-
-      send_trans_request(outbuf,SMBtrans2,NULL,FID_UNUSED,0,
-                        NULL,param,&setup,
-                        0,12+strlen(mask)+1,1,
-                        BUFFER_SIZE,10,0);
+      return(32 + CVAL(p,30));
 
-      if (!receive_trans_response(inbuf,SMBtrans2,
-                             &resp_data_len,&resp_param_len,
-                                 &resp_data,&resp_param))
+      /* levels 3 and 4 are untested */
+    case 3:
+      if (finfo)
        {
-         DEBUG(3,("FIND%s gave %s\n",First?"FIRST":"NEXT",smb_errstr(inbuf)));
-         break;
+         /* these dates are probably like the other ones */
+         finfo->ctime = make_unix_date2(p+8);
+         finfo->atime = make_unix_date2(p+12);
+         finfo->mtime = make_unix_date2(p+16);
+         finfo->size = IVAL(p,20);
+         finfo->mode = CVAL(p,28);
+         strcpy(finfo->name,p+33);
        }
+      return(SVAL(p,4)+4);
 
-      /* parse out some important return info */
-      p = resp_param;
-      if (First)
+    case 4:
+      if (finfo)
        {
-         ff_dir_handle = SVAL(p,0);
-         ff_searchcount = SVAL(p,2);
-         ff_eos = SVAL(p,4);
-         ff_lastname = SVAL(p,8);
+         /* these dates are probably like the other ones */
+         finfo->ctime = make_unix_date2(p+8);
+         finfo->atime = make_unix_date2(p+12);
+         finfo->mtime = make_unix_date2(p+16);
+         finfo->size = IVAL(p,20);
+         finfo->mode = CVAL(p,28);
+         strcpy(finfo->name,p+37);
        }
-      else
+      return(SVAL(p,4)+4);
+
+    case 260: /* NT uses this, but also accepts 2 */
+      if (finfo)
        {
-         ff_searchcount = SVAL(p,0);
-         ff_eos = SVAL(p,2);
-         ff_lastname = SVAL(p,6);
+         int ret = SVAL(p,0);
+         int namelen;
+         p += 4; /* next entry offset */
+         p += 4; /* fileindex */
+
+         /* these dates appear to arrive in a weird way. It seems to
+            be localtime plus the serverzone given in the initial
+            connect. This is GMT when DST is not in effect and one
+            hour from GMT otherwise. Can this really be right??
+
+            I suppose this could be called kludge-GMT. Is is the GMT
+            you get by using the current DST setting on a different
+            localtime. It will be cheap to calculate, I suppose, as
+            no DST tables will be needed */
+
+         finfo->ctime = interpret_long_date(p); p += 8;
+         finfo->atime = interpret_long_date(p); p += 8;
+         finfo->mtime = interpret_long_date(p); p += 8; p += 8;
+         finfo->size = IVAL(p,0); p += 8;
+         p += 8; /* alloc size */
+         finfo->mode = CVAL(p,0); p += 4;
+         namelen = IVAL(p,0); p += 4;
+         p += 4; /* EA size */
+         p += 2; /* short name len? */
+         p += 24; /* short name? */      
+         StrnCpy(finfo->name,p,namelen);
+         return(ret);
        }
+      return(SVAL(p,0));
+    }
 
-      if (ff_searchcount == 0) 
-       break;
+  DEBUG(1,("Unknown long filename format %d\n",level));
+  return(SVAL(p,0));
+}
 
-      /* point to the data bytes */
-      p = resp_data;
 
-      /* we might need the lastname for continuations */
-      if (ff_lastname > 0)
+
+
+/****************************************************************************
+  act on the files in a dir listing
+  ****************************************************************************/
+static void dir_action(char *inbuf,char *outbuf,int attribute,file_info *finfo,BOOL recurse_dir,void (*fn)(),BOOL longdir)
+{
+
+  if (!((finfo->mode & aDIR) == 0 && *fileselection && 
+       !mask_match(finfo->name,fileselection,False,False)) &&
+      !(recurse_dir && (strequal(finfo->name,".") || 
+                       strequal(finfo->name,".."))))
+    {
+      if (recurse_dir && (finfo->mode & aDIR))
        {
-         switch(info_level)
-           {
-           case 260:
-             ff_resume_key =0;
-             StrnCpy(mask,p+ff_lastname,resp_data_len-ff_lastname);
-             /* strcpy(mask,p+ff_lastname+94); */
-             break;
-           case 1:
-             strcpy(mask,p + ff_lastname + 1);
-             ff_resume_key = 0;
-             break;
-           }
+         pstring mask2;
+         pstring sav_dir;
+         strcpy(sav_dir,cur_dir);
+         strcat(cur_dir,finfo->name);
+         strcat(cur_dir,"\\");
+         strcpy(mask2,cur_dir);
+
+         if (!fn)
+           DEBUG(0,("\n%s\n",CNV_LANG(cur_dir)));
+
+         strcat(mask2,"*");
+
+         if (longdir)
+           do_long_dir(inbuf,outbuf,mask2,attribute,fn,True);      
+         else
+           do_dir(inbuf,outbuf,mask2,attribute,fn,True);
+
+         strcpy(cur_dir,sav_dir);
        }
       else
-       strcpy(mask,"");
-  
-      /* and add them to the dirlist pool */
-      dirlist = Realloc(dirlist,dirlist_len + resp_data_len);
-
-      if (!dirlist)
        {
-         DEBUG(0,("Failed to expand dirlist\n"));
-         break;
+         if (fn && do_this_one(finfo))
+           fn(finfo);
        }
+    }
+}
 
-      /* put in a length for the last entry, to ensure we can chain entries 
-        into the next packet */
-      {
-       char *p2;
-       for (p2=p,i=0;i<(ff_searchcount-1);i++)
-         p2 += interpret_long_filename(info_level,p2,NULL);
-       SSVAL(p2,0,resp_data_len - PTR_DIFF(p2,p));
-      }
 
-      /* grab the data for later use */
-      memcpy(dirlist+dirlist_len,p,resp_data_len);
-      dirlist_len += resp_data_len;
+/****************************************************************************
+  receive a SMB trans or trans2 response allocating the necessary memory
+  ****************************************************************************/
+static BOOL receive_trans_response(char *inbuf,int trans,
+                                   int *data_len,int *param_len,
+                                  char **data,char **param)
+{
+  int total_data=0;
+  int total_param=0;
+  int this_data,this_param;
+
+  *data_len = *param_len = 0;
+
+  receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+  show_msg(inbuf);
+
+  /* sanity check */
+  if (CVAL(inbuf,smb_com) != trans)
+    {
+      DEBUG(0,("Expected %s response, got command 0x%02x\n",
+              trans==SMBtrans?"SMBtrans":"SMBtrans2", CVAL(inbuf,smb_com)));
+      return(False);
+    }
+  if (CVAL(inbuf,smb_rcls) != 0)
+    return(False);
+
+  /* parse out the lengths */
+  total_data = SVAL(inbuf,smb_tdrcnt);
+  total_param = SVAL(inbuf,smb_tprcnt);
 
-      total_received += ff_searchcount;
+  /* allocate it */
+  *data = Realloc(*data,total_data);
+  *param = Realloc(*param,total_param);
 
-      if (resp_data) free(resp_data); resp_data = NULL;
-      if (resp_param) free(resp_param); resp_param = NULL;
+  while (1)
+    {
+      this_data = SVAL(inbuf,smb_drcnt);
+      this_param = SVAL(inbuf,smb_prcnt);
+      if (this_data)
+       memcpy(*data + SVAL(inbuf,smb_drdisp),
+              smb_base(inbuf) + SVAL(inbuf,smb_droff),
+              this_data);
+      if (this_param)
+       memcpy(*param + SVAL(inbuf,smb_prdisp),
+              smb_base(inbuf) + SVAL(inbuf,smb_proff),
+              this_param);
+      *data_len += this_data;
+      *param_len += this_param;
 
-      DEBUG(3,("received %d entries (eos=%d resume=%d)\n",
-              ff_searchcount,ff_eos,ff_resume_key));
+      /* parse out the total lengths again - they can shrink! */
+      total_data = SVAL(inbuf,smb_tdrcnt);
+      total_param = SVAL(inbuf,smb_tprcnt);
 
-      First = False;
-    }
+      if (total_data <= *data_len && total_param <= *param_len)
+       break;
 
-  if (!fn)
-    for (p=dirlist,i=0;i<total_received;i++)
-      {
-       p += interpret_long_filename(info_level,p,&finfo);
-       display_finfo(&finfo);
-      }
+      receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+      show_msg(inbuf);
 
-  for (p=dirlist,i=0;i<total_received;i++)
-    {
-      p += interpret_long_filename(info_level,p,&finfo);
-      dir_action(inbuf,outbuf,attribute,&finfo,recurse_dir,fn,True);
+      /* sanity check */
+      if (CVAL(inbuf,smb_com) != trans)
+       {
+         DEBUG(0,("Expected %s response, got command 0x%02x\n",
+                  trans==SMBtrans?"SMBtrans":"SMBtrans2", CVAL(inbuf,smb_com)));
+         return(False);
+       }
+      if (CVAL(inbuf,smb_rcls) != 0)
+         return(False);
     }
-
-  /* free up the dirlist buffer */
-  if (dirlist) free(dirlist);
-  return(total_received);
+  
+  return(True);
 }
 
 
@@ -1076,6 +1117,7 @@ static void cmd_dir(char *inbuf,char *outbuf)
   fstring buf;
   char *p=buf;
 
+  dir_total = 0;
   strcpy(mask,cur_dir);
   if(mask[strlen(mask)-1]!='\\')
     strcat(mask,"\\");
@@ -1094,6 +1136,8 @@ static void cmd_dir(char *inbuf,char *outbuf)
   do_dir(inbuf,outbuf,mask,attribute,NULL,recurse);
 
   do_dskattr();
+
+  DEBUG(3, ("Total bytes listed: %d\n", dir_total));
 }
 
 
@@ -1493,7 +1537,7 @@ static void do_get(char *rname,char *lname,file_info *finfo1)
     get_total_time_ms += this_time;
     get_total_size += finfo.size;
 
-    DEBUG(2,("(%g kb/s) (average %g kb/s)\n",
+    DEBUG(1,("(%g kb/s) (average %g kb/s)\n",
             finfo.size / (1.024*this_time + 1.0e-4),
             get_total_size / (1.024*get_total_time_ms)));
   }
@@ -1623,7 +1667,7 @@ static void cmd_more(void)
 
   strcpy(rname,cur_dir);
   strcat(rname,"\\");
-  sprintf(tmpname,"/tmp/smbmore.%d",getpid());
+  sprintf(tmpname,"%s/smbmore.%d",tmpdir(),(int)getpid());
   strcpy(lname,tmpname);
 
   if (!next_token(NULL,rname+strlen(rname),NULL)) {
@@ -1994,7 +2038,7 @@ static void do_put(char *rname,char *lname,file_info *finfo)
     put_total_time_ms += this_time;
     put_total_size += finfo->size;
 
-    DEBUG(2,("(%g kb/s) (average %g kb/s)\n",
+    DEBUG(1,("(%g kb/s) (average %g kb/s)\n",
             finfo->size / (1.024*this_time + 1.0e-4),
             put_total_size / (1.024*put_total_time_ms)));
   }
@@ -2097,7 +2141,7 @@ static void cmd_mput(void)
       pstring tmpname;
       FILE *f;
       
-      sprintf(tmpname,"/tmp/ls.smb.%d",(int)getpid());
+      sprintf(tmpname,"%s/ls.smb.%d",tmpdir(),(int)getpid());
       if (recurse)
        sprintf(cmd,"find . -name \"%s\" -print > %s",p,tmpname);
       else
@@ -2131,13 +2175,12 @@ static void cmd_mput(void)
              
              strcpy(rname,cur_dir);
              strcat(rname,lname);
-             if (!do_mkdir(rname))
-               {
-                 strcat(lname,"/");
-                 if (!seek_list(f,lname))
-                   break;
-                 goto again1;                            
-               }
+             if (!chkpath(rname,False) && !do_mkdir(rname)) {
+               strcat(lname,"/");
+               if (!seek_list(f,lname))
+                 break;
+               goto again1;                              
+             }
 
              continue;
            }
@@ -2178,7 +2221,7 @@ static void do_cancel(int job)
   bzero(param,sizeof(param));
 
   p = param;
-  SSVAL(p,0,81);               /* api number */
+  SSVAL(p,0,81);               /* DosPrintJobDel() */
   p += 2;
   strcpy(p,"W");
   p = skip_string(p,1);
@@ -2425,7 +2468,8 @@ static void cmd_print(char *inbuf,char *outbuf )
 }
 
 /****************************************************************************
-print a file
+show a print queue - this is deprecated as it uses the old smb that
+has limited support - the correct call is the cmd_p_queue_4() after this.
 ****************************************************************************/
 static void cmd_queue(char *inbuf,char *outbuf )
 {
@@ -2486,6 +2530,222 @@ static void cmd_queue(char *inbuf,char *outbuf )
 }
 
 
+/****************************************************************************
+show information about a print queue
+****************************************************************************/
+static void cmd_p_queue_4(char *inbuf,char *outbuf )
+{
+  char *rparam = NULL;
+  char *rdata = NULL;
+  char *p;
+  int rdrcnt, rprcnt;
+  pstring param;
+  int result_code=0;
+
+  if (!connect_as_printer)
+    {
+      DEBUG(0,("WARNING: You didn't use the -P option to smbclient.\n"));
+      DEBUG(0,("Trying to print without -P may fail\n"));
+    }
+  
+  bzero(param,sizeof(param));
+
+  p = param;
+  SSVAL(p,0,76);                        /* API function number 76 (DosPrintJobEnum) */
+  p += 2;
+  strcpy(p,"zWrLeh");                   /* parameter description? */
+  p = skip_string(p,1);
+  strcpy(p,"WWzWWDDzz");                /* returned data format */
+  p = skip_string(p,1);
+  strcpy(p,strrchr(service,'\\')+1);    /* name of queue */
+  p = skip_string(p,1);
+  SSVAL(p,0,2);                 /* API function level 2, PRJINFO_2 data structure */
+  SSVAL(p,2,1000);                      /* size of bytes of returned data buffer */
+  p += 4;
+  strcpy(p,"");                         /* subformat */
+  p = skip_string(p,1);
+
+  DEBUG(1,("Calling DosPrintJobEnum()...\n"));
+  if( call_api(PTR_DIFF(p,param), 0,
+               10, 4096,
+               &rprcnt, &rdrcnt,
+               param, NULL,
+               &rparam, &rdata) )
+    {
+      int converter;
+      result_code = SVAL(rparam,0);
+      converter = SVAL(rparam,2);             /* conversion factor */
+
+      DEBUG(2,("returned %d bytes of parameters, %d bytes of data, %d records\n", rprcnt, rdrcnt, SVAL(rparam,4) ));
+
+      if (result_code == 0)                   /* if no error, */
+        {
+          int i;
+          uint16 JobId;
+          uint16 Priority;
+          uint32 Size;
+          char *UserName;
+          char *JobName;
+          char *JobTimeStr;
+          time_t JobTime;
+          char PrinterName[20];
+             
+          strcpy(PrinterName,strrchr(service,'\\')+1);       /* name of queue */
+          strlower(PrinterName);                             /* in lower case */
+
+          p = rdata;                          /* received data */
+          for( i = 0; i < SVAL(rparam,4); ++i)
+            {
+              JobId = SVAL(p,0);
+              Priority = SVAL(p,2);
+              UserName = fix_char_ptr(SVAL(p,4), converter, rdata, rdrcnt);
+              strlower(UserName);
+              Priority = SVAL(p,2);
+              JobTime = make_unix_date3( p + 12);
+              JobTimeStr = asctime(LocalTime( &JobTime));
+              Size = IVAL(p,16);
+              JobName = fix_char_ptr(SVAL(p,24), converter, rdata, rdrcnt);
+            
+
+              printf("%s-%u    %s    priority %u   %s    %s   %u bytes\n", 
+               PrinterName, JobId, UserName,
+                Priority, JobTimeStr, JobName, Size);
+   
+#if 0 /* DEBUG code */
+              printf("Job Id: \"%u\"\n", SVAL(p,0));
+              printf("Priority: \"%u\"\n", SVAL(p,2));
+            
+              printf("User Name: \"%s\"\n", fix_char_ptr(SVAL(p,4), converter, rdata, rdrcnt) );
+              printf("Position: \"%u\"\n", SVAL(p,8));
+              printf("Status: \"%u\"\n", SVAL(p,10));
+            
+              JobTime = make_unix_date3( p + 12);
+              printf("Submitted: \"%s\"\n", asctime(LocalTime(&JobTime)));
+              printf("date: \"%u\"\n", SVAL(p,12));
+
+              printf("Size: \"%u\"\n", SVAL(p,16));
+              printf("Comment: \"%s\"\n", fix_char_ptr(SVAL(p,20), converter, rdata, rdrcnt) );
+              printf("Document: \"%s\"\n", fix_char_ptr(SVAL(p,24), converter, rdata, rdrcnt) );
+#endif /* DEBUG CODE */ 
+              p += 28;
+            }
+        }
+    }
+  else                  /* call_api() failed */
+    {
+      printf("Failed, error = %d\n", result_code);
+    }
+
+  /* If any parameters or data were returned, free the storage. */
+  if(rparam) free(rparam);
+  if(rdata) free(rdata);
+
+  return;
+}
+
+/****************************************************************************
+show information about a print queue
+****************************************************************************/
+static void cmd_qinfo(char *inbuf,char *outbuf )
+{
+  char *rparam = NULL;
+  char *rdata = NULL;
+  char *p;
+  int rdrcnt, rprcnt;
+  pstring param;
+  int result_code=0;
+  
+  bzero(param,sizeof(param));
+
+  p = param;
+  SSVAL(p,0,70);                       /* API function number 70 (DosPrintQGetInfo) */
+  p += 2;
+  strcpy(p,"zWrLh");                   /* parameter description? */
+  p = skip_string(p,1);
+  strcpy(p,"zWWWWzzzzWWzzl");          /* returned data format */
+  p = skip_string(p,1);
+  strcpy(p,strrchr(service,'\\')+1);   /* name of queue */
+  p = skip_string(p,1);
+  SSVAL(p,0,3);                                /* API function level 3, just queue info, no job info */
+  SSVAL(p,2,1000);                     /* size of bytes of returned data buffer */
+  p += 4;
+  strcpy(p,"");                                /* subformat */
+  p = skip_string(p,1);
+
+  DEBUG(1,("Calling DosPrintQueueGetInfo()...\n"));
+  if( call_api(PTR_DIFF(p,param), 0,
+              10, 4096,
+              &rprcnt, &rdrcnt,
+              param, NULL,
+              &rparam, &rdata) )
+       {
+       int converter;
+       result_code = SVAL(rparam,0);
+       converter = SVAL(rparam,2);             /* conversion factor */
+
+       DEBUG(2,("returned %d bytes of parameters, %d bytes of data, %d records\n", rprcnt, rdrcnt, SVAL(rparam,4) ));
+
+       if (result_code == 0)                   /* if no error, */
+           {
+           p = rdata;                          /* received data */
+
+           printf("Name: \"%s\"\n", fix_char_ptr(SVAL(p,0), converter, rdata, rdrcnt) );
+           printf("Priority: %u\n", SVAL(p,4) );
+           printf("Start time: %u\n", SVAL(p,6) );
+           printf("Until time: %u\n", SVAL(p,8) );
+           printf("Seperator file: \"%s\"\n", fix_char_ptr(SVAL(p,12), converter, rdata, rdrcnt) );
+           printf("Print processor: \"%s\"\n", fix_char_ptr(SVAL(p,16), converter, rdata, rdrcnt) );
+           printf("Parameters: \"%s\"\n", fix_char_ptr(SVAL(p,20), converter, rdata, rdrcnt) );
+           printf("Comment: \"%s\"\n", fix_char_ptr(SVAL(p,24), converter, rdata, rdrcnt) );
+           printf("Status: %u\n", SVAL(p,28) );
+           printf("Jobs: %u\n", SVAL(p,30) );
+           printf("Printers: \"%s\"\n", fix_char_ptr(SVAL(p,32), converter, rdata, rdrcnt) );
+           printf("Drivername: \"%s\"\n", fix_char_ptr(SVAL(p,36), converter, rdata, rdrcnt) );
+
+           /* Dump the driver data */
+           {
+           int count, x, y, c;
+           char *ddptr;
+
+           ddptr = rdata + SVAL(p,40) - converter;
+           if( SVAL(p,40) == 0 ) {count = 0;} else {count = IVAL(ddptr,0);}
+           printf("Driverdata: size=%d, version=%u\n", count, IVAL(ddptr,4) );
+
+           for(x=8; x < count; x+=16)
+               {
+               for(y=0; y < 16; y++)
+                   {
+                   if( (x+y) < count )
+                       printf("%2.2X ", CVAL(ddptr,(x+y)) );
+                   else
+                       fputs("   ", stdout);
+                   }
+               for(y=0; y < 16 && (x+y) < count; y++)
+                   {
+                   c = CVAL(ddptr,(x+y));
+                   if(isprint(c))
+                       fputc(c, stdout);
+                   else
+                       fputc('.', stdout);
+                   }
+               fputc('\n', stdout);
+               }
+           }
+           
+           }
+       }
+  else                 /* call_api() failed */
+       {
+       printf("Failed, error = %d\n", result_code);
+       }
+
+  /* If any parameters or data were returned, free the storage. */
+  if(rparam) free(rparam);
+  if(rdata) free(rdata);
+
+  return;
+}
+
 /****************************************************************************
 delete some files
 ****************************************************************************/
@@ -2670,7 +2930,7 @@ static void cmd_newer(void)
     {
       newer_than = sbuf.st_mtime;
       DEBUG(1,("Getting files newer than %s",
-              asctime(LocalTime(&newer_than,GMT_TO_LOCAL))));
+              asctime(LocalTime(&newer_than))));
     }
   else
     newer_than = 0;
@@ -2791,7 +3051,7 @@ static BOOL send_session_request(char *inbuf,char *outbuf)
 
   /* put in the destination name */
   p = outbuf+len;
-  name_mangle(dest,p,name_type);
+  name_mangle(dest,p,name_type); /* 0x20 is the SMB server NetBIOS type. */
   len += name_len(p);
 
   /* and my name */
@@ -2826,7 +3086,7 @@ static BOOL send_session_request(char *inbuf,char *outbuf)
       putip((char *)&dest_ip,inbuf+4);
 
       close_sockets();
-      Client = open_socket_out(SOCK_STREAM, &dest_ip, port);
+      Client = open_socket_out(SOCK_STREAM, &dest_ip, port, LONG_CONNECT_TIMEOUT);
       if (Client == -1)
         return False;
 
@@ -2875,6 +3135,21 @@ static BOOL send_session_request(char *inbuf,char *outbuf)
   return(True);
 }
 
+static struct {
+  int prot;
+  char *name;
+} prots[] = {
+  {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"},
+  {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
+  {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
+  {PROTOCOL_LANMAN1,"LANMAN1.0"},
+  {PROTOCOL_LANMAN2,"LM1.2X002"},
+  {PROTOCOL_LANMAN2,"Samba"},
+  {PROTOCOL_NT1,"NT LM 0.12"},
+  {PROTOCOL_NT1,"NT LANMAN 1.0"},
+  {-1,NULL}
+};
+
 
 /****************************************************************************
 send a login command
@@ -2888,26 +3163,11 @@ static BOOL send_login(char *inbuf,char *outbuf,BOOL start_session,BOOL use_setu
   int sec_mode=0;
   int crypt_len;
   int max_vcs=0;
-  struct {
-    int prot;
-    char *name;
-  }
-  prots[] = 
-    {
-      {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"},
-      {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
-      {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
-      {PROTOCOL_LANMAN1,"LANMAN1.0"},
-      {PROTOCOL_LANMAN2,"LM1.2X002"},
-      {PROTOCOL_LANMAN2,"Samba"},
-      {PROTOCOL_NT1,"NT LM 0.12"},
-      {PROTOCOL_NT1,"NT LANMAN 1.0"},
-      {-1,NULL}
-    };
   char *pass = NULL;  
   pstring dev;
   char *p;
   int numprots;
+  int tries=0;
 
   if (was_null)
     {
@@ -3032,7 +3292,7 @@ static BOOL send_login(char *inbuf,char *outbuf,BOOL start_session,BOOL use_setu
     static BOOL done_time = False;
     if (!done_time) {
       DEBUG(1,("Server time is %sTimezone is UTC%+02.1f\n",
-              asctime(LocalTime(&servertime,GMT_TO_LOCAL)),
+              asctime(LocalTime(&servertime)),
               -(double)(serverzone/3600.0)));
       done_time = True;
     }
@@ -3045,21 +3305,21 @@ static BOOL send_login(char *inbuf,char *outbuf,BOOL start_session,BOOL use_setu
   else
     pass = (char *)getpass("Password: ");
 
+  /* use a blank username for the 2nd try with a blank password */
+  if (tries++ && !*pass)
+    *username = 0;
+
   if (Protocol >= PROTOCOL_LANMAN1 && use_setup)
     {
       fstring pword;
       int passlen = strlen(pass)+1;
       strcpy(pword,pass);      
 
-#ifdef SMB_PASSWD
       if (doencrypt && *pass) {
        DEBUG(3,("Using encrypted passwords\n"));
        passlen = 24;
-       SMBencrypt(pass,cryptkey,pword);
+       SMBencrypt((uchar *)pass,(uchar *)cryptkey,(uchar *)pword);
       }
-#else
-      doencrypt = False;
-#endif
 
       /* if in share level security then don't send a password now */
       if (!(sec_mode & 1)) {strcpy(pword, "");passlen=1;} 
@@ -3170,31 +3430,46 @@ static BOOL send_login(char *inbuf,char *outbuf,BOOL start_session,BOOL use_setu
     fstring pword;
     strcpy(pword,pass);
 
-#ifdef SMB_PASSWD
     if (doencrypt && *pass) {
       passlen=24;
-      SMBencrypt(pass,cryptkey,pword);      
+      SMBencrypt((uchar *)pass,(uchar *)cryptkey,(uchar *)pword);      
     }
-#endif
 
     /* if in user level security then don't send a password now */
     if ((sec_mode & 1)) {
       strcpy(pword, ""); passlen=1; 
     }
 
-    set_message(outbuf,4,2 + strlen(service) + passlen + strlen(dev),True);
-    CVAL(outbuf,smb_com) = SMBtconX;
-    setup_pkt(outbuf);
-
-    SSVAL(outbuf,smb_vwv0,0xFF);
-    SSVAL(outbuf,smb_vwv3,passlen);
+    if (Protocol <= PROTOCOL_COREPLUS) {
+      set_message(outbuf,0,6 + strlen(service) + passlen + strlen(dev),True);
+      CVAL(outbuf,smb_com) = SMBtcon;
+      setup_pkt(outbuf);
 
-    p = smb_buf(outbuf);
-    memcpy(p,pword,passlen);
-    p += passlen;
-    strcpy(p,service);
-    p = skip_string(p,1);
-    strcpy(p,dev);
+      p = smb_buf(outbuf);
+      *p++ = 0x04;
+      strcpy(p, service);
+      p = skip_string(p,1);
+      *p++ = 0x04;
+      memcpy(p,pword,passlen);
+      p += passlen;
+      *p++ = 0x04;
+      strcpy(p, dev);
+    }
+    else {
+      set_message(outbuf,4,2 + strlen(service) + passlen + strlen(dev),True);
+      CVAL(outbuf,smb_com) = SMBtconX;
+      setup_pkt(outbuf);
+  
+      SSVAL(outbuf,smb_vwv0,0xFF);
+      SSVAL(outbuf,smb_vwv3,passlen);
+  
+      p = smb_buf(outbuf);
+      memcpy(p,pword,passlen);
+      p += passlen;
+      strcpy(p,service);
+      p = skip_string(p,1);
+      strcpy(p,dev);
+    }
   }
 
   send_smb(Client,outbuf);
@@ -3225,11 +3500,18 @@ static BOOL send_login(char *inbuf,char *outbuf,BOOL start_session,BOOL use_setu
     }
   
 
-  max_xmit = MIN(max_xmit,BUFFER_SIZE-4);
-  if (max_xmit <= 0)
-    max_xmit = BUFFER_SIZE - 4;
+  if (Protocol <= PROTOCOL_COREPLUS) {
+    max_xmit = SVAL(inbuf,smb_vwv0);
+
+    cnum = SVAL(inbuf,smb_vwv1);
+  }
+  else {
+    max_xmit = MIN(max_xmit,BUFFER_SIZE-4);
+    if (max_xmit <= 0)
+      max_xmit = BUFFER_SIZE - 4;
 
-  cnum = SVAL(inbuf,smb_tid);
+    cnum = SVAL(inbuf,smb_tid);
+  }
 
   DEBUG(3,("Connected with cnum=%d max_xmit=%d\n",cnum,max_xmit));
 
@@ -3417,8 +3699,13 @@ try and browse available connections on a host
 static BOOL browse_host(BOOL sort)
 {
 #ifdef NOSTRCASECMP
+/* If strcasecmp is already defined, remove it. */
+#ifdef strcasecmp
+#undef strcasecmp
+#endif /* strcasecmp */
 #define strcasecmp StrCaseCmp
-#endif
+#endif /* NOSTRCASECMP */
+
   extern int strcasecmp();
 
   char *rparam = NULL;
@@ -3522,7 +3809,7 @@ static void server_info()
   bzero(param,sizeof(param));
 
   p = param;
-  SSVAL(p,0,63); /* api number */
+  SSVAL(p,0,63);               /* NetServerGetInfo()? */
   p += 2;
   strcpy(p,"WrLh");
   p = skip_string(p,1);
@@ -3563,37 +3850,52 @@ static void server_info()
 /****************************************************************************
 try and browse available connections on a host
 ****************************************************************************/
-static BOOL list_servers()
+static BOOL list_servers(char *wk_grp)
 {
   char *rparam = NULL;
   char *rdata = NULL;
   int rdrcnt,rprcnt;
-  char *p;
+  char *p,*svtype_p;
   pstring param;
   int uLevel = 1;
   int count = 0;
+  BOOL ok = False;
+  BOOL generic_request = False;
+
+
+  if (strequal(wk_grp,"WORKGROUP")) {
+    /* we won't specify a workgroup */
+    generic_request = True;
+  } 
 
   /* now send a SMBtrans command with api ServerEnum? */
   p = param;
   SSVAL(p,0,0x68); /* api number */
   p += 2;
-  strcpy(p,"WrLehDO");
+
+  strcpy(p,generic_request?"WrLehDO":"WrLehDz");
   p = skip_string(p,1);
 
   strcpy(p,"B16BBDz");
-#if 0
-  strcpy(p,getenv("XX_STR2"));
-#endif
 
   p = skip_string(p,1);
   SSVAL(p,0,uLevel);
-  SSVAL(p,2,0x2000); /* buf length */
+  SSVAL(p,2,BUFFER_SIZE - SAFETY_MARGIN); /* buf length */
+  p += 4;
+
+  svtype_p = p;
   p += 4;
 
-  SIVAL(p,0,SV_TYPE_ALL);
+  if (!generic_request) {
+    strcpy(p, wk_grp);
+    p = skip_string(p,1);
+  }
+
+  /* first ask for a list of servers in this workgroup */
+  SIVAL(svtype_p,0,SV_TYPE_ALL);
 
   if (call_api(PTR_DIFF(p+4,param),0,
-              8,10000,
+              8,BUFFER_SIZE - SAFETY_MARGIN,
               &rprcnt,&rdrcnt,
               param,NULL,
               &rparam,&rdata))
@@ -3618,7 +3920,8 @@ static BOOL list_servers()
          printf("\t%-16.16s     %s\n",
                 sname,
                 comment_offset?rdata+comment_offset-converter:"");
-         
+
+         ok=True;
          p2 += 26;
        }
       }
@@ -3627,10 +3930,11 @@ static BOOL list_servers()
   if (rparam) {free(rparam); rparam = NULL;}
   if (rdata) {free(rdata); rdata = NULL;}
 
-  SIVAL(p,0,SV_TYPE_DOMAIN_ENUM);
+  /* now ask for a list of workgroups */
+  SIVAL(svtype_p,0,SV_TYPE_DOMAIN_ENUM);
 
   if (call_api(PTR_DIFF(p+4,param),0,
-              8,10000,
+              8,BUFFER_SIZE - SAFETY_MARGIN,
               &rprcnt,&rdrcnt,
               param,NULL,
               &rparam,&rdata))
@@ -3656,6 +3960,7 @@ static BOOL list_servers()
                 sname,
                 comment_offset?rdata+comment_offset-converter:"");
          
+         ok=True;
          p2 += 26;
        }
       }
@@ -3664,14 +3969,10 @@ static BOOL list_servers()
   if (rparam) free(rparam);
   if (rdata) free(rdata);
 
-  return(count>0);
+  return(ok);
 }
 
 
-
-
-void cmd_help();
-
 /* This defines the commands supported by this client */
 struct
 {
@@ -3698,6 +3999,7 @@ struct
   {"md",cmd_mkdir,"<directory> make a directory"},
   {"rmdir",cmd_rmdir,"<directory> remove a directory"},
   {"rd",cmd_rmdir,"<directory> remove a directory"},
+  {"pq",cmd_p_queue_4,"enumerate the print queue"},
   {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput"},  
   {"recurse",cmd_recurse,"toggle directory recursion for mget and mput"},  
   {"translate",cmd_translate,"toggle text translation for printing"},  
@@ -3705,6 +4007,7 @@ struct
   {"print",cmd_print,"<file name> print a file"},
   {"printmode",cmd_printmode,"<graphics or text> set the print mode"},
   {"queue",cmd_queue,"show the print queue"},
+  {"qinfo",cmd_qinfo,"show print queue information"},
   {"cancel",cmd_cancel,"<jobid> cancel a print queue entry"},
   {"stat",cmd_stat,"<file> get info on a file (experimental!)"},
   {"quit",send_logout,"logoff the server"},
@@ -3815,13 +4118,12 @@ static BOOL open_sockets(int port )
       strcpy(desthost,host);
     }
 
-  DEBUG(3,("Opening sockets\n"));
-
-  if (*myname == 0)
-    {
+  if (*myname == 0) {
       get_myname(myname,NULL);
-      strupper(myname);
-    }
+  }
+  strupper(myname);
+
+  DEBUG(3,("Opening sockets\n"));
 
   if (!have_ip)
     {
@@ -3834,17 +4136,13 @@ static BOOL open_sockets(int port )
 #ifdef USENMB
        /* Try and resolve the name with the netbios server */
        int             bcast;
-       pstring         hs;
-       struct in_addr  ip1, ip2;
-       
-       if ((bcast = open_socket_in(SOCK_DGRAM, 0, 3)) != -1) {
-         set_socket_options (bcast, "SO_BROADCAST");
 
-         if (!got_bcast && get_myname(hs, &ip1)) {
-           get_broadcast(&ip1, &bcast_ip, &ip2);
-         }
+       if ((bcast = open_socket_in(SOCK_DGRAM, 0, 3,
+                                   interpret_addr(lp_socket_address()))) != -1) {
+         set_socket_options(bcast, "SO_BROADCAST");
 
-         if (name_query(bcast, host, 0x20, True, True, bcast_ip, &dest_ip,0)){
+         if (name_query(bcast, host, name_type, True, True, *iface_bcast(dest_ip),
+                        &dest_ip,0)) {
            failed = False;
          }
          close (bcast);
@@ -3857,7 +4155,7 @@ static BOOL open_sockets(int port )
       }
     }
 
-  Client = open_socket_out(SOCK_STREAM, &dest_ip, port);
+  Client = open_socket_out(SOCK_STREAM, &dest_ip, port, LONG_CONNECT_TIMEOUT);
   if (Client == -1)
     return False;
 
@@ -3907,13 +4205,11 @@ static void wait_keyboard(char *buffer)
 #else
       {
        char ch;
-       int f_flags;
        int readret;
-       
-       f_flags = fcntl(fileno(stdin), F_GETFL, 0);
-       fcntl( fileno(stdin), F_SETFL, f_flags | O_NONBLOCK);
+
+    set_blocking(fileno(stdin), False);        
        readret = read_data( fileno(stdin), &ch, 1);
-       fcntl(fileno(stdin), F_SETFL, f_flags);
+       set_blocking(fileno(stdin), True);
        if (readret == -1)
          {
            if (errno != EAGAIN)
@@ -3975,10 +4271,11 @@ BOOL reopen_connection(char *inbuf,char *outbuf)
 /****************************************************************************
   process commands from the client
 ****************************************************************************/
-BOOL process(char *base_directory)
+static BOOL process(char *base_directory)
 {
   extern FILE *dbf;
   pstring line;
+  char *cmd;
 
   char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
   char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
@@ -3993,7 +4290,44 @@ BOOL process(char *base_directory)
 
   if (*base_directory) do_cd(base_directory);
 
-  while (!feof(stdin))
+  cmd = cmdstr;
+  if (cmd[0] != '\0') while (cmd[0] != '\0')
+    {
+      char *p;
+      fstring tok;
+      int i;
+
+      if ((p = strchr(cmd, ';')) == 0)
+       {
+         strncpy(line, cmd, 999);
+         line[1000] = '\0';
+         cmd += strlen(cmd);
+       }
+      else
+       {
+         if (p - cmd > 999) p = cmd + 999;
+         strncpy(line, cmd, p - cmd);
+         line[p - cmd] = '\0';
+         cmd = p + 1;
+       }
+
+      /* input language code to internal one */
+      CNV_INPUT (line);
+      
+      /* and get the first part of the command */
+      {
+       char *ptr = line;
+       if (!next_token(&ptr,tok,NULL)) continue;
+      }
+
+      if ((i = process_tok(tok)) >= 0)
+       commands[i].fn(InBuffer,OutBuffer);
+      else if (i == -2)
+       DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok)));
+      else
+       DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
+    }
+  else while (!feof(stdin))
     {
       fstring tok;
       int i;
@@ -4001,7 +4335,7 @@ BOOL process(char *base_directory)
       bzero(OutBuffer,smb_size);
 
       /* display a prompt */
-      DEBUG(1,("smb: %s> ", CNV_LANG(cur_dir)));
+      DEBUG(0,("smb: %s> ", CNV_LANG(cur_dir)));
       fflush(dbf);
 
 #ifdef CLIX
@@ -4053,15 +4387,11 @@ BOOL process(char *base_directory)
 /****************************************************************************
 usage on the program
 ****************************************************************************/
-void usage(char *pname)
+static void usage(char *pname)
 {
   DEBUG(0,("Usage: %s service <password> [-p port] [-d debuglevel] [-l log] ",
           pname));
 
-#ifdef KANJI
-  DEBUG(0,("[-t termcode] "));
-#endif /* KANJI */
-
   DEBUG(0,("\nVersion %s\n",VERSION));
   DEBUG(0,("\t-p port               listen on the specified port\n"));
   DEBUG(0,("\t-d debuglevel         set the debuglevel\n"));
@@ -4076,24 +4406,21 @@ void usage(char *pname)
   DEBUG(0,("\t-E                    write messages to stderr instead of stdout\n"));
   DEBUG(0,("\t-U username           set the network username\n"));
   DEBUG(0,("\t-W workgroup          set the workgroup name\n"));
-#ifdef KANJI
+  DEBUG(0,("\t-c command string     execute semicolon separated commands\n"));
   DEBUG(0,("\t-t terminal code      terminal i/o code {sjis|euc|jis7|jis8|junet|hex}\n"));
-#endif /* KANJI */
   DEBUG(0,("\t-T<c|x>IXgbNa          command line tar\n"));
   DEBUG(0,("\t-D directory          start from directory\n"));
   DEBUG(0,("\n"));
 }
 
-
-
 /****************************************************************************
   main program
 ****************************************************************************/
-int main(int argc,char *argv[])
+ int main(int argc,char *argv[])
 {
   fstring base_directory;
   char *pname = argv[0];
-  int port = 139;
+  int port = SMB_PORT;
   int opt;
   extern FILE *dbf;
   extern char *optarg;
@@ -4101,6 +4428,15 @@ int main(int argc,char *argv[])
   pstring query_host;
   BOOL message = False;
   extern char tar_type;
+  static pstring servicesf = CONFIGFILE;
+  pstring term_code;
+  char *p;
+
+#ifdef KANJI
+  strcpy(term_code, KANJI);
+#else /* KANJI */
+  *term_code = 0;
+#endif /* KANJI */
 
   *query_host = 0;
   *base_directory = 0;
@@ -4120,10 +4456,27 @@ int main(int argc,char *argv[])
   umask(myumask);
 
   if (getenv("USER"))
+  {
+    strcpy(username,getenv("USER"));
+
+    /* modification to support userid%passwd syntax in the USER var
+       25.Aug.97, jdblair@uab.edu */
+
+    if ((p=strchr(username,'%')))
     {
-      strcpy(username,getenv("USER"));
-      strupper(username);
+      *p = 0;
+      strcpy(password,p+1);
+      got_pass = True;
+      memset(strchr(getenv("USER"),'%')+1,'X',strlen(password));
     }
+    strupper(username);
+  }
+
+ /* modification to support PASSWD environmental var
+  25.Aug.97, jdblair@uab.edu */
+
+  if (getenv("PASSWD"))
+    strcpy(password,getenv("PASSWD"));
 
   if (*username == 0 && getenv("LOGNAME"))
     {
@@ -4141,6 +4494,8 @@ int main(int argc,char *argv[])
     {
 
       strcpy(service,argv[1]);  
+      /* Convert any '/' characters in the service name to '\' characters */
+      string_replace( service, '/','\\');
       argc--;
       argv++;
 
@@ -4170,12 +4525,8 @@ int main(int argc,char *argv[])
        }
     }
 
-#ifdef KANJI
-  setup_term_code (KANJI);
-  while ((opt = getopt (argc, argv, "B:O:M:i:Nn:d:Pp:l:hI:EB:U:L:t:m:W:T:D:")) != EOF)
-#else
-  while ((opt = getopt (argc, argv, "B:O:M:i:Nn:d:Pp:l:hI:EB:U:L:m:W:T:D:")) != EOF)
-#endif /* KANJI */
+  while ((opt = 
+         getopt(argc, argv,"s:B:O:M:i:Nn:d:Pp:l:hI:EB:U:L:t:m:W:T:D:c:")) != EOF)
     switch (opt)
       {
       case 'm':
@@ -4185,14 +4536,13 @@ int main(int argc,char *argv[])
        strcpy(user_socket_options,optarg);
        break;  
       case 'M':
-       name_type = 3;
+       name_type = 0x03; /* messages are sent to NetBIOS name type 0x3 */
        strcpy(desthost,optarg);
        strupper(desthost);
        message = True;
        break;
       case 'B':
-       bcast_ip = *interpret_addr2(optarg);
-       got_bcast = True;
+       iface_set_default(NULL,optarg,NULL);
        break;
       case 'D':
        strcpy(base_directory,optarg);
@@ -4212,12 +4562,12 @@ int main(int argc,char *argv[])
        break;
       case 'U':
        {
-         char *p;
+         char *lp;
        strcpy(username,optarg);
-       if ((p=strchr(username,'%')))
+       if ((lp=strchr(username,'%')))
          {
-           *p = 0;
-           strcpy(password,p+1);
+           *lp = 0;
+           strcpy(password,lp+1);
            got_pass = True;
            memset(strchr(optarg,'%')+1,'X',strlen(password));
          }
@@ -4258,19 +4608,20 @@ int main(int argc,char *argv[])
       case 'p':
        port = atoi(optarg);
        break;
+      case 'c':
+       cmdstr = optarg;
+       got_pass = True;
+       break;
       case 'h':
        usage(pname);
        exit(0);
        break;
-#ifdef KANJI
+      case 's':
+       strcpy(servicesf, optarg);
+       break;
       case 't':
-       if (!setup_term_code (optarg)) {
-           DEBUG(0, ("%s: unknown terminal code name\n", optarg));
-           usage (pname);
-           exit (1);
-       }
+        strcpy(term_code, optarg);
        break;
-#endif /* KANJI */
       default:
        usage(pname);
        exit(1);
@@ -4285,7 +4636,32 @@ int main(int argc,char *argv[])
 
   DEBUG(3,("%s client started (version %s)\n",timestring(),VERSION));
 
-  get_myname(*myname?NULL:myname,&myip);  
+  if(!get_myname(myhostname,NULL))
+  {
+    DEBUG(0,("Failed to get my hostname.\n"));
+  }
+
+  if (!lp_load(servicesf,True)) {
+    fprintf(stderr, "Can't load %s - run testparm to debug it\n", servicesf);
+  }
+
+  codepage_initialise(lp_client_code_page());
+
+  if(lp_client_code_page() == KANJI_CODEPAGE)
+  {
+        if (!setup_term_code (term_code))
+    {
+            DEBUG(0, ("%s: unknown terminal code name\n", optarg));
+            usage (pname);
+            exit (1);
+        }
+  }
+
+  if (*workgroup == 0)
+    strcpy(workgroup,lp_workgroup());
+
+  load_interfaces();
+  get_myname(*myname?NULL:myname,NULL);  
   strupper(myname);
 
   if (tar_type) {
@@ -4333,9 +4709,9 @@ int main(int argc,char *argv[])
            sleep(1);
            browse_host(True);
          }
-         if (!list_servers()) {
+         if (!list_servers(workgroup)) {
            sleep(1);
-           list_servers();
+           list_servers(workgroup);
          }
 
          send_logout();
@@ -4471,7 +4847,7 @@ err_code_struct hard_msgs[] = {
   {"ERRwrite",29,"Write fault."},
   {"ERRread",30,"Read fault."},
   {"ERRgeneral",31,"General failure."},
-  {"ERRbadshare",32,"A open conflicts with an existing open."},
+  {"ERRbadshare",32,"An open conflicts with an existing open."},
   {"ERRlock",33,"A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."},
   {"ERRwrongdisk",34,"The wrong disk was found in a drive."},
   {"ERRFCBUnavail",35,"No FCBs are available to process request."},
@@ -4529,6 +4905,6 @@ char *smb_errstr(char *inbuf)
        return ret;
       }
   
-  sprintf(ret,"ERROR: Unknown error (%d,%d)",class,num);
+  sprintf(ret,"Error: Unknown error (%d,%d)",class,num);
   return(ret);
 }