r25026: Move param/param.h out of includes.h
[kai/samba-autobuild/.git] / source4 / client / client.c
index d9e995f1806eee5df129c3da7484b879e046d47f..eaa8fe48a0dd5703604320452d4de31b7759d84e 100644 (file)
@@ -8,7 +8,7 @@
    
    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
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    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.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
-#include "dynconfig.h"
-#include "clilist.h"
+#include "version.h"
+#include "libcli/libcli.h"
 #include "lib/cmdline/popt_common.h"
-#include "librpc/gen_ndr/ndr_srvsvc.h"
+#include "librpc/gen_ndr/ndr_srvsvc_c.h"
+#include "librpc/gen_ndr/ndr_lsa.h"
+#include "librpc/gen_ndr/ndr_security.h"
 #include "libcli/raw/libcliraw.h"
-#include "system/time.h"
+#include "libcli/util/clilsa.h"
 #include "system/dir.h"
 #include "system/filesys.h"
-#include "dlinklist.h"
-
-#ifndef REGISTER
-#define REGISTER 0
-#endif
-
-struct smbcli_state *cli;
-extern BOOL in_client;
-static int port = 0;
-pstring cur_dir = "\\";
-static pstring cd_path = "";
-static pstring service;
-static pstring desthost;
-static pstring username;
-static pstring domain;
-static pstring password;
-static char *cmdstr = NULL;
+#include "lib/util/dlinklist.h"
+#include "system/readline.h"
+#include "auth/credentials/credentials.h"
+#include "auth/gensec/gensec.h"
+#include "system/time.h" /* needed by some systems for asctime() */
+#include "libcli/resolve/resolve.h"
+#include "libcli/security/security.h"
+#include "lib/smbreadline/smbreadline.h"
+#include "librpc/gen_ndr/ndr_nbt.h"
+#include "param/param.h"
 
 static int io_bufsize = 64512;
 
-static int name_type = 0x20;
-
-static int process_tok(fstring tok);
-static int cmd_help(const char **cmd_ptr);
-
-/* 30 second timeout on most commands */
-#define CLIENT_TIMEOUT (30*1000)
-#define SHORT_TIMEOUT (5*1000)
-
-/* value for unused fid field in trans2 secondary request */
-#define FID_UNUSED (0xFFFF)
-
-time_t newer_than = 0;
-static int archive_level = 0;
-
-static BOOL translation = False;
-
-/* clitar bits insert */
-extern int blocksize;
-extern BOOL tar_inc;
-extern BOOL tar_reset;
-/* clitar bits end */
-
-static BOOL prompt = True;
-
-static int printmode = 1;
-
-static BOOL recurse = False;
-BOOL lowercase = False;
-
-static const char *dest_ip;
-
-#define SEPARATORS " \t\n\r"
-
-static BOOL abort_mget = True;
-
-static pstring fileselection = "";
+struct smbclient_context {
+       char *remote_cur_dir;
+       struct smbcli_state *cli;
+       char *fileselection;
+       time_t newer_than;
+       BOOL prompt;
+       BOOL recurse;
+       int archive_level;
+       BOOL lowercase;
+       int printmode;
+       BOOL translation;
+};
 
 /* timing globals */
-uint64_t get_total_size = 0;
-uint_t get_total_time_ms = 0;
+static uint64_t get_total_size = 0;
+static uint_t get_total_time_ms = 0;
 static uint64_t put_total_size = 0;
 static uint_t put_total_time_ms = 0;
 
+/* Unfortunately, there is no way to pass the a context to the completion function as an argument */
+static struct smbclient_context *rl_ctx; 
+
 /* totals globals */
 static double dir_total;
 
-#define USENMB
-
-/* some forward declarations */
-static struct smbcli_state *do_connect(const char *server, const char *share);
-
-
 /*******************************************************************
  Reduce a file name, removing .. elements.
 ********************************************************************/
 void dos_clean_name(char *s)
 {
-       char *p=NULL;
+       char *p=NULL,*r;
 
        DEBUG(3,("dos_clean_name [%s]\n",s));
 
@@ -117,17 +82,10 @@ void dos_clean_name(char *s)
        all_string_sub(s, "\\\\", "\\", 0);
 
        while ((p = strstr(s,"\\..\\")) != NULL) {
-               pstring s1;
-
-               *p = 0;
-               pstrcpy(s1,p+3);
-
-               if ((p=strrchr_m(s,'\\')) != NULL)
-                       *p = 0;
-               else
-                       *s = 0;
-               pstrcat(s,s1);
-       }  
+               *p = '\0';
+               if ((r = strrchr(s,'\\')) != NULL)
+                       memmove(r,p+3,strlen(p+3)+1);
+       }
 
        trim_string(s,NULL,"\\..");
 
@@ -138,8 +96,9 @@ void dos_clean_name(char *s)
 write to a local file with CR/LF->LF translation if appropriate. return the 
 number taken from the buffer. This may not equal the number written.
 ****************************************************************************/
-static int writefile(int f, char *b, int n)
+static int writefile(int f, const void *_b, int n, BOOL translation)
 {
+       const uint8_t *b = _b;
        int i;
 
        if (!translation) {
@@ -165,8 +124,9 @@ static int writefile(int f, char *b, int n)
   read from a file with LF->CR/LF translation if appropriate. return the 
   number read. read approx n bytes.
 ****************************************************************************/
-static int readfile(char *b, int n, XFILE *f)
+static int readfile(void *_b, int n, XFILE *f, BOOL translation)
 {
+       uint8_t *b = _b;
        int i;
        int c;
 
@@ -193,12 +153,13 @@ static int readfile(char *b, int n, XFILE *f)
 /****************************************************************************
 send a message
 ****************************************************************************/
-static void send_message(void)
+static void send_message(struct smbcli_state *cli, const char *desthost)
 {
+       char msg[1600];
        int total_len = 0;
        int grp_id;
 
-       if (!smbcli_message_start(cli->tree, desthost, username, &grp_id)) {
+       if (!smbcli_message_start(cli->tree, desthost, cli_credentials_get_username(cmdline_credentials), &grp_id)) {
                d_printf("message start: %s\n", smbcli_errstr(cli->tree));
                return;
        }
@@ -208,12 +169,9 @@ static void send_message(void)
 
        while (!feof(stdin) && total_len < 1600) {
                int maxlen = MIN(1600 - total_len,127);
-               pstring msg;
                int l=0;
                int c;
 
-               ZERO_ARRAY(msg);
-
                for (l=0;l<maxlen && (c=fgetc(stdin))!=EOF;l++) {
                        if (c == '\n')
                                msg[l++] = '\r';
@@ -244,12 +202,12 @@ static void send_message(void)
 /****************************************************************************
 check the space on a device
 ****************************************************************************/
-static int do_dskattr(void)
+static int do_dskattr(struct smbclient_context *ctx)
 {
        int total, bsize, avail;
 
-       if (NT_STATUS_IS_ERR(smbcli_dskattr(cli->tree, &bsize, &total, &avail))) {
-               d_printf("Error in dskattr: %s\n",smbcli_errstr(cli->tree)); 
+       if (NT_STATUS_IS_ERR(smbcli_dskattr(ctx->cli->tree, &bsize, &total, &avail))) {
+               d_printf("Error in dskattr: %s\n",smbcli_errstr(ctx->cli->tree)); 
                return 1;
        }
 
@@ -262,10 +220,9 @@ static int do_dskattr(void)
 /****************************************************************************
 show cd/pwd
 ****************************************************************************/
-static int cmd_pwd(const char **cmd_ptr)
+static int cmd_pwd(struct smbclient_context *ctx, const char **args)
 {
-       d_printf("Current directory is %s",service);
-       d_printf("%s\n",cur_dir);
+       d_printf("Current directory is %s\n", ctx->remote_cur_dir);
        return 0;
 }
 
@@ -280,77 +237,72 @@ static void dos_format(char *s)
 /****************************************************************************
 change directory - inner section
 ****************************************************************************/
-static int do_cd(char *newdir)
+static int do_cd(struct smbclient_context *ctx, const char *newdir)
 {
-       char *p = newdir;
-       pstring saved_dir;
-       pstring dname;
+       char *dname;
       
-       dos_format(newdir);
-
        /* Save the current directory in case the
           new directory is invalid */
-       pstrcpy(saved_dir, cur_dir);
-       if (*p == '\\')
-               pstrcpy(cur_dir,p);
+       if (newdir[0] == '\\')
+               dname = talloc_strdup(NULL, newdir);
        else
-               pstrcat(cur_dir,p);
-       if (*(cur_dir+strlen(cur_dir)-1) != '\\') {
-               pstrcat(cur_dir, "\\");
-       }
-       dos_clean_name(cur_dir);
-       pstrcpy(dname,cur_dir);
-       pstrcat(cur_dir,"\\");
-       dos_clean_name(cur_dir);
+               dname = talloc_asprintf(NULL, "%s\\%s", ctx->remote_cur_dir, newdir);
+
+       dos_format(dname);
+
+       if (*(dname+strlen(dname)-1) != '\\') {
+               dname = talloc_append_string(NULL, dname, "\\");
+       }
+       dos_clean_name(dname);
        
-       if (!strequal(cur_dir,"\\")) {
-               if (NT_STATUS_IS_ERR(smbcli_chkpath(cli->tree, dname))) {
-                       d_printf("cd %s: %s\n", dname, smbcli_errstr(cli->tree));
-                       pstrcpy(cur_dir,saved_dir);
-               }
+       if (NT_STATUS_IS_ERR(smbcli_chkpath(ctx->cli->tree, dname))) {
+               d_printf("cd %s: %s\n", dname, smbcli_errstr(ctx->cli->tree));
+               talloc_free(dname);
+       } else {
+               ctx->remote_cur_dir = dname;
        }
        
-       pstrcpy(cd_path,cur_dir);
-
        return 0;
 }
 
 /****************************************************************************
 change directory
 ****************************************************************************/
-static int cmd_cd(const char **cmd_ptr)
+static int cmd_cd(struct smbclient_context *ctx, const char **args)
 {
-       fstring buf;
        int rc = 0;
 
-       if (next_token(cmd_ptr,buf,NULL,sizeof(buf)))
-               rc = do_cd(buf);
+       if (args[1]) 
+               rc = do_cd(ctx, args[1]);
        else
-               d_printf("Current directory is %s\n",cur_dir);
+               d_printf("Current directory is %s\n",ctx->remote_cur_dir);
 
        return rc;
 }
 
 
-BOOL mask_match(struct smbcli_state *c, const char *string, char *pattern, 
+BOOL mask_match(struct smbcli_state *c, const char *string, const char *pattern, 
                BOOL is_case_sensitive)
 {
-       fstring p2, s2;
+       char *p2, *s2;
+       BOOL ret;
 
-       if (strcmp(string,"..") == 0)
+       if (ISDOTDOT(string))
                string = ".";
-       if (strcmp(pattern,".") == 0)
+       if (ISDOT(pattern))
                return False;
        
        if (is_case_sensitive)
                return ms_fnmatch(pattern, string, 
                                  c->transport->negotiate.protocol) == 0;
 
-       fstrcpy(p2, pattern);
-       fstrcpy(s2, string);
-       strlower(p2); 
-       strlower(s2);
-       return ms_fnmatch(p2, s2, c->transport->negotiate.protocol) == 0;
+       p2 = strlower_talloc(NULL, pattern);
+       s2 = strlower_talloc(NULL, string);
+       ret = ms_fnmatch(p2, s2, c->transport->negotiate.protocol) == 0;
+       talloc_free(p2);
+       talloc_free(s2);
+
+       return ret;
 }
 
 
@@ -358,22 +310,22 @@ BOOL mask_match(struct smbcli_state *c, const char *string, char *pattern,
 /*******************************************************************
   decide if a file should be operated on
   ********************************************************************/
-static BOOL do_this_one(struct clilist_file_info *finfo)
+static BOOL do_this_one(struct smbclient_context *ctx, struct clilist_file_info *finfo)
 {
        if (finfo->attrib & FILE_ATTRIBUTE_DIRECTORY) return(True);
 
-       if (*fileselection && 
-           !mask_match(cli, finfo->name,fileselection,False)) {
+       if (ctx->fileselection && 
+           !mask_match(ctx->cli, finfo->name,ctx->fileselection,False)) {
                DEBUG(3,("mask_match %s failed\n", finfo->name));
                return False;
        }
 
-       if (newer_than && finfo->mtime < newer_than) {
+       if (ctx->newer_than && finfo->mtime < ctx->newer_than) {
                DEBUG(3,("newer_than %s failed\n", finfo->name));
                return(False);
        }
 
-       if ((archive_level==1 || archive_level==2) && !(finfo->attrib & FILE_ATTRIBUTE_ARCHIVE)) {
+       if ((ctx->archive_level==1 || ctx->archive_level==2) && !(finfo->attrib & FILE_ATTRIBUTE_ARCHIVE)) {
                DEBUG(3,("archive %s failed\n", finfo->name));
                return(False);
        }
@@ -384,9 +336,9 @@ static BOOL do_this_one(struct clilist_file_info *finfo)
 /****************************************************************************
   display info about a file
   ****************************************************************************/
-static void display_finfo(struct clilist_file_info *finfo)
+static void display_finfo(struct smbclient_context *ctx, struct clilist_file_info *finfo)
 {
-       if (do_this_one(finfo)) {
+       if (do_this_one(ctx, finfo)) {
                time_t t = finfo->mtime; /* the time is assumed to be passed as GMT */
                char *astr = attrib_string(NULL, finfo->attrib);
                d_printf("  %-30s%7.7s %8.0f  %s",
@@ -403,9 +355,9 @@ static void display_finfo(struct clilist_file_info *finfo)
 /****************************************************************************
    accumulate size of a file
   ****************************************************************************/
-static void do_du(struct clilist_file_info *finfo)
+static void do_du(struct smbclient_context *ctx, struct clilist_file_info *finfo)
 {
-       if (do_this_one(finfo)) {
+       if (do_this_one(ctx, finfo)) {
                dir_total += finfo->size;
        }
 }
@@ -416,7 +368,7 @@ static char *do_list_queue = 0;
 static long do_list_queue_size = 0;
 static long do_list_queue_start = 0;
 static long do_list_queue_end = 0;
-static void (*do_list_fn)(struct clilist_file_info *);
+static void (*do_list_fn)(struct smbclient_context *, struct clilist_file_info *);
 
 /****************************************************************************
 functions for do_list_queue
@@ -457,11 +409,13 @@ static void init_do_list_queue(void)
 
 static void adjust_do_list_queue(void)
 {
+       if (do_list_queue == NULL) return;
+
        /*
         * If the starting point of the queue is more than half way through,
         * move everything toward the beginning.
         */
-       if (do_list_queue && (do_list_queue_start == do_list_queue_end))
+       if (do_list_queue_start == do_list_queue_end)
        {
                DEBUG(4,("do_list_queue is empty\n"));
                do_list_queue_start = do_list_queue_end = 0;
@@ -488,7 +442,7 @@ static void add_to_do_list_queue(const char* entry)
                do_list_queue_size *= 2;
                DEBUG(4,("enlarging do_list_queue to %d\n",
                         (int)do_list_queue_size));
-               dlq = Realloc(do_list_queue, do_list_queue_size);
+               dlq = realloc_p(do_list_queue, char, do_list_queue_size);
                if (! dlq) {
                        d_printf("failure enlarging do_list_queue to %d bytes\n",
                                 (int)do_list_queue_size);
@@ -537,29 +491,30 @@ a helper for do_list
   ****************************************************************************/
 static void do_list_helper(struct clilist_file_info *f, const char *mask, void *state)
 {
+       struct smbclient_context *ctx = state;
+
        if (f->attrib & FILE_ATTRIBUTE_DIRECTORY) {
-               if (do_list_dirs && do_this_one(f)) {
-                       do_list_fn(f);
+               if (do_list_dirs && do_this_one(ctx, f)) {
+                       do_list_fn(ctx, f);
                }
                if (do_list_recurse && 
-                   !strequal(f->name,".") && 
-                   !strequal(f->name,"..")) {
-                       pstring mask2;
+                   !ISDOT(f->name) &&
+                   !ISDOTDOT(f->name)) {
+                       char *mask2;
                        char *p;
 
-                       pstrcpy(mask2, mask);
+                       mask2 = talloc_strdup(NULL, mask);
                        p = strrchr_m(mask2,'\\');
                        if (!p) return;
                        p[1] = 0;
-                       pstrcat(mask2, f->name);
-                       pstrcat(mask2,"\\*");
+                       mask2 = talloc_asprintf_append(mask2, "%s\\*", f->name);
                        add_to_do_list_queue(mask2);
                }
                return;
        }
 
-       if (do_this_one(f)) {
-               do_list_fn(f);
+       if (do_this_one(ctx, f)) {
+               do_list_fn(ctx, f);
        }
 }
 
@@ -567,8 +522,8 @@ static void do_list_helper(struct clilist_file_info *f, const char *mask, void *
 /****************************************************************************
 a wrapper around smbcli_list that adds recursion
   ****************************************************************************/
-void do_list(const char *mask,uint16_t attribute,
-            void (*fn)(struct clilist_file_info *),BOOL rec, BOOL dirs)
+static void do_list(struct smbclient_context *ctx, const char *mask,uint16_t attribute,
+            void (*fn)(struct smbclient_context *, struct clilist_file_info *),BOOL rec, BOOL dirs)
 {
        static int in_do_list = 0;
 
@@ -598,9 +553,9 @@ void do_list(const char *mask,uint16_t attribute,
                         * during the call.
                         * Fix from E. Jay Berkenbilt (ejb@ql.org)
                         */
-                       pstring head;
-                       pstrcpy(head, do_list_queue_head());
-                       smbcli_list(cli->tree, head, attribute, do_list_helper, NULL);
+                       char *head;
+                       head = do_list_queue_head();
+                       smbcli_list(ctx->cli->tree, head, attribute, do_list_helper, ctx);
                        remove_do_list_queue_head();
                        if ((! do_list_queue_empty()) && (fn == display_finfo))
                        {
@@ -624,9 +579,9 @@ void do_list(const char *mask,uint16_t attribute,
        }
        else
        {
-               if (smbcli_list(cli->tree, mask, attribute, do_list_helper, NULL) == -1)
+               if (smbcli_list(ctx->cli->tree, mask, attribute, do_list_helper, ctx) == -1)
                {
-                       d_printf("%s listing %s\n", smbcli_errstr(cli->tree), mask);
+                       d_printf("%s listing %s\n", smbcli_errstr(ctx->cli->tree), mask);
                }
        }
 
@@ -637,38 +592,36 @@ void do_list(const char *mask,uint16_t attribute,
 /****************************************************************************
   get a directory listing
   ****************************************************************************/
-static int cmd_dir(const char **cmd_ptr)
+static int cmd_dir(struct smbclient_context *ctx, const char **args)
 {
        uint16_t attribute = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
-       pstring mask;
-       fstring buf;
-       char *p=buf;
+       char *mask;
        int rc;
        
        dir_total = 0;
-       pstrcpy(mask,cur_dir);
+       
+       mask = talloc_strdup(ctx, ctx->remote_cur_dir);
        if(mask[strlen(mask)-1]!='\\')
-               pstrcat(mask,"\\");
+               mask = talloc_append_string(ctx, mask,"\\");
        
-       if (next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
-               dos_format(p);
-               if (*p == '\\')
-                       pstrcpy(mask,p);
-               else
-                       pstrcat(mask,p);
+       if (args[1]) {
+               mask = talloc_strdup(ctx, args[1]);
+               if (mask[0] != '\\')
+                       mask = talloc_append_string(ctx, mask, "\\");
+               dos_format(mask);
        }
        else {
-               if (cli->tree->session->transport->negotiate.protocol <= 
+               if (ctx->cli->tree->session->transport->negotiate.protocol <= 
                    PROTOCOL_LANMAN1) { 
-                       pstrcat(mask,"*.*");
+                       mask = talloc_append_string(ctx, mask, "*.*");
                } else {
-                       pstrcat(mask,"*");
+                       mask = talloc_append_string(ctx, mask, "*");
                }
        }
 
-       do_list(mask, attribute, display_finfo, recurse, True);
+       do_list(ctx, mask, attribute, display_finfo, ctx->recurse, True);
 
-       rc = do_dskattr();
+       rc = do_dskattr(ctx);
 
        DEBUG(3, ("Total bytes listed: %.0f\n", dir_total));
 
@@ -679,32 +632,29 @@ static int cmd_dir(const char **cmd_ptr)
 /****************************************************************************
   get a directory listing
   ****************************************************************************/
-static int cmd_du(const char **cmd_ptr)
+static int cmd_du(struct smbclient_context *ctx, const char **args)
 {
        uint16_t attribute = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
-       pstring mask;
-       fstring buf;
-       char *p=buf;
        int rc;
+       char *mask;
        
        dir_total = 0;
-       pstrcpy(mask,cur_dir);
-       if(mask[strlen(mask)-1]!='\\')
-               pstrcat(mask,"\\");
        
-       if (next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
-               dos_format(p);
-               if (*p == '\\')
-                       pstrcpy(mask,p);
+       if (args[1]) {
+               if (args[1][0] == '\\')
+                       mask = talloc_strdup(ctx, args[1]);
                else
-                       pstrcat(mask,p);
+                       mask = talloc_asprintf(ctx, "%s\\%s", ctx->remote_cur_dir, args[1]);
+               dos_format(mask);
        } else {
-               pstrcat(mask,"\\*");
+               mask = talloc_asprintf(ctx, "%s\\*", ctx->remote_cur_dir);
        }
 
-       do_list(mask, attribute, do_du, recurse, True);
+       do_list(ctx, mask, attribute, do_du, ctx->recurse, True);
 
-       rc = do_dskattr();
+       talloc_free(mask);
+
+       rc = do_dskattr(ctx);
 
        d_printf("Total number of bytes: %.0f\n", dir_total);
 
@@ -715,11 +665,11 @@ static int cmd_du(const char **cmd_ptr)
 /****************************************************************************
   get a file from rname to lname
   ****************************************************************************/
-static int do_get(char *rname, const char *lname, BOOL reget)
+static int do_get(struct smbclient_context *ctx, char *rname, const char *lname, BOOL reget)
 {  
        int handle = 0, fnum;
        BOOL newhandle = False;
-       char *data;
+       uint8_t *data;
        struct timeval tp_start;
        int read_size = io_bufsize;
        uint16_t attr;
@@ -730,14 +680,14 @@ static int do_get(char *rname, const char *lname, BOOL reget)
 
        GetTimeOfDay(&tp_start);
 
-       if (lowercase) {
+       if (ctx->lowercase) {
                strlower(discard_const_p(char, lname));
        }
 
-       fnum = smbcli_open(cli->tree, rname, O_RDONLY, DENY_NONE);
+       fnum = smbcli_open(ctx->cli->tree, rname, O_RDONLY, DENY_NONE);
 
        if (fnum == -1) {
-               d_printf("%s opening remote file %s\n",smbcli_errstr(cli->tree),rname);
+               d_printf("%s opening remote file %s\n",smbcli_errstr(ctx->cli->tree),rname);
                return 1;
        }
 
@@ -764,29 +714,29 @@ static int do_get(char *rname, const char *lname, BOOL reget)
        }
 
 
-       if (NT_STATUS_IS_ERR(smbcli_qfileinfo(cli->tree, fnum, 
+       if (NT_STATUS_IS_ERR(smbcli_qfileinfo(ctx->cli->tree, fnum, 
                           &attr, &size, NULL, NULL, NULL, NULL, NULL)) &&
-           NT_STATUS_IS_ERR(smbcli_getattrE(cli->tree, fnum, 
+           NT_STATUS_IS_ERR(smbcli_getattrE(ctx->cli->tree, fnum, 
                          &attr, &size, NULL, NULL, NULL))) {
-               d_printf("getattrib: %s\n",smbcli_errstr(cli->tree));
+               d_printf("getattrib: %s\n",smbcli_errstr(ctx->cli->tree));
                return 1;
        }
 
        DEBUG(2,("getting file %s of size %.0f as %s ", 
                 rname, (double)size, lname));
 
-       if(!(data = (char *)malloc(read_size))) { 
+       if(!(data = (uint8_t *)malloc(read_size))) { 
                d_printf("malloc fail for size %d\n", read_size);
-               smbcli_close(cli->tree, fnum);
+               smbcli_close(ctx->cli->tree, fnum);
                return 1;
        }
 
        while (1) {
-               int n = smbcli_read(cli->tree, fnum, data, nread + start, read_size);
+               int n = smbcli_read(ctx->cli->tree, fnum, data, nread + start, read_size);
 
                if (n <= 0) break;
  
-               if (writefile(handle,data, n) != n) {
+               if (writefile(handle,data, n, ctx->translation) != n) {
                        d_printf("Error writing local file\n");
                        rc = 1;
                        break;
@@ -804,8 +754,8 @@ static int do_get(char *rname, const char *lname, BOOL reget)
 
        SAFE_FREE(data);
        
-       if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnum))) {
-               d_printf("Error %s closing remote file\n",smbcli_errstr(cli->tree));
+       if (NT_STATUS_IS_ERR(smbcli_close(ctx->cli->tree, fnum))) {
+               d_printf("Error %s closing remote file\n",smbcli_errstr(ctx->cli->tree));
                rc = 1;
        }
 
@@ -813,8 +763,8 @@ static int do_get(char *rname, const char *lname, BOOL reget)
                close(handle);
        }
 
-       if (archive_level >= 2 && (attr & FILE_ATTRIBUTE_ARCHIVE)) {
-               smbcli_setatr(cli->tree, rname, attr & ~(uint16_t)FILE_ATTRIBUTE_ARCHIVE, 0);
+       if (ctx->archive_level >= 2 && (attr & FILE_ATTRIBUTE_ARCHIVE)) {
+               smbcli_setatr(ctx->cli->tree, rname, attr & ~(uint16_t)FILE_ATTRIBUTE_ARCHIVE, 0);
        }
 
        {
@@ -840,27 +790,26 @@ static int do_get(char *rname, const char *lname, BOOL reget)
 /****************************************************************************
   get a file
   ****************************************************************************/
-static int cmd_get(const char **cmd_ptr)
+static int cmd_get(struct smbclient_context *ctx, const char **args)
 {
-       pstring lname;
-       pstring rname;
-       char *p;
+       const char *lname;
+       char *rname;
 
-       pstrcpy(rname,cur_dir);
-       pstrcat(rname,"\\");
-       
-       p = rname + strlen(rname);
-       
-       if (!next_token(cmd_ptr,p,NULL,sizeof(rname)-strlen(rname))) {
+       if (!args[1]) {
                d_printf("get <filename>\n");
                return 1;
        }
-       pstrcpy(lname,p);
-       dos_clean_name(rname);
+
+       rname = talloc_asprintf(ctx, "%s\\%s", ctx->remote_cur_dir, args[1]);
+
+       if (args[2]) 
+               lname = args[2];
+       else 
+               lname = args[1];
        
-       next_token(cmd_ptr,lname,NULL,sizeof(lname));
+       dos_clean_name(rname);
        
-       return do_get(rname, lname, False);
+       return do_get(ctx, rname, lname, False);
 }
 
 /****************************************************************************
@@ -868,7 +817,7 @@ static int cmd_get(const char **cmd_ptr)
 ****************************************************************************/
 static BOOL yesno(char *p)
 {
-       pstring ans;
+       char ans[4];
        printf("%s",p);
 
        if (!fgets(ans,sizeof(ans)-1,stdin))
@@ -883,104 +832,96 @@ static BOOL yesno(char *p)
 /****************************************************************************
   do a mget operation on one file
   ****************************************************************************/
-static void do_mget(struct clilist_file_info *finfo)
+static void do_mget(struct smbclient_context *ctx, struct clilist_file_info *finfo)
 {
-       pstring rname;
-       pstring quest;
-       pstring saved_curdir;
-       pstring mget_mask;
-
-       if (strequal(finfo->name,".") || strequal(finfo->name,".."))
-               return;
+       char *rname;
+       char *quest;
+       char *mget_mask;
+       char *saved_curdir;
 
-       if (abort_mget) {
-               d_printf("mget aborted\n");
+       if (ISDOT(finfo->name) || ISDOTDOT(finfo->name))
                return;
-       }
 
        if (finfo->attrib & FILE_ATTRIBUTE_DIRECTORY)
-               slprintf(quest,sizeof(pstring)-1,
-                        "Get directory %s? ",finfo->name);
+               asprintf(&quest, "Get directory %s? ",finfo->name);
        else
-               slprintf(quest,sizeof(pstring)-1,
-                        "Get file %s? ",finfo->name);
+               asprintf(&quest, "Get file %s? ",finfo->name);
 
-       if (prompt && !yesno(quest)) return;
+       if (ctx->prompt && !yesno(quest)) return;
+
+       SAFE_FREE(quest);
 
        if (!(finfo->attrib & FILE_ATTRIBUTE_DIRECTORY)) {
-               pstrcpy(rname,cur_dir);
-               pstrcat(rname,finfo->name);
-               do_get(rname, finfo->name, False);
+               asprintf(&rname, "%s%s",ctx->remote_cur_dir,finfo->name);
+               do_get(ctx, rname, finfo->name, False);
+               SAFE_FREE(rname);
                return;
        }
 
        /* handle directories */
-       pstrcpy(saved_curdir,cur_dir);
+       saved_curdir = talloc_strdup(NULL, ctx->remote_cur_dir);
 
-       pstrcat(cur_dir,finfo->name);
-       pstrcat(cur_dir,"\\");
+       ctx->remote_cur_dir = talloc_asprintf_append(NULL, "%s\\", finfo->name);
 
        string_replace(discard_const_p(char, finfo->name), '\\', '/');
-       if (lowercase) {
+       if (ctx->lowercase) {
                strlower(discard_const_p(char, finfo->name));
        }
        
-       if (!directory_exist(finfo->name,NULL) && 
+       if (!directory_exist(finfo->name) && 
            mkdir(finfo->name,0777) != 0) {
                d_printf("failed to create directory %s\n",finfo->name);
-               pstrcpy(cur_dir,saved_curdir);
                return;
        }
        
        if (chdir(finfo->name) != 0) {
                d_printf("failed to chdir to directory %s\n",finfo->name);
-               pstrcpy(cur_dir,saved_curdir);
                return;
        }
 
-       pstrcpy(mget_mask,cur_dir);
-       pstrcat(mget_mask,"*");
+       mget_mask = talloc_asprintf(NULL, "%s*", ctx->remote_cur_dir);
        
-       do_list(mget_mask, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY,do_mget,False, True);
+       do_list(ctx, mget_mask, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY,do_mget,False, True);
        chdir("..");
-       pstrcpy(cur_dir,saved_curdir);
+       talloc_free(ctx->remote_cur_dir);
+
+       ctx->remote_cur_dir = saved_curdir;
 }
 
 
 /****************************************************************************
 view the file using the pager
 ****************************************************************************/
-static int cmd_more(const char **cmd_ptr)
+static int cmd_more(struct smbclient_context *ctx, const char **args)
 {
-       fstring rname,lname,pager_cmd;
+       char *rname;
+       char *pager_cmd;
+       char *lname;
        char *pager;
        int fd;
        int rc = 0;
 
-       fstrcpy(rname,cur_dir);
-       fstrcat(rname,"\\");
-       
-       slprintf(lname,sizeof(lname)-1, "%s/smbmore.XXXXXX",tmpdir());
-       fd = smb_mkstemp(lname);
+       lname = talloc_asprintf(ctx, "%s/smbmore.XXXXXX",tmpdir());
+       fd = mkstemp(lname);
        if (fd == -1) {
                d_printf("failed to create temporary file for more\n");
                return 1;
        }
        close(fd);
 
-       if (!next_token(cmd_ptr,rname+strlen(rname),NULL,sizeof(rname)-strlen(rname))) {
+       if (!args[1]) {
                d_printf("more <filename>\n");
                unlink(lname);
                return 1;
        }
+       rname = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[1]);
        dos_clean_name(rname);
 
-       rc = do_get(rname, lname, False);
+       rc = do_get(ctx, rname, lname, False);
 
        pager=getenv("PAGER");
 
-       slprintf(pager_cmd,sizeof(pager_cmd)-1,
-                "%s %s",(pager? pager:PAGER), lname);
+       pager_cmd = talloc_asprintf(ctx, "%s %s",(pager? pager:PAGER), lname);
        system(pager_cmd);
        unlink(lname);
        
@@ -992,38 +933,32 @@ static int cmd_more(const char **cmd_ptr)
 /****************************************************************************
 do a mget command
 ****************************************************************************/
-static int cmd_mget(const char **cmd_ptr)
+static int cmd_mget(struct smbclient_context *ctx, const char **args)
 {
        uint16_t attribute = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
-       pstring mget_mask;
-       fstring buf;
-       char *p=buf;
-
-       *mget_mask = 0;
+       char *mget_mask = NULL;
+       int i;
 
-       if (recurse)
+       if (ctx->recurse)
                attribute |= FILE_ATTRIBUTE_DIRECTORY;
        
-       abort_mget = False;
-
-       while (next_token(cmd_ptr,p,NULL,sizeof(buf))) {
-               pstrcpy(mget_mask,cur_dir);
+       for (i = 1; args[i]; i++) {
+               mget_mask = talloc_strdup(ctx,ctx->remote_cur_dir);
                if(mget_mask[strlen(mget_mask)-1]!='\\')
-                       pstrcat(mget_mask,"\\");
+                       mget_mask = talloc_append_string(ctx, mget_mask, "\\");
                
-               if (*p == '\\')
-                       pstrcpy(mget_mask,p);
-               else
-                       pstrcat(mget_mask,p);
-               do_list(mget_mask, attribute,do_mget,False,True);
+               mget_mask = talloc_strdup(ctx, args[i]);
+               if (mget_mask[0] != '\\')
+                       mget_mask = talloc_append_string(ctx, mget_mask, "\\");
+               do_list(ctx, mget_mask, attribute,do_mget,False,True);
+
+               talloc_free(mget_mask);
        }
 
-       if (!*mget_mask) {
-               pstrcpy(mget_mask,cur_dir);
-               if(mget_mask[strlen(mget_mask)-1]!='\\')
-                       pstrcat(mget_mask,"\\");
-               pstrcat(mget_mask,"*");
-               do_list(mget_mask, attribute,do_mget,False,True);
+       if (mget_mask == NULL) {
+               mget_mask = talloc_asprintf(ctx, "%s\\*", ctx->remote_cur_dir);
+               do_list(ctx, mget_mask, attribute,do_mget,False,True);
+               talloc_free(mget_mask);
        }
        
        return 0;
@@ -1033,42 +968,26 @@ static int cmd_mget(const char **cmd_ptr)
 /****************************************************************************
 make a directory of name "name"
 ****************************************************************************/
-static NTSTATUS do_mkdir(char *name)
+static NTSTATUS do_mkdir(struct smbclient_context *ctx, char *name)
 {
        NTSTATUS status;
 
-       if (NT_STATUS_IS_ERR(status = smbcli_mkdir(cli->tree, name))) {
+       if (NT_STATUS_IS_ERR(status = smbcli_mkdir(ctx->cli->tree, name))) {
                d_printf("%s making remote directory %s\n",
-                        smbcli_errstr(cli->tree),name);
+                        smbcli_errstr(ctx->cli->tree),name);
                return status;
        }
 
        return status;
 }
 
-/****************************************************************************
-show 8.3 name of a file
-****************************************************************************/
-static BOOL do_altname(char *name)
-{
-       const char *altname;
-       if (!NT_STATUS_IS_OK(smbcli_qpathinfo_alt_name(cli->tree, name, &altname))) {
-               d_printf("%s getting alt name for %s\n",
-                        smbcli_errstr(cli->tree),name);
-               return(False);
-       }
-       d_printf("%s\n", altname);
-
-       return(True);
-}
-
 
 /****************************************************************************
  Exit client.
 ****************************************************************************/
-static int cmd_quit(const char **cmd_ptr)
+static int cmd_quit(struct smbclient_context *ctx, const char **args)
 {
-       smbcli_shutdown(cli);
+       talloc_free(ctx);
        exit(0);
        /* NOTREACHED */
        return 0;
@@ -1078,63 +997,59 @@ static int cmd_quit(const char **cmd_ptr)
 /****************************************************************************
   make a directory
   ****************************************************************************/
-static int cmd_mkdir(const char **cmd_ptr)
+static int cmd_mkdir(struct smbclient_context *ctx, const char **args)
 {
-       pstring mask;
-       fstring buf;
-       char *p=buf;
+       char *mask, *p;
   
-       pstrcpy(mask,cur_dir);
-
-       if (!next_token(cmd_ptr,p,NULL,sizeof(buf))) {
-               if (!recurse)
+       if (!args[1]) {
+               if (!ctx->recurse)
                        d_printf("mkdir <dirname>\n");
                return 1;
        }
-       pstrcat(mask,p);
 
-       if (recurse) {
-               pstring ddir;
-               pstring ddir2;
-               *ddir2 = 0;
-               
-               pstrcpy(ddir,mask);
-               trim_string(ddir,".",NULL);
-               p = strtok(ddir,"/\\");
-               while (p) {
-                       pstrcat(ddir2,p);
-                       if (NT_STATUS_IS_ERR(smbcli_chkpath(cli->tree, ddir2))) { 
-                               do_mkdir(ddir2);
+       mask = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir,args[1]);
+
+       if (ctx->recurse) {
+               dos_clean_name(mask);
+
+               trim_string(mask,".",NULL);
+               for (p = strtok(mask,"/\\"); p; p = strtok(p, "/\\")) {
+                       char *parent = talloc_strndup(ctx, mask, PTR_DIFF(p, mask));
+                       
+                       if (NT_STATUS_IS_ERR(smbcli_chkpath(ctx->cli->tree, parent))) { 
+                               do_mkdir(ctx, parent);
                        }
-                       pstrcat(ddir2,"\\");
-                       p = strtok(NULL,"/\\");
+
+                       talloc_free(parent);
                }        
        } else {
-               do_mkdir(mask);
+               do_mkdir(ctx, mask);
        }
        
        return 0;
 }
 
-
 /****************************************************************************
-  show alt name
-  ****************************************************************************/
-static int cmd_altname(const char **cmd_ptr)
+show 8.3 name of a file
+****************************************************************************/
+static int cmd_altname(struct smbclient_context *ctx, const char **args)
 {
-       pstring name;
-       fstring buf;
-       char *p=buf;
+       const char *altname;
+       char *name;
   
-       pstrcpy(name,cur_dir);
-
-       if (!next_token(cmd_ptr,p,NULL,sizeof(buf))) {
+       if (!args[1]) {
                d_printf("altname <file>\n");
                return 1;
        }
-       pstrcat(name,p);
 
-       do_altname(name);
+       name = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[1]);
+
+       if (!NT_STATUS_IS_OK(smbcli_qpathinfo_alt_name(ctx->cli->tree, name, &altname))) {
+               d_printf("%s getting alt name for %s\n",
+                        smbcli_errstr(ctx->cli->tree),name);
+               return(False);
+       }
+       d_printf("%s\n", altname);
 
        return 0;
 }
@@ -1143,13 +1058,13 @@ static int cmd_altname(const char **cmd_ptr)
 /****************************************************************************
   put a single file
   ****************************************************************************/
-static int do_put(char *rname, char *lname, BOOL reput)
+static int do_put(struct smbclient_context *ctx, char *rname, char *lname, BOOL reput)
 {
        int fnum;
        XFILE *f;
        size_t start = 0;
        off_t nread = 0;
-       char *buf = NULL;
+       uint8_t *buf = NULL;
        int maxwrite = io_bufsize;
        int rc = 0;
        
@@ -1157,21 +1072,21 @@ static int do_put(char *rname, char *lname, BOOL reput)
        GetTimeOfDay(&tp_start);
 
        if (reput) {
-               fnum = smbcli_open(cli->tree, rname, O_RDWR|O_CREAT, DENY_NONE);
+               fnum = smbcli_open(ctx->cli->tree, rname, O_RDWR|O_CREAT, DENY_NONE);
                if (fnum >= 0) {
-                       if (NT_STATUS_IS_ERR(smbcli_qfileinfo(cli->tree, fnum, NULL, &start, NULL, NULL, NULL, NULL, NULL)) &&
-                           NT_STATUS_IS_ERR(smbcli_getattrE(cli->tree, fnum, NULL, &start, NULL, NULL, NULL))) {
-                               d_printf("getattrib: %s\n",smbcli_errstr(cli->tree));
+                       if (NT_STATUS_IS_ERR(smbcli_qfileinfo(ctx->cli->tree, fnum, NULL, &start, NULL, NULL, NULL, NULL, NULL)) &&
+                           NT_STATUS_IS_ERR(smbcli_getattrE(ctx->cli->tree, fnum, NULL, &start, NULL, NULL, NULL))) {
+                               d_printf("getattrib: %s\n",smbcli_errstr(ctx->cli->tree));
                                return 1;
                        }
                }
        } else {
-               fnum = smbcli_open(cli->tree, rname, O_RDWR|O_CREAT|O_TRUNC, 
+               fnum = smbcli_open(ctx->cli->tree, rname, O_RDWR|O_CREAT|O_TRUNC, 
                                DENY_NONE);
        }
   
        if (fnum == -1) {
-               d_printf("%s opening remote file %s\n",smbcli_errstr(cli->tree),rname);
+               d_printf("%s opening remote file %s\n",smbcli_errstr(ctx->cli->tree),rname);
                return 1;
        }
 
@@ -1202,7 +1117,7 @@ static int do_put(char *rname, char *lname, BOOL reput)
        DEBUG(1,("putting file %s as %s ",lname,
                 rname));
   
-       buf = (char *)malloc(maxwrite);
+       buf = (uint8_t *)malloc(maxwrite);
        if (!buf) {
                d_printf("ERROR: Not enough memory!\n");
                return 1;
@@ -1211,7 +1126,7 @@ static int do_put(char *rname, char *lname, BOOL reput)
                int n = maxwrite;
                int ret;
 
-               if ((n = readfile(buf,n,f)) < 1) {
+               if ((n = readfile(buf,n,f,ctx->translation)) < 1) {
                        if((n == 0) && x_feof(f))
                                break; /* Empty local file. */
 
@@ -1220,10 +1135,10 @@ static int do_put(char *rname, char *lname, BOOL reput)
                        break;
                }
 
-               ret = smbcli_write(cli->tree, fnum, 0, buf, nread + start, n);
+               ret = smbcli_write(ctx->cli->tree, fnum, 0, buf, nread + start, n);
 
                if (n != ret) {
-                       d_printf("Error writing file: %s\n", smbcli_errstr(cli->tree));
+                       d_printf("Error writing file: %s\n", smbcli_errstr(ctx->cli->tree));
                        rc = 1;
                        break;
                } 
@@ -1231,8 +1146,8 @@ static int do_put(char *rname, char *lname, BOOL reput)
                nread += n;
        }
 
-       if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnum))) {
-               d_printf("%s closing remote file %s\n",smbcli_errstr(cli->tree),rname);
+       if (NT_STATUS_IS_ERR(smbcli_close(ctx->cli->tree, fnum))) {
+               d_printf("%s closing remote file %s\n",smbcli_errstr(ctx->cli->tree),rname);
                x_fclose(f);
                SAFE_FREE(buf);
                return 1;
@@ -1262,7 +1177,7 @@ static int do_put(char *rname, char *lname, BOOL reput)
        }
 
        if (f == x_stdin) {
-               smbcli_shutdown(cli);
+               talloc_free(ctx);
                exit(0);
        }
        
@@ -1274,41 +1189,33 @@ static int do_put(char *rname, char *lname, BOOL reput)
 /****************************************************************************
   put a file
   ****************************************************************************/
-static int cmd_put(const char **cmd_ptr)
+static int cmd_put(struct smbclient_context *ctx, const char **args)
 {
-       pstring lname;
-       pstring rname;
-       fstring buf;
-       char *p=buf;
+       char *lname;
+       char *rname;
        
-       pstrcpy(rname,cur_dir);
-       pstrcat(rname,"\\");
-  
-       if (!next_token(cmd_ptr,p,NULL,sizeof(buf))) {
-               d_printf("put <filename>\n");
+       if (!args[1]) {
+               d_printf("put <filename> [<remotename>]\n");
                return 1;
        }
-       pstrcpy(lname,p);
+
+       lname = talloc_strdup(ctx, args[1]);
   
-       if (next_token(cmd_ptr,p,NULL,sizeof(buf)))
-               pstrcat(rname,p);      
+       if (args[2])
+               rname = talloc_strdup(ctx, args[2]);
        else
-               pstrcat(rname,lname);
+               rname = talloc_asprintf(ctx, "%s\\%s", ctx->remote_cur_dir, lname);
        
        dos_clean_name(rname);
 
-       {
-               struct stat st;
-               /* allow '-' to represent stdin
-                  jdblair, 24.jun.98 */
-               if (!file_exist(lname,&st) &&
-                   (strcmp(lname,"-"))) {
-                       d_printf("%s does not exist\n",lname);
-                       return 1;
-               }
+       /* allow '-' to represent stdin
+          jdblair, 24.jun.98 */
+       if (!file_exist(lname) && (strcmp(lname,"-"))) {
+               d_printf("%s does not exist\n",lname);
+               return 1;
        }
 
-       return do_put(rname, lname, False);
+       return do_put(ctx, rname, lname, False);
 }
 
 /*************************************
@@ -1358,10 +1265,10 @@ static BOOL seek_list(struct file_list *list, char *name)
 /****************************************************************************
   set the file selection mask
   ****************************************************************************/
-static int cmd_select(const char **cmd_ptr)
+static int cmd_select(struct smbclient_context *ctx, const char **args)
 {
-       pstrcpy(fileselection,"");
-       next_token(cmd_ptr,fileselection,NULL,sizeof(fileselection));
+       talloc_free(ctx->fileselection);
+       ctx->fileselection = talloc_strdup(NULL, args[1]);
 
        return 0;
 }
@@ -1394,10 +1301,9 @@ static const char *readdirname(DIR *p)
 #endif
 
        {
-               static pstring buf;
+               static char *buf;
                int len = NAMLEN(ptr);
-               memcpy(buf, dname, len);
-               buf[len] = 0;
+               buf = talloc_strndup(NULL, dname, len);
                dname = buf;
        }
 
@@ -1408,7 +1314,7 @@ static const char *readdirname(DIR *p)
   Recursive file matching function act as find
   match must be always set to True when calling this function
 ****************************************************************************/
-static int file_find(struct file_list **list, const char *directory, 
+static int file_find(struct smbclient_context *ctx, struct file_list **list, const char *directory, 
                      const char *expression, BOOL match)
 {
        DIR *dir;
@@ -1423,8 +1329,9 @@ static int file_find(struct file_list **list, const char *directory,
        if (!dir) return -1;
        
         while ((dname = readdirname(dir))) {
-               if (!strcmp("..", dname)) continue;
-               if (!strcmp(".", dname)) continue;
+               if (ISDOT(dname) || ISDOTDOT(dname)) {
+                       continue;
+               }
                
                if (asprintf(&path, "%s/%s", directory, dname) <= 0) {
                        continue;
@@ -1432,12 +1339,12 @@ static int file_find(struct file_list **list, const char *directory,
 
                isdir = False;
                if (!match || !gen_fnmatch(expression, dname)) {
-                       if (recurse) {
+                       if (ctx->recurse) {
                                ret = stat(path, &statbuf);
                                if (ret == 0) {
                                        if (S_ISDIR(statbuf.st_mode)) {
                                                isdir = True;
-                                               ret = file_find(list, path, expression, False);
+                                               ret = file_find(ctx, list, path, expression, False);
                                        }
                                } else {
                                        d_printf("file_find: cannot stat file %s\n", path);
@@ -1449,7 +1356,7 @@ static int file_find(struct file_list **list, const char *directory,
                                        return -1;
                                }
                        }
-                       entry = (struct file_list *) malloc(sizeof (struct file_list));
+                       entry = malloc_p(struct file_list);
                        if (!entry) {
                                d_printf("Out of memory in file_find\n");
                                closedir(dir);
@@ -1470,19 +1377,20 @@ static int file_find(struct file_list **list, const char *directory,
 /****************************************************************************
   mput some files
   ****************************************************************************/
-static int cmd_mput(const char **cmd_ptr)
+static int cmd_mput(struct smbclient_context *ctx, const char **args)
 {
-       fstring buf;
-       char *p=buf;
+       int i;
        
-       while (next_token(cmd_ptr,p,NULL,sizeof(buf))) {
+       for (i = 1; args[i]; i++) {
                int ret;
                struct file_list *temp_list;
                char *quest, *lname, *rname;
+
+               printf("%s\n", args[i]);
        
                file_list = NULL;
 
-               ret = file_find(&file_list, ".", p, True);
+               ret = file_find(ctx, &file_list, ".", args[i], True);
                if (ret) {
                        free_file_list(file_list);
                        continue;
@@ -1506,17 +1414,17 @@ static int cmd_mput(const char **cmd_ptr)
                                
                                SAFE_FREE(quest);
                                if (asprintf(&quest, "Put directory %s? ", lname) < 0) break;
-                               if (prompt && !yesno(quest)) { /* No */
+                               if (ctx->prompt && !yesno(quest)) { /* No */
                                        /* Skip the directory */
                                        lname[strlen(lname)-1] = '/';
                                        if (!seek_list(temp_list, lname))
                                                break;              
                                } else { /* Yes */
                                        SAFE_FREE(rname);
-                                       if(asprintf(&rname, "%s%s", cur_dir, lname) < 0) break;
+                                       if(asprintf(&rname, "%s%s", ctx->remote_cur_dir, lname) < 0) break;
                                        dos_format(rname);
-                                       if (NT_STATUS_IS_ERR(smbcli_chkpath(cli->tree, rname)) && 
-                                           NT_STATUS_IS_ERR(do_mkdir(rname))) {
+                                       if (NT_STATUS_IS_ERR(smbcli_chkpath(ctx->cli->tree, rname)) && 
+                                           NT_STATUS_IS_ERR(do_mkdir(ctx, rname))) {
                                                DEBUG (0, ("Unable to make dir, skipping..."));
                                                /* Skip the directory */
                                                lname[strlen(lname)-1] = '/';
@@ -1528,17 +1436,17 @@ static int cmd_mput(const char **cmd_ptr)
                        } else {
                                SAFE_FREE(quest);
                                if (asprintf(&quest,"Put file %s? ", lname) < 0) break;
-                               if (prompt && !yesno(quest)) /* No */
+                               if (ctx->prompt && !yesno(quest)) /* No */
                                        continue;
                                
                                /* Yes */
                                SAFE_FREE(rname);
-                               if (asprintf(&rname, "%s%s", cur_dir, lname) < 0) break;
+                               if (asprintf(&rname, "%s%s", ctx->remote_cur_dir, lname) < 0) break;
                        }
 
                        dos_format(rname);
 
-                       do_put(rname, lname, False);
+                       do_put(ctx, rname, lname, False);
                }
                free_file_list(file_list);
                SAFE_FREE(quest);
@@ -1550,52 +1458,22 @@ static int cmd_mput(const char **cmd_ptr)
 }
 
 
-/****************************************************************************
-  cancel a print job
-  ****************************************************************************/
-static int do_cancel(int job)
-{
-       d_printf("REWRITE: print job cancel not implemented\n");
-       return 1;
-}
-
-
-/****************************************************************************
-  cancel a print job
-  ****************************************************************************/
-static int cmd_cancel(const char **cmd_ptr)
-{
-       fstring buf;
-       int job; 
-
-       if (!next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
-               d_printf("cancel <jobid> ...\n");
-               return 1;
-       }
-       do {
-               job = atoi(buf);
-               do_cancel(job);
-       } while (next_token(cmd_ptr,buf,NULL,sizeof(buf)));
-       
-       return 0;
-}
-
-
 /****************************************************************************
   print a file
   ****************************************************************************/
-static int cmd_print(const char **cmd_ptr)
+static int cmd_print(struct smbclient_context *ctx, const char **args)
 {
-       pstring lname;
-       pstring rname;
+       char *lname, *rname;
        char *p;
 
-       if (!next_token(cmd_ptr,lname,NULL, sizeof(lname))) {
+       if (!args[1]) {
                d_printf("print <filename>\n");
                return 1;
        }
 
-       pstrcpy(rname,lname);
+       lname = talloc_strdup(ctx, args[1]);
+
+       rname = talloc_strdup(ctx, lname);
        p = strrchr_m(rname,'/');
        if (p) {
                slprintf(rname, sizeof(rname)-1, "%s-%d", p+1, (int)getpid());
@@ -1605,16 +1483,13 @@ static int cmd_print(const char **cmd_ptr)
                slprintf(rname, sizeof(rname)-1, "stdin-%d", (int)getpid());
        }
 
-       return do_put(rname, lname, False);
+       return do_put(ctx, rname, lname, False);
 }
 
 
-/****************************************************************************
- show a print queue
-****************************************************************************/
-static int cmd_queue(const char **cmd_ptr)
+static int cmd_rewrite(struct smbclient_context *ctx, const char **args)
 {
-       d_printf("REWRITE: print job queue not implemented\n");
+       d_printf("REWRITE: command not implemented (FIXME!)\n");
        
        return 0;
 }
@@ -1622,25 +1497,22 @@ static int cmd_queue(const char **cmd_ptr)
 /****************************************************************************
 delete some files
 ****************************************************************************/
-static int cmd_del(const char **cmd_ptr)
+static int cmd_del(struct smbclient_context *ctx, const char **args)
 {
-       pstring mask;
-       fstring buf;
+       char *mask;
        uint16_t attribute = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
 
-       if (recurse)
+       if (ctx->recurse)
                attribute |= FILE_ATTRIBUTE_DIRECTORY;
        
-       pstrcpy(mask,cur_dir);
-       
-       if (!next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
+       if (!args[1]) {
                d_printf("del <filename>\n");
                return 1;
        }
-       pstrcat(mask,buf);
+       mask = talloc_asprintf(ctx,"%s%s", ctx->remote_cur_dir, args[1]);
 
-       if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, mask))) {
-               d_printf("%s deleting remote file %s\n",smbcli_errstr(cli->tree),mask);
+       if (NT_STATUS_IS_ERR(smbcli_unlink(ctx->cli->tree, mask))) {
+               d_printf("%s deleting remote file %s\n",smbcli_errstr(ctx->cli->tree),mask);
        }
        
        return 0;
@@ -1650,24 +1522,22 @@ static int cmd_del(const char **cmd_ptr)
 /****************************************************************************
 delete a whole directory tree
 ****************************************************************************/
-static int cmd_deltree(const char **cmd_ptr)
+static int cmd_deltree(struct smbclient_context *ctx, const char **args)
 {
-       pstring dname;
-       fstring buf;
+       char *dname;
        int ret;
 
-       pstrcpy(dname,cur_dir);
-       
-       if (!next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
+       if (!args[1]) {
                d_printf("deltree <dirname>\n");
                return 1;
        }
-       pstrcat(dname,buf);
 
-       ret = smbcli_deltree(cli->tree, dname);
+       dname = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[1]);
+       
+       ret = smbcli_deltree(ctx->cli->tree, dname);
 
        if (ret == -1) {
-               printf("Failed to delete tree %s - %s\n", dname, smbcli_errstr(cli->tree));
+               printf("Failed to delete tree %s - %s\n", dname, smbcli_errstr(ctx->cli->tree));
                return -1;
        }
 
@@ -1676,43 +1546,207 @@ static int cmd_deltree(const char **cmd_ptr)
        return 0;
 }
 
+typedef struct {
+       const char  *level_name;
+       enum smb_fsinfo_level level;
+} fsinfo_level_t;
+
+fsinfo_level_t fsinfo_levels[] = {
+       {"dskattr", RAW_QFS_DSKATTR},
+       {"allocation", RAW_QFS_ALLOCATION},
+       {"volume", RAW_QFS_VOLUME},
+       {"volumeinfo", RAW_QFS_VOLUME_INFO},
+       {"sizeinfo", RAW_QFS_SIZE_INFO},
+       {"deviceinfo", RAW_QFS_DEVICE_INFO},
+       {"attributeinfo", RAW_QFS_ATTRIBUTE_INFO},
+       {"unixinfo", RAW_QFS_UNIX_INFO},
+       {"volume-information", RAW_QFS_VOLUME_INFORMATION},
+       {"size-information", RAW_QFS_SIZE_INFORMATION},
+       {"device-information", RAW_QFS_DEVICE_INFORMATION},
+       {"attribute-information", RAW_QFS_ATTRIBUTE_INFORMATION},
+       {"quota-information", RAW_QFS_QUOTA_INFORMATION},
+       {"fullsize-information", RAW_QFS_FULL_SIZE_INFORMATION},
+       {"objectid", RAW_QFS_OBJECTID_INFORMATION},
+       {NULL, RAW_QFS_GENERIC}
+};
+
+
+static int cmd_fsinfo(struct smbclient_context *ctx, const char **args)
+{
+       union smb_fsinfo fsinfo;
+       NTSTATUS status;
+       fsinfo_level_t *fsinfo_level;
+       
+       if (!args[1]) {
+               d_printf("fsinfo <level>, where level is one of following:\n");
+               fsinfo_level = fsinfo_levels;
+               while(fsinfo_level->level_name) {
+                       d_printf("%s\n", fsinfo_level->level_name);
+                       fsinfo_level++;
+               }
+               return 1;
+       }
+       
+       fsinfo_level = fsinfo_levels;
+       while(fsinfo_level->level_name && !strequal(args[1],fsinfo_level->level_name)) {
+               fsinfo_level++;
+       }
+  
+       if (!fsinfo_level->level_name) {
+               d_printf("wrong level name!\n");
+               return 1;
+       }
+  
+       fsinfo.generic.level = fsinfo_level->level;
+       status = smb_raw_fsinfo(ctx->cli->tree, ctx, &fsinfo);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_printf("fsinfo-level-%s - %s\n", fsinfo_level->level_name, nt_errstr(status));
+               return 1;
+       }
+
+       d_printf("fsinfo-level-%s:\n", fsinfo_level->level_name);
+       switch(fsinfo.generic.level) {
+       case RAW_QFS_DSKATTR:
+               d_printf("\tunits_total:                %hu\n", 
+                        (unsigned short) fsinfo.dskattr.out.units_total);
+               d_printf("\tblocks_per_unit:            %hu\n", 
+                        (unsigned short) fsinfo.dskattr.out.blocks_per_unit);
+               d_printf("\tblocks_size:                %hu\n", 
+                        (unsigned short) fsinfo.dskattr.out.block_size);
+               d_printf("\tunits_free:                 %hu\n", 
+                        (unsigned short) fsinfo.dskattr.out.units_free);
+               break;
+       case RAW_QFS_ALLOCATION:
+               d_printf("\tfs_id:                      %lu\n", 
+                        (unsigned long) fsinfo.allocation.out.fs_id);
+               d_printf("\tsectors_per_unit:           %lu\n", 
+                        (unsigned long) fsinfo.allocation.out.sectors_per_unit);
+               d_printf("\ttotal_alloc_units:          %lu\n", 
+                        (unsigned long) fsinfo.allocation.out.total_alloc_units);
+               d_printf("\tavail_alloc_units:          %lu\n", 
+                        (unsigned long) fsinfo.allocation.out.avail_alloc_units);
+               d_printf("\tbytes_per_sector:           %hu\n", 
+                        (unsigned short) fsinfo.allocation.out.bytes_per_sector);
+               break;
+       case RAW_QFS_VOLUME:
+               d_printf("\tserial_number:              %lu\n", 
+                        (unsigned long) fsinfo.volume.out.serial_number);
+               d_printf("\tvolume_name:                %s\n", fsinfo.volume.out.volume_name.s);
+               break;
+       case RAW_QFS_VOLUME_INFO:
+       case RAW_QFS_VOLUME_INFORMATION:
+               d_printf("\tcreate_time:                %s\n",
+                        nt_time_string(ctx,fsinfo.volume_info.out.create_time));
+               d_printf("\tserial_number:              %lu\n", 
+                        (unsigned long) fsinfo.volume_info.out.serial_number);
+               d_printf("\tvolume_name:                %s\n", fsinfo.volume_info.out.volume_name.s);
+               break;
+       case RAW_QFS_SIZE_INFO:
+       case RAW_QFS_SIZE_INFORMATION:
+               d_printf("\ttotal_alloc_units:          %llu\n", 
+                        (unsigned long long) fsinfo.size_info.out.total_alloc_units);
+               d_printf("\tavail_alloc_units:          %llu\n", 
+                        (unsigned long long) fsinfo.size_info.out.avail_alloc_units);
+               d_printf("\tsectors_per_unit:           %lu\n", 
+                        (unsigned long) fsinfo.size_info.out.sectors_per_unit);
+               d_printf("\tbytes_per_sector:           %lu\n", 
+                        (unsigned long) fsinfo.size_info.out.bytes_per_sector);
+               break;
+       case RAW_QFS_DEVICE_INFO:
+       case RAW_QFS_DEVICE_INFORMATION:
+               d_printf("\tdevice_type:                %lu\n", 
+                        (unsigned long) fsinfo.device_info.out.device_type);
+               d_printf("\tcharacteristics:            0x%lx\n", 
+                        (unsigned long) fsinfo.device_info.out.characteristics);
+               break;
+       case RAW_QFS_ATTRIBUTE_INFORMATION:
+       case RAW_QFS_ATTRIBUTE_INFO:
+               d_printf("\tfs_attr:                    0x%lx\n", 
+                        (unsigned long) fsinfo.attribute_info.out.fs_attr);
+               d_printf("\tmax_file_component_length:  %lu\n", 
+                        (unsigned long) fsinfo.attribute_info.out.max_file_component_length);
+               d_printf("\tfs_type:                    %s\n", fsinfo.attribute_info.out.fs_type.s);
+               break;
+       case RAW_QFS_UNIX_INFO:
+               d_printf("\tmajor_version:              %hu\n", 
+                        (unsigned short) fsinfo.unix_info.out.major_version);
+               d_printf("\tminor_version:              %hu\n", 
+                        (unsigned short) fsinfo.unix_info.out.minor_version);
+               d_printf("\tcapability:                 0x%llx\n", 
+                        (unsigned long long) fsinfo.unix_info.out.capability);
+               break;
+       case RAW_QFS_QUOTA_INFORMATION:
+               d_printf("\tunknown[3]:                 [%llu,%llu,%llu]\n", 
+                        (unsigned long long) fsinfo.quota_information.out.unknown[0],
+                        (unsigned long long) fsinfo.quota_information.out.unknown[1],
+                        (unsigned long long) fsinfo.quota_information.out.unknown[2]);
+               d_printf("\tquota_soft:                 %llu\n", 
+                        (unsigned long long) fsinfo.quota_information.out.quota_soft);
+               d_printf("\tquota_hard:                 %llu\n", 
+                        (unsigned long long) fsinfo.quota_information.out.quota_hard);
+               d_printf("\tquota_flags:                0x%llx\n", 
+                        (unsigned long long) fsinfo.quota_information.out.quota_flags);
+               break;
+       case RAW_QFS_FULL_SIZE_INFORMATION:
+               d_printf("\ttotal_alloc_units:          %llu\n", 
+                        (unsigned long long) fsinfo.full_size_information.out.total_alloc_units);
+               d_printf("\tcall_avail_alloc_units:     %llu\n", 
+                        (unsigned long long) fsinfo.full_size_information.out.call_avail_alloc_units);
+               d_printf("\tactual_avail_alloc_units:   %llu\n", 
+                        (unsigned long long) fsinfo.full_size_information.out.actual_avail_alloc_units);
+               d_printf("\tsectors_per_unit:           %lu\n", 
+                        (unsigned long) fsinfo.full_size_information.out.sectors_per_unit);
+               d_printf("\tbytes_per_sector:           %lu\n", 
+                        (unsigned long) fsinfo.full_size_information.out.bytes_per_sector);
+               break;
+       case RAW_QFS_OBJECTID_INFORMATION:
+               d_printf("\tGUID:                       %s\n", 
+                        GUID_string(ctx,&fsinfo.objectid_information.out.guid));
+               d_printf("\tunknown[6]:                 [%llu,%llu,%llu,%llu,%llu,%llu]\n", 
+                        (unsigned long long) fsinfo.objectid_information.out.unknown[0],
+                        (unsigned long long) fsinfo.objectid_information.out.unknown[1],
+                        (unsigned long long) fsinfo.objectid_information.out.unknown[2],
+                        (unsigned long long) fsinfo.objectid_information.out.unknown[3],
+                        (unsigned long long) fsinfo.objectid_information.out.unknown[4],
+                        (unsigned long long) fsinfo.objectid_information.out.unknown[5] );
+               break;
+       case RAW_QFS_GENERIC:
+               d_printf("\twrong level returned\n");
+               break;
+       }
+  
+       return 0;
+}
 
 /****************************************************************************
 show as much information as possible about a file
 ****************************************************************************/
-static int cmd_allinfo(const char **cmd_ptr)
+static int cmd_allinfo(struct smbclient_context *ctx, const char **args)
 {
-       pstring fname;
-       fstring buf;
-       int ret = 0;
-       TALLOC_CTX *mem_ctx;
+       char *fname;
        union smb_fileinfo finfo;
        NTSTATUS status;
+       int fnum;
 
-       pstrcpy(fname,cur_dir);
-       
-       if (!next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
+       if (!args[1]) {
                d_printf("allinfo <filename>\n");
                return 1;
        }
-       pstrcat(fname,buf);
-
-       mem_ctx = talloc_init("%s", fname);
+       fname = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[1]);
 
        /* first a ALL_INFO QPATHINFO */
        finfo.generic.level = RAW_FILEINFO_ALL_INFO;
-       finfo.generic.in.fname = fname;
-       status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
+       finfo.generic.in.file.path = fname;
+       status = smb_raw_pathinfo(ctx->cli->tree, ctx, &finfo);
        if (!NT_STATUS_IS_OK(status)) {
                d_printf("%s - %s\n", fname, nt_errstr(status));
-               ret = 1;
-               goto done;
+               return 1;
        }
 
-       d_printf("\tcreate_time:    %s\n", nt_time_string(mem_ctx, finfo.all_info.out.create_time));
-       d_printf("\taccess_time:    %s\n", nt_time_string(mem_ctx, finfo.all_info.out.access_time));
-       d_printf("\twrite_time:     %s\n", nt_time_string(mem_ctx, finfo.all_info.out.write_time));
-       d_printf("\tchange_time:    %s\n", nt_time_string(mem_ctx, finfo.all_info.out.change_time));
+       d_printf("\tcreate_time:    %s\n", nt_time_string(ctx, finfo.all_info.out.create_time));
+       d_printf("\taccess_time:    %s\n", nt_time_string(ctx, finfo.all_info.out.access_time));
+       d_printf("\twrite_time:     %s\n", nt_time_string(ctx, finfo.all_info.out.write_time));
+       d_printf("\tchange_time:    %s\n", nt_time_string(ctx, finfo.all_info.out.change_time));
        d_printf("\tattrib:         0x%x\n", finfo.all_info.out.attrib);
        d_printf("\talloc_size:     %lu\n", (unsigned long)finfo.all_info.out.alloc_size);
        d_printf("\tsize:           %lu\n", (unsigned long)finfo.all_info.out.size);
@@ -1724,14 +1758,14 @@ static int cmd_allinfo(const char **cmd_ptr)
 
        /* 8.3 name if any */
        finfo.generic.level = RAW_FILEINFO_ALT_NAME_INFO;
-       status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
+       status = smb_raw_pathinfo(ctx->cli->tree, ctx, &finfo);
        if (NT_STATUS_IS_OK(status)) {
                d_printf("\talt_name:       %s\n", finfo.alt_name_info.out.fname.s);
        }
 
        /* file_id if available */
        finfo.generic.level = RAW_FILEINFO_INTERNAL_INFORMATION;
-       status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
+       status = smb_raw_pathinfo(ctx->cli->tree, ctx, &finfo);
        if (NT_STATUS_IS_OK(status)) {
                d_printf("\tfile_id         %.0f\n", 
                         (double)finfo.internal_information.out.file_id);
@@ -1739,22 +1773,20 @@ static int cmd_allinfo(const char **cmd_ptr)
 
        /* the EAs, if any */
        finfo.generic.level = RAW_FILEINFO_ALL_EAS;
-       status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
+       status = smb_raw_pathinfo(ctx->cli->tree, ctx, &finfo);
        if (NT_STATUS_IS_OK(status)) {
                int i;
                for (i=0;i<finfo.all_eas.out.num_eas;i++) {
-                       d_printf("\tEA[%d] flags=%d %s=%*.*s\n", i,
+                       d_printf("\tEA[%d] flags=%d len=%d '%s'\n", i,
                                 finfo.all_eas.out.eas[i].flags,
-                                finfo.all_eas.out.eas[i].name.s,
-                                finfo.all_eas.out.eas[i].value.length,
-                                finfo.all_eas.out.eas[i].value.length,
-                                finfo.all_eas.out.eas[i].value.data);
+                                (int)finfo.all_eas.out.eas[i].value.length,
+                                finfo.all_eas.out.eas[i].name.s);
                }
        }
 
        /* streams, if available */
        finfo.generic.level = RAW_FILEINFO_STREAM_INFO;
-       status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
+       status = smb_raw_pathinfo(ctx->cli->tree, ctx, &finfo);
        if (NT_STATUS_IS_OK(status)) {
                int i;
                for (i=0;i<finfo.stream_info.out.num_streams;i++) {
@@ -1769,7 +1801,7 @@ static int cmd_allinfo(const char **cmd_ptr)
 
        /* dev/inode if available */
        finfo.generic.level = RAW_FILEINFO_COMPRESSION_INFORMATION;
-       status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
+       status = smb_raw_pathinfo(ctx->cli->tree, ctx, &finfo);
        if (NT_STATUS_IS_OK(status)) {
                d_printf("\tcompressed size %ld\n", (long)finfo.compression_info.out.compressed_size);
                d_printf("\tformat          %ld\n", (long)finfo.compression_info.out.format);
@@ -1778,78 +1810,310 @@ static int cmd_allinfo(const char **cmd_ptr)
                d_printf("\tcluster_shift   %ld\n", (long)finfo.compression_info.out.cluster_shift);
        }
 
-       talloc_destroy(mem_ctx);
+       /* shadow copies if available */
+       fnum = smbcli_open(ctx->cli->tree, fname, O_RDONLY, DENY_NONE);
+       if (fnum != -1) {
+               struct smb_shadow_copy info;
+               int i;
+               info.in.file.fnum = fnum;
+               info.in.max_data = ~0;
+               status = smb_raw_shadow_data(ctx->cli->tree, ctx, &info);
+               if (NT_STATUS_IS_OK(status)) {
+                       d_printf("\tshadow_copy: %u volumes  %u names\n",
+                                info.out.num_volumes, info.out.num_names);
+                       for (i=0;i<info.out.num_names;i++) {
+                               d_printf("\t%s\n", info.out.names[i]);
+                               finfo.generic.level = RAW_FILEINFO_ALL_INFO;
+                               finfo.generic.in.file.path = talloc_asprintf(ctx, "%s%s", 
+                                                                            info.out.names[i], fname); 
+                               status = smb_raw_pathinfo(ctx->cli->tree, ctx, &finfo);
+                               if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_NOT_FOUND) ||
+                                   NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+                                       continue;
+                               }
+                               if (!NT_STATUS_IS_OK(status)) {
+                                       d_printf("%s - %s\n", finfo.generic.in.file.path, 
+                                                nt_errstr(status));
+                                       return 1;
+                               }
+                               
+                               d_printf("\t\tcreate_time:    %s\n", nt_time_string(ctx, finfo.all_info.out.create_time));
+                               d_printf("\t\twrite_time:     %s\n", nt_time_string(ctx, finfo.all_info.out.write_time));
+                               d_printf("\t\tchange_time:    %s\n", nt_time_string(ctx, finfo.all_info.out.change_time));
+                               d_printf("\t\tsize:           %lu\n", (unsigned long)finfo.all_info.out.size);
+                       }
+               }
+       }
+       
+       return 0;
+}
 
-done:
-       return ret;
+
+/****************************************************************************
+shows EA contents
+****************************************************************************/
+static int cmd_eainfo(struct smbclient_context *ctx, const char **args)
+{
+       char *fname;
+       union smb_fileinfo finfo;
+       NTSTATUS status;
+       int i;
+
+       if (!args[1]) {
+               d_printf("eainfo <filename>\n");
+               return 1;
+       }
+       fname = talloc_strdup(ctx, args[1]);
+
+       finfo.generic.level = RAW_FILEINFO_ALL_EAS;
+       finfo.generic.in.file.path = fname;
+       status = smb_raw_pathinfo(ctx->cli->tree, ctx, &finfo);
+       
+       if (!NT_STATUS_IS_OK(status)) {
+               d_printf("RAW_FILEINFO_ALL_EAS - %s\n", nt_errstr(status));
+               return 1;
+       }
+
+       d_printf("%s has %d EAs\n", fname, finfo.all_eas.out.num_eas);
+
+       for (i=0;i<finfo.all_eas.out.num_eas;i++) {
+               d_printf("\tEA[%d] flags=%d len=%d '%s'\n", i,
+                        finfo.all_eas.out.eas[i].flags,
+                        (int)finfo.all_eas.out.eas[i].value.length,
+                        finfo.all_eas.out.eas[i].name.s);
+               fflush(stdout);
+               dump_data(0, 
+                         finfo.all_eas.out.eas[i].value.data,
+                         finfo.all_eas.out.eas[i].value.length);
+       }
+
+       return 0;
 }
 
 
 /****************************************************************************
 show any ACL on a file
 ****************************************************************************/
-static int cmd_acl(const char **cmd_ptr)
+static int cmd_acl(struct smbclient_context *ctx, const char **args)
 {
-       pstring fname;
-       fstring buf;
-       int ret = 0;
-       TALLOC_CTX *mem_ctx;
+       char *fname;
        union smb_fileinfo query;
        NTSTATUS status;
        int fnum;
 
-       pstrcpy(fname,cur_dir);
-       
-       if (!next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
+       if (!args[1]) {
                d_printf("acl <filename>\n");
                return 1;
        }
-       pstrcat(fname,buf);
+       fname = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[1]);
 
-       fnum = smbcli_open(cli->tree, fname, O_RDONLY, DENY_NONE);
+       fnum = smbcli_nt_create_full(ctx->cli->tree, fname, 0, 
+                                    SEC_STD_READ_CONTROL,
+                                    0,
+                                    NTCREATEX_SHARE_ACCESS_DELETE|
+                                    NTCREATEX_SHARE_ACCESS_READ|
+                                    NTCREATEX_SHARE_ACCESS_WRITE, 
+                                    NTCREATEX_DISP_OPEN,
+                                    0, 0);
        if (fnum == -1) {
-               d_printf("%s - %s\n", fname, smbcli_errstr(cli->tree));
+               d_printf("%s - %s\n", fname, smbcli_errstr(ctx->cli->tree));
                return -1;
        }
 
-       mem_ctx = talloc_init("%s", fname);
-
        query.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
-       query.query_secdesc.in.fnum = fnum;
+       query.query_secdesc.in.file.fnum = fnum;
        query.query_secdesc.in.secinfo_flags = 0x7;
 
-       status = smb_raw_fileinfo(cli->tree, mem_ctx, &query);
+       status = smb_raw_fileinfo(ctx->cli->tree, ctx, &query);
        if (!NT_STATUS_IS_OK(status)) {
                d_printf("%s - %s\n", fname, nt_errstr(status));
-               ret = 1;
-               goto done;
+               return 1;
        }
 
        NDR_PRINT_DEBUG(security_descriptor, query.query_secdesc.out.sd);
 
-       talloc_destroy(mem_ctx);
+       return 0;
+}
+
+/****************************************************************************
+lookup a name or sid
+****************************************************************************/
+static int cmd_lookup(struct smbclient_context *ctx, const char **args)
+{
+       NTSTATUS status;
+       struct dom_sid *sid;
 
-done:
-       return ret;
+       if (!args[1]) {
+               d_printf("lookup <sid|name>\n");
+               return 1;
+       }
+
+       sid = dom_sid_parse_talloc(ctx, args[1]);
+       if (sid == NULL) {
+               const char *sidstr;
+               status = smblsa_lookup_name(ctx->cli, args[1], ctx, &sidstr);
+               if (!NT_STATUS_IS_OK(status)) {
+                       d_printf("lsa_LookupNames - %s\n", nt_errstr(status));
+                       return 1;
+               }
+
+               d_printf("%s\n", sidstr);
+       } else {
+               const char *name;
+               status = smblsa_lookup_sid(ctx->cli, args[1], ctx, &name);
+               if (!NT_STATUS_IS_OK(status)) {
+                       d_printf("lsa_LookupSids - %s\n", nt_errstr(status));
+                       return 1;
+               }
+
+               d_printf("%s\n", name);
+       }
+
+       return 0;
+}
+
+/****************************************************************************
+show privileges for a user
+****************************************************************************/
+static int cmd_privileges(struct smbclient_context *ctx, const char **args)
+{
+       NTSTATUS status;
+       struct dom_sid *sid;
+       struct lsa_RightSet rights;
+       unsigned i;
+
+       if (!args[1]) {
+               d_printf("privileges <sid|name>\n");
+               return 1;
+       }
+
+       sid = dom_sid_parse_talloc(ctx, args[1]);
+       if (sid == NULL) {
+               const char *sid_str;
+               status = smblsa_lookup_name(ctx->cli, args[1], ctx, &sid_str);
+               if (!NT_STATUS_IS_OK(status)) {
+                       d_printf("lsa_LookupNames - %s\n", nt_errstr(status));
+                       return 1;
+               }
+               sid = dom_sid_parse_talloc(ctx, sid_str);
+       }
+
+       status = smblsa_sid_privileges(ctx->cli, sid, ctx, &rights);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_printf("lsa_EnumAccountRights - %s\n", nt_errstr(status));
+               return 1;
+       }
+
+       for (i=0;i<rights.count;i++) {
+               d_printf("\t%s\n", rights.names[i].string);
+       }
+
+       return 0;
 }
 
 
 /****************************************************************************
+add privileges for a user
 ****************************************************************************/
-static int cmd_open(const char **cmd_ptr)
+static int cmd_addprivileges(struct smbclient_context *ctx, const char **args)
 {
-       pstring mask;
-       fstring buf;
-       
-       pstrcpy(mask,cur_dir);
+       NTSTATUS status;
+       struct dom_sid *sid;
+       struct lsa_RightSet rights;
+       int i;
+
+       if (!args[1]) {
+               d_printf("addprivileges <sid|name> <privilege...>\n");
+               return 1;
+       }
+
+       sid = dom_sid_parse_talloc(ctx, args[1]);
+       if (sid == NULL) {
+               const char *sid_str;
+               status = smblsa_lookup_name(ctx->cli, args[1], ctx, &sid_str);
+               if (!NT_STATUS_IS_OK(status)) {
+                       d_printf("lsa_LookupNames - %s\n", nt_errstr(status));
+                       return 1;
+               }
+               sid = dom_sid_parse_talloc(ctx, sid_str);
+       }
+
+       ZERO_STRUCT(rights);
+       for (i = 2; args[i]; i++) {
+               rights.names = talloc_realloc(ctx, rights.names, 
+                                             struct lsa_StringLarge, rights.count+1);
+               rights.names[rights.count].string = talloc_strdup(ctx, args[i]);
+               rights.count++;
+       }
+
+
+       status = smblsa_sid_add_privileges(ctx->cli, sid, ctx, &rights);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_printf("lsa_AddAccountRights - %s\n", nt_errstr(status));
+               return 1;
+       }
+
+       return 0;
+}
+
+/****************************************************************************
+delete privileges for a user
+****************************************************************************/
+static int cmd_delprivileges(struct smbclient_context *ctx, const char **args)
+{
+       NTSTATUS status;
+       struct dom_sid *sid;
+       struct lsa_RightSet rights;
+       int i;
+
+       if (!args[1]) {
+               d_printf("delprivileges <sid|name> <privilege...>\n");
+               return 1;
+       }
+
+       sid = dom_sid_parse_talloc(ctx, args[1]);
+       if (sid == NULL) {
+               const char *sid_str;
+               status = smblsa_lookup_name(ctx->cli, args[1], ctx, &sid_str);
+               if (!NT_STATUS_IS_OK(status)) {
+                       d_printf("lsa_LookupNames - %s\n", nt_errstr(status));
+                       return 1;
+               }
+               sid = dom_sid_parse_talloc(ctx, sid_str);
+       }
+
+       ZERO_STRUCT(rights);
+       for (i = 2; args[i]; i++) {
+               rights.names = talloc_realloc(ctx, rights.names, 
+                                             struct lsa_StringLarge, rights.count+1);
+               rights.names[rights.count].string = talloc_strdup(ctx, args[i]);
+               rights.count++;
+       }
+
+
+       status = smblsa_sid_del_privileges(ctx->cli, sid, ctx, &rights);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_printf("lsa_RemoveAccountRights - %s\n", nt_errstr(status));
+               return 1;
+       }
+
+       return 0;
+}
+
+
+/****************************************************************************
+****************************************************************************/
+static int cmd_open(struct smbclient_context *ctx, const char **args)
+{
+       char *mask;
        
-       if (!next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
+       if (!args[1]) {
                d_printf("open <filename>\n");
                return 1;
        }
-       pstrcat(mask,buf);
+       mask = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[1]);
 
-       smbcli_open(cli->tree, mask, O_RDWR, DENY_ALL);
+       smbcli_open(ctx->cli->tree, mask, O_RDWR, DENY_ALL);
 
        return 0;
 }
@@ -1858,22 +2122,19 @@ static int cmd_open(const char **cmd_ptr)
 /****************************************************************************
 remove a directory
 ****************************************************************************/
-static int cmd_rmdir(const char **cmd_ptr)
+static int cmd_rmdir(struct smbclient_context *ctx, const char **args)
 {
-       pstring mask;
-       fstring buf;
+       char *mask;
   
-       pstrcpy(mask,cur_dir);
-       
-       if (!next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
+       if (!args[1]) {
                d_printf("rmdir <dirname>\n");
                return 1;
        }
-       pstrcat(mask,buf);
+       mask = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[1]);
 
-       if (NT_STATUS_IS_ERR(smbcli_rmdir(cli->tree, mask))) {
+       if (NT_STATUS_IS_ERR(smbcli_rmdir(ctx->cli->tree, mask))) {
                d_printf("%s removing remote directory file %s\n",
-                        smbcli_errstr(cli->tree),mask);
+                        smbcli_errstr(ctx->cli->tree),mask);
        }
        
        return 0;
@@ -1882,30 +2143,26 @@ static int cmd_rmdir(const char **cmd_ptr)
 /****************************************************************************
  UNIX hardlink.
 ****************************************************************************/
-static int cmd_link(const char **cmd_ptr)
+static int cmd_link(struct smbclient_context *ctx, const char **args)
 {
-       pstring src,dest;
-       fstring buf,buf2;
+       char *src,*dest;
   
-       if (!(cli->transport->negotiate.capabilities & CAP_UNIX)) {
+       if (!(ctx->cli->transport->negotiate.capabilities & CAP_UNIX)) {
                d_printf("Server doesn't support UNIX CIFS calls.\n");
                return 1;
        }
 
-       pstrcpy(src,cur_dir);
-       pstrcpy(dest,cur_dir);
-  
-       if (!next_token(cmd_ptr,buf,NULL,sizeof(buf)) || 
-           !next_token(cmd_ptr,buf2,NULL, sizeof(buf2))) {
+       
+       if (!args[1] || !args[2]) {
                d_printf("link <src> <dest>\n");
                return 1;
        }
 
-       pstrcat(src,buf);
-       pstrcat(dest,buf2);
+       src = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[1]);
+       dest = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[2]);
 
-       if (NT_STATUS_IS_ERR(smbcli_unix_hardlink(cli->tree, src, dest))) {
-               d_printf("%s linking files (%s -> %s)\n", smbcli_errstr(cli->tree), src, dest);
+       if (NT_STATUS_IS_ERR(smbcli_unix_hardlink(ctx->cli->tree, src, dest))) {
+               d_printf("%s linking files (%s -> %s)\n", smbcli_errstr(ctx->cli->tree), src, dest);
                return 1;
        }  
 
@@ -1916,31 +2173,26 @@ static int cmd_link(const char **cmd_ptr)
  UNIX symlink.
 ****************************************************************************/
 
-static int cmd_symlink(const char **cmd_ptr)
+static int cmd_symlink(struct smbclient_context *ctx, const char **args)
 {
-       pstring src,dest;
-       fstring buf,buf2;
+       char *src,*dest;
   
-       if (!(cli->transport->negotiate.capabilities & CAP_UNIX)) {
+       if (!(ctx->cli->transport->negotiate.capabilities & CAP_UNIX)) {
                d_printf("Server doesn't support UNIX CIFS calls.\n");
                return 1;
        }
 
-       pstrcpy(src,cur_dir);
-       pstrcpy(dest,cur_dir);
-       
-       if (!next_token(cmd_ptr,buf,NULL,sizeof(buf)) || 
-           !next_token(cmd_ptr,buf2,NULL, sizeof(buf2))) {
+       if (!args[1] || !args[2]) {
                d_printf("symlink <src> <dest>\n");
                return 1;
        }
 
-       pstrcat(src,buf);
-       pstrcat(dest,buf2);
+       src = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[1]);
+       dest = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[2]);
 
-       if (NT_STATUS_IS_ERR(smbcli_unix_symlink(cli->tree, src, dest))) {
+       if (NT_STATUS_IS_ERR(smbcli_unix_symlink(ctx->cli->tree, src, dest))) {
                d_printf("%s symlinking files (%s -> %s)\n",
-                       smbcli_errstr(cli->tree), src, dest);
+                       smbcli_errstr(ctx->cli->tree), src, dest);
                return 1;
        } 
 
@@ -1951,31 +2203,28 @@ static int cmd_symlink(const char **cmd_ptr)
  UNIX chmod.
 ****************************************************************************/
 
-static int cmd_chmod(const char **cmd_ptr)
+static int cmd_chmod(struct smbclient_context *ctx, const char **args)
 {
-       pstring src;
+       char *src;
        mode_t mode;
-       fstring buf, buf2;
   
-       if (!(cli->transport->negotiate.capabilities & CAP_UNIX)) {
+       if (!(ctx->cli->transport->negotiate.capabilities & CAP_UNIX)) {
                d_printf("Server doesn't support UNIX CIFS calls.\n");
                return 1;
        }
 
-       pstrcpy(src,cur_dir);
-       
-       if (!next_token(cmd_ptr,buf,NULL,sizeof(buf)) || 
-           !next_token(cmd_ptr,buf2,NULL, sizeof(buf2))) {
+       if (!args[1] || !args[2]) {
                d_printf("chmod mode file\n");
                return 1;
        }
 
-       mode = (mode_t)strtol(buf, NULL, 8);
-       pstrcat(src,buf2);
+       src = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[2]);
+       
+       mode = (mode_t)strtol(args[1], NULL, 8);
 
-       if (NT_STATUS_IS_ERR(smbcli_unix_chmod(cli->tree, src, mode))) {
+       if (NT_STATUS_IS_ERR(smbcli_unix_chmod(ctx->cli->tree, src, mode))) {
                d_printf("%s chmod file %s 0%o\n",
-                       smbcli_errstr(cli->tree), src, (uint_t)mode);
+                       smbcli_errstr(ctx->cli->tree), src, (mode_t)mode);
                return 1;
        } 
 
@@ -1986,34 +2235,29 @@ static int cmd_chmod(const char **cmd_ptr)
  UNIX chown.
 ****************************************************************************/
 
-static int cmd_chown(const char **cmd_ptr)
+static int cmd_chown(struct smbclient_context *ctx, const char **args)
 {
-       pstring src;
+       char *src;
        uid_t uid;
        gid_t gid;
-       fstring buf, buf2, buf3;
   
-       if (!(cli->transport->negotiate.capabilities & CAP_UNIX)) {
+       if (!(ctx->cli->transport->negotiate.capabilities & CAP_UNIX)) {
                d_printf("Server doesn't support UNIX CIFS calls.\n");
                return 1;
        }
 
-       pstrcpy(src,cur_dir);
-       
-       if (!next_token(cmd_ptr,buf,NULL,sizeof(buf)) || 
-           !next_token(cmd_ptr,buf2,NULL, sizeof(buf2)) ||
-           !next_token(cmd_ptr,buf3,NULL, sizeof(buf3))) {
+       if (!args[1] || !args[2] || !args[3]) {
                d_printf("chown uid gid file\n");
                return 1;
        }
 
-       uid = (uid_t)atoi(buf);
-       gid = (gid_t)atoi(buf2);
-       pstrcat(src,buf3);
+       uid = (uid_t)atoi(args[1]);
+       gid = (gid_t)atoi(args[2]);
+       src = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[3]);
 
-       if (NT_STATUS_IS_ERR(smbcli_unix_chown(cli->tree, src, uid, gid))) {
+       if (NT_STATUS_IS_ERR(smbcli_unix_chown(ctx->cli->tree, src, uid, gid))) {
                d_printf("%s chown file %s uid=%d, gid=%d\n",
-                       smbcli_errstr(cli->tree), src, (int)uid, (int)gid);
+                       smbcli_errstr(ctx->cli->tree), src, (int)uid, (int)gid);
                return 1;
        } 
 
@@ -2023,25 +2267,20 @@ static int cmd_chown(const char **cmd_ptr)
 /****************************************************************************
 rename some files
 ****************************************************************************/
-static int cmd_rename(const char **cmd_ptr)
+static int cmd_rename(struct smbclient_context *ctx, const char **args)
 {
-       pstring src,dest;
-       fstring buf,buf2;
+       char *src,*dest;
   
-       pstrcpy(src,cur_dir);
-       pstrcpy(dest,cur_dir);
-       
-       if (!next_token(cmd_ptr,buf,NULL,sizeof(buf)) || 
-           !next_token(cmd_ptr,buf2,NULL, sizeof(buf2))) {
+       if (!args[1] || !args[2]) {
                d_printf("rename <src> <dest>\n");
                return 1;
        }
 
-       pstrcat(src,buf);
-       pstrcat(dest,buf2);
+       src = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[1]);
+       dest = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[2]);
 
-       if (NT_STATUS_IS_ERR(smbcli_rename(cli->tree, src, dest))) {
-               d_printf("%s renaming files\n",smbcli_errstr(cli->tree));
+       if (NT_STATUS_IS_ERR(smbcli_rename(ctx->cli->tree, src, dest))) {
+               d_printf("%s renaming files\n",smbcli_errstr(ctx->cli->tree));
                return 1;
        }
        
@@ -2052,10 +2291,10 @@ static int cmd_rename(const char **cmd_ptr)
 /****************************************************************************
 toggle the prompt flag
 ****************************************************************************/
-static int cmd_prompt(const char **cmd_ptr)
+static int cmd_prompt(struct smbclient_context *ctx, const char **args)
 {
-       prompt = !prompt;
-       DEBUG(2,("prompting is now %s\n",prompt?"on":"off"));
+       ctx->prompt = !ctx->prompt;
+       DEBUG(2,("prompting is now %s\n",ctx->prompt?"on":"off"));
        
        return 1;
 }
@@ -2064,22 +2303,19 @@ static int cmd_prompt(const char **cmd_ptr)
 /****************************************************************************
 set the newer than time
 ****************************************************************************/
-static int cmd_newer(const char **cmd_ptr)
+static int cmd_newer(struct smbclient_context *ctx, const char **args)
 {
-       fstring buf;
-       BOOL ok;
        struct stat sbuf;
 
-       ok = next_token(cmd_ptr,buf,NULL,sizeof(buf));
-       if (ok && (stat(buf,&sbuf) == 0)) {
-               newer_than = sbuf.st_mtime;
+       if (args[1] && (stat(args[1],&sbuf) == 0)) {
+               ctx->newer_than = sbuf.st_mtime;
                DEBUG(1,("Getting files newer than %s",
-                        asctime(localtime(&newer_than))));
+                        asctime(localtime(&ctx->newer_than))));
        } else {
-               newer_than = 0;
+               ctx->newer_than = 0;
        }
 
-       if (ok && newer_than == 0) {
+       if (args[1] && ctx->newer_than == 0) {
                d_printf("Error setting newer-than time\n");
                return 1;
        }
@@ -2090,14 +2326,12 @@ static int cmd_newer(const char **cmd_ptr)
 /****************************************************************************
 set the archive level
 ****************************************************************************/
-static int cmd_archive(const char **cmd_ptr)
+static int cmd_archive(struct smbclient_context *ctx, const char **args)
 {
-       fstring buf;
-
-       if (next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
-               archive_level = atoi(buf);
+       if (args[1]) {
+               ctx->archive_level = atoi(args[1]);
        } else
-               d_printf("Archive level is %d\n",archive_level);
+               d_printf("Archive level is %d\n",ctx->archive_level);
 
        return 0;
 }
@@ -2105,10 +2339,10 @@ static int cmd_archive(const char **cmd_ptr)
 /****************************************************************************
 toggle the lowercaseflag
 ****************************************************************************/
-static int cmd_lowercase(const char **cmd_ptr)
+static int cmd_lowercase(struct smbclient_context *ctx, const char **args)
 {
-       lowercase = !lowercase;
-       DEBUG(2,("filename lowercasing is now %s\n",lowercase?"on":"off"));
+       ctx->lowercase = !ctx->lowercase;
+       DEBUG(2,("filename lowercasing is now %s\n",ctx->lowercase?"on":"off"));
 
        return 0;
 }
@@ -2119,10 +2353,10 @@ static int cmd_lowercase(const char **cmd_ptr)
 /****************************************************************************
 toggle the recurse flag
 ****************************************************************************/
-static int cmd_recurse(const char **cmd_ptr)
+static int cmd_recurse(struct smbclient_context *ctx, const char **args)
 {
-       recurse = !recurse;
-       DEBUG(2,("directory recursion is now %s\n",recurse?"on":"off"));
+       ctx->recurse = !ctx->recurse;
+       DEBUG(2,("directory recursion is now %s\n",ctx->recurse?"on":"off"));
 
        return 0;
 }
@@ -2130,11 +2364,11 @@ static int cmd_recurse(const char **cmd_ptr)
 /****************************************************************************
 toggle the translate flag
 ****************************************************************************/
-static int cmd_translate(const char **cmd_ptr)
+static int cmd_translate(struct smbclient_context *ctx, const char **args)
 {
-       translation = !translation;
+       ctx->translation = !ctx->translation;
        DEBUG(2,("CR/LF<->LF and print text translation now %s\n",
-                translation?"on":"off"));
+                ctx->translation?"on":"off"));
 
        return 0;
 }
@@ -2143,51 +2377,66 @@ static int cmd_translate(const char **cmd_ptr)
 /****************************************************************************
 do a printmode command
 ****************************************************************************/
-static int cmd_printmode(const char **cmd_ptr)
+static int cmd_printmode(struct smbclient_context *ctx, const char **args)
 {
-       fstring buf;
-       fstring mode;
-
-       if (next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
-               if (strequal(buf,"text")) {
-                       printmode = 0;      
+       if (args[1]) {
+               if (strequal(args[1],"text")) {
+                       ctx->printmode = 0;      
                } else {
-                       if (strequal(buf,"graphics"))
-                               printmode = 1;
+                       if (strequal(args[1],"graphics"))
+                               ctx->printmode = 1;
                        else
-                               printmode = atoi(buf);
+                               ctx->printmode = atoi(args[1]);
                }
        }
 
-       switch(printmode)
-               {
+       switch(ctx->printmode)
+       {
                case 0: 
-                       fstrcpy(mode,"text");
+                       DEBUG(2,("the printmode is now text\n"));
                        break;
                case 1: 
-                       fstrcpy(mode,"graphics");
+                       DEBUG(2,("the printmode is now graphics\n"));
                        break;
                default: 
-                       slprintf(mode,sizeof(mode)-1,"%d",printmode);
+                       DEBUG(2,("the printmode is now %d\n", ctx->printmode));
                        break;
-               }
+       }
        
-       DEBUG(2,("the printmode is now %s\n",mode));
-
        return 0;
 }
 
 /****************************************************************************
  do the lcd command
  ****************************************************************************/
-static int cmd_lcd(const char **cmd_ptr)
+static int cmd_lcd(struct smbclient_context *ctx, const char **args)
+{
+       char d[PATH_MAX];
+       
+       if (args[1]) 
+               chdir(args[1]);
+       DEBUG(2,("the local directory is now %s\n",getcwd(d, PATH_MAX)));
+
+       return 0;
+}
+
+/****************************************************************************
+history
+****************************************************************************/
+static int cmd_history(struct smbclient_context *ctx, const char **args)
 {
-       fstring buf;
-       pstring d;
+#if defined(HAVE_LIBREADLINE) && defined(HAVE_HISTORY_LIST)
+       HIST_ENTRY **hlist;
+       int i;
+
+       hlist = history_list();
        
-       if (next_token(cmd_ptr,buf,NULL,sizeof(buf)))
-               chdir(buf);
-       DEBUG(2,("the local directory is now %s\n",sys_getwd(d)));
+       for (i = 0; hlist && hlist[i]; i++) {
+               DEBUG(0, ("%d: %s\n", i, hlist[i]->line));
+       }
+#else
+       DEBUG(0,("no history without readline support\n"));
+#endif
 
        return 0;
 }
@@ -2195,62 +2444,53 @@ static int cmd_lcd(const char **cmd_ptr)
 /****************************************************************************
  get a file restarting at end of local file
  ****************************************************************************/
-static int cmd_reget(const char **cmd_ptr)
+static int cmd_reget(struct smbclient_context *ctx, const char **args)
 {
-       pstring local_name;
-       pstring remote_name;
-       char *p;
+       char *local_name;
+       char *remote_name;
 
-       pstrcpy(remote_name, cur_dir);
-       pstrcat(remote_name, "\\");
-       
-       p = remote_name + strlen(remote_name);
-       
-       if (!next_token(cmd_ptr, p, NULL, sizeof(remote_name) - strlen(remote_name))) {
+       if (!args[1]) {
                d_printf("reget <filename>\n");
                return 1;
        }
-       pstrcpy(local_name, p);
+       remote_name = talloc_asprintf(ctx, "%s\\%s", ctx->remote_cur_dir, args[1]);
        dos_clean_name(remote_name);
        
-       next_token(cmd_ptr, local_name, NULL, sizeof(local_name));
+       if (args[2]) 
+               local_name = talloc_strdup(ctx, args[2]);
+       else
+               local_name = talloc_strdup(ctx, args[1]);
        
-       return do_get(remote_name, local_name, True);
+       return do_get(ctx, remote_name, local_name, True);
 }
 
 /****************************************************************************
  put a file restarting at end of local file
  ****************************************************************************/
-static int cmd_reput(const char **cmd_ptr)
+static int cmd_reput(struct smbclient_context *ctx, const char **args)
 {
-       pstring local_name;
-       pstring remote_name;
-       fstring buf;
-       char *p = buf;
-       struct stat st;
+       char *local_name;
+       char *remote_name;
        
-       pstrcpy(remote_name, cur_dir);
-       pstrcat(remote_name, "\\");
-  
-       if (!next_token(cmd_ptr, p, NULL, sizeof(buf))) {
+       if (!args[1]) {
                d_printf("reput <filename>\n");
                return 1;
        }
-       pstrcpy(local_name, p);
+       local_name = talloc_asprintf(ctx, "%s\\%s", ctx->remote_cur_dir, args[1]);
   
-       if (!file_exist(local_name, &st)) {
+       if (!file_exist(local_name)) {
                d_printf("%s does not exist\n", local_name);
                return 1;
        }
 
-       if (next_token(cmd_ptr, p, NULL, sizeof(buf)))
-               pstrcat(remote_name, p);
+       if (args[2]) 
+               remote_name = talloc_strdup(ctx, args[2]);
        else
-               pstrcat(remote_name, local_name);
+               remote_name = talloc_strdup(ctx, args[1]);
        
        dos_clean_name(remote_name);
 
-       return do_put(remote_name, local_name, True);
+       return do_put(ctx, remote_name, local_name, True);
 }
 
 
@@ -2308,18 +2548,15 @@ static BOOL browse_host(const char *query_host)
 
        binding = talloc_asprintf(mem_ctx, "ncacn_np:%s", query_host);
 
-       status = dcerpc_pipe_connect(&p, binding, 
-                                    DCERPC_SRVSVC_UUID, 
-                                    DCERPC_SRVSVC_VERSION,
-                                    domain, 
-                                    username, password);
+       status = dcerpc_pipe_connect(mem_ctx, &p, binding, 
+                                        &ndr_table_srvsvc,
+                                    cmdline_credentials, NULL);
        if (!NT_STATUS_IS_OK(status)) {
                d_printf("Failed to connect to %s - %s\n", 
                         binding, nt_errstr(status));
-               talloc_destroy(mem_ctx);
+               talloc_free(mem_ctx);
                return False;
        }
-       talloc_steal(mem_ctx, p);
 
        r.in.server_unc = talloc_asprintf(mem_ctx,"\\\\%s",dcerpc_server_name(p));
        r.in.level = 1;
@@ -2343,7 +2580,7 @@ static BOOL browse_host(const char *query_host)
                }
        } while (NT_STATUS_IS_OK(status) && W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA));
 
-       talloc_destroy(mem_ctx);
+       talloc_free(mem_ctx);
 
        if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(r.out.result)) {
                d_printf("Failed NetShareEnumAll %s - %s/%s\n", 
@@ -2369,6 +2606,8 @@ static BOOL list_servers(const char *wk_grp)
 #define COMPL_REMOTE      1          /* Complete remote filename */
 #define COMPL_LOCAL       2          /* Complete local filename */
 
+static int cmd_help(struct smbclient_context *ctx, const char **args);
+
 /* This defines the commands supported by this client.
  * NOTE: The "!" must be the last one in the list because it's fn pointer
  *       field is NULL, and NULL in that field is used in process_tok()
@@ -2377,30 +2616,35 @@ static BOOL list_servers(const char *wk_grp)
 static struct
 {
   const char *name;
-  int (*fn)(const char **cmd_ptr);
+  int (*fn)(struct smbclient_context *ctx, const char **args);
   const char *description;
   char compl_args[2];      /* Completion argument info */
 } commands[] = 
 {
   {"?",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
+  {"addprivileges",cmd_addprivileges,"<sid|name> <privilege...> add privileges for a user",{COMPL_NONE,COMPL_NONE}},
   {"altname",cmd_altname,"<file> show alt name",{COMPL_NONE,COMPL_NONE}},
   {"acl",cmd_acl,"<file> show file ACL",{COMPL_NONE,COMPL_NONE}},
   {"allinfo",cmd_allinfo,"<file> show all possible info about a file",{COMPL_NONE,COMPL_NONE}},
   {"archive",cmd_archive,"<level>\n0=ignore archive bit\n1=only get archive files\n2=only get archive files and reset archive bit\n3=get all files and reset archive bit",{COMPL_NONE,COMPL_NONE}},
-  {"cancel",cmd_cancel,"<jobid> cancel a print queue entry",{COMPL_NONE,COMPL_NONE}},
+  {"cancel",cmd_rewrite,"<jobid> cancel a print queue entry",{COMPL_NONE,COMPL_NONE}},
   {"cd",cmd_cd,"[directory] change/report the remote directory",{COMPL_REMOTE,COMPL_NONE}},
   {"chmod",cmd_chmod,"<src> <mode> chmod a file using UNIX permission",{COMPL_REMOTE,COMPL_REMOTE}},
   {"chown",cmd_chown,"<src> <uid> <gid> chown a file using UNIX uids and gids",{COMPL_REMOTE,COMPL_REMOTE}},
   {"del",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
+  {"delprivileges",cmd_delprivileges,"<sid|name> <privilege...> remove privileges for a user",{COMPL_NONE,COMPL_NONE}},
   {"deltree",cmd_deltree,"<dir> delete a whole directory tree",{COMPL_REMOTE,COMPL_NONE}},
   {"dir",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
   {"du",cmd_du,"<mask> computes the total size of the current directory",{COMPL_REMOTE,COMPL_NONE}},
+  {"eainfo",cmd_eainfo,"<file> show EA contents for a file",{COMPL_NONE,COMPL_NONE}},
   {"exit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
+  {"fsinfo",cmd_fsinfo,"query file system info",{COMPL_NONE,COMPL_NONE}},
   {"get",cmd_get,"<remote name> [local name] get a file",{COMPL_REMOTE,COMPL_LOCAL}},
   {"help",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
   {"history",cmd_history,"displays the command history",{COMPL_NONE,COMPL_NONE}},
   {"lcd",cmd_lcd,"[directory] change/report the local current working directory",{COMPL_LOCAL,COMPL_NONE}},
   {"link",cmd_link,"<src> <dest> create a UNIX hard link",{COMPL_REMOTE,COMPL_REMOTE}},
+  {"lookup",cmd_lookup,"<sid|name> show SID for name or name for SID",{COMPL_NONE,COMPL_NONE}},
   {"lowercase",cmd_lowercase,"toggle lowercasing of filenames for get",{COMPL_NONE,COMPL_NONE}},  
   {"ls",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
   {"mask",cmd_select,"<mask> mask all filenames against this",{COMPL_REMOTE,COMPL_NONE}},
@@ -2411,13 +2655,14 @@ static struct
   {"mput",cmd_mput,"<mask> put all matching files",{COMPL_REMOTE,COMPL_NONE}},
   {"newer",cmd_newer,"<file> only mget files newer than the specified local file",{COMPL_LOCAL,COMPL_NONE}},
   {"open",cmd_open,"<mask> open a file",{COMPL_REMOTE,COMPL_NONE}},
+  {"privileges",cmd_privileges,"<user> show privileges for a user",{COMPL_NONE,COMPL_NONE}},
   {"print",cmd_print,"<file name> print a file",{COMPL_NONE,COMPL_NONE}},
   {"printmode",cmd_printmode,"<graphics or text> set the print mode",{COMPL_NONE,COMPL_NONE}},
   {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput",{COMPL_NONE,COMPL_NONE}},  
   {"put",cmd_put,"<local name> [remote name] put a file",{COMPL_LOCAL,COMPL_REMOTE}},
   {"pwd",cmd_pwd,"show current remote directory (same as 'cd' with no args)",{COMPL_NONE,COMPL_NONE}},
   {"q",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
-  {"queue",cmd_queue,"show the print queue",{COMPL_NONE,COMPL_NONE}},
+  {"queue",cmd_rewrite,"show the print queue",{COMPL_NONE,COMPL_NONE}},
   {"quit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
   {"rd",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
   {"recurse",cmd_recurse,"toggle directory recursion for mget and mput",{COMPL_NONE,COMPL_NONE}},  
@@ -2439,7 +2684,7 @@ static struct
   lookup a command string in the list of commands, including 
   abbreviations
   ******************************************************************/
-static int process_tok(fstring tok)
+static int process_tok(const char *tok)
 {
        int i = 0, matches = 0;
        int cmd=0;
@@ -2468,13 +2713,12 @@ static int process_tok(fstring tok)
 /****************************************************************************
 help
 ****************************************************************************/
-static int cmd_help(const char **cmd_ptr)
+static int cmd_help(struct smbclient_context *ctx, const char **args)
 {
        int i=0,j;
-       fstring buf;
        
-       if (next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
-               if ((i = process_tok(buf)) >= 0)
+       if (args[1]) {
+               if ((i = process_tok(args[1])) >= 0)
                        d_printf("HELP %s:\n\t%s\n\n",commands[i].name,commands[i].description);
        } else {
                while (commands[i].description) {
@@ -2488,59 +2732,28 @@ static int cmd_help(const char **cmd_ptr)
        return 0;
 }
 
+static int process_line(struct smbclient_context *ctx, const char *cline);
 /****************************************************************************
 process a -c command string
 ****************************************************************************/
-static int process_command_string(char *cmd)
+static int process_command_string(struct smbclient_context *ctx, const char *cmd)
 {
-       pstring line;
-       const char *ptr;
-       int rc = 0;
+       const char **lines;
+       int i, rc = 0;
 
-       /* establish the connection if not already */
-       
-       if (!cli) {
-               cli = do_connect(desthost, service);
-               if (!cli)
-                       return 0;
+       lines = str_list_make(NULL, cmd, ";");
+       for (i = 0; lines[i]; i++) {
+               rc |= process_line(ctx, lines[i]);
        }
-       
-       while (cmd[0] != '\0')    {
-               char *p;
-               fstring tok;
-               int i;
-               
-               if ((p = strchr_m(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;
-               }
-               
-               /* and get the first part of the command */
-               ptr = line;
-               if (!next_token(&ptr,tok,NULL,sizeof(tok))) continue;
-               
-               if ((i = process_tok(tok)) >= 0) {
-                       rc = commands[i].fn(&ptr);
-               } else if (i == -2) {
-                       d_printf("%s: command abbreviation ambiguous\n",tok);
-               } else {
-                       d_printf("%s: command not found\n",tok);
-               }
-       }
-       
+       talloc_free(lines);
+
        return rc;
 }      
 
 #define MAX_COMPLETIONS 100
 
 typedef struct {
-       pstring dirmask;
+       char *dirmask;
        char **matches;
        int count, samelen;
        const char *text;
@@ -2551,20 +2764,20 @@ static void completion_remote_filter(struct clilist_file_info *f, const char *ma
 {
        completion_remote_t *info = (completion_remote_t *)state;
 
-       if ((info->count < MAX_COMPLETIONS - 1) && (strncmp(info->text, f->name, info->len) == 0) && (strcmp(f->name, ".") != 0) && (strcmp(f->name, "..") != 0)) {
+       if ((info->count < MAX_COMPLETIONS - 1) && (strncmp(info->text, f->name, info->len) == 0) && (!ISDOT(f->name)) && (!ISDOTDOT(f->name))) {
                if ((info->dirmask[0] == 0) && !(f->attrib & FILE_ATTRIBUTE_DIRECTORY))
                        info->matches[info->count] = strdup(f->name);
                else {
-                       pstring tmp;
+                       char *tmp;
 
                        if (info->dirmask[0] != 0)
-                               pstrcpy(tmp, info->dirmask);
+                               tmp = talloc_asprintf(NULL, "%s/%s", info->dirmask, f->name);
                        else
-                               tmp[0] = 0;
-                       pstrcat(tmp, f->name);
+                               tmp = talloc_strdup(NULL, f->name);
+                       
                        if (f->attrib & FILE_ATTRIBUTE_DIRECTORY)
-                               pstrcat(tmp, "/");
-                       info->matches[info->count] = strdup(tmp);
+                               tmp = talloc_append_string(NULL, tmp, "/");
+                       info->matches[info->count] = tmp;
                }
                if (info->matches[info->count] == NULL)
                        return;
@@ -2582,9 +2795,9 @@ static void completion_remote_filter(struct clilist_file_info *f, const char *ma
 
 static char **remote_completion(const char *text, int len)
 {
-       pstring dirmask;
+       char *dirmask;
        int i;
-       completion_remote_t info = { "", NULL, 1, 0, NULL, 0 };
+       completion_remote_t info;
 
        info.samelen = len;
        info.text = text;
@@ -2593,7 +2806,7 @@ static char **remote_completion(const char *text, int len)
        if (len >= PATH_MAX)
                return(NULL);
 
-       info.matches = (char **)malloc(sizeof(info.matches[0])*MAX_COMPLETIONS);
+       info.matches = malloc_array_p(char *, MAX_COMPLETIONS);
        if (!info.matches) return NULL;
        info.matches[0] = NULL;
 
@@ -2604,13 +2817,13 @@ static char **remote_completion(const char *text, int len)
        info.samelen = info.len = len-i-1;
 
        if (i > 0) {
-               strncpy(info.dirmask, text, i+1);
+               info.dirmask = talloc_strndup(NULL, text, i+1);
                info.dirmask[i+1] = 0;
-               snprintf(dirmask, sizeof(dirmask), "%s%*s*", cur_dir, i-1, text);
+               asprintf(&dirmask, "%s%*s*", rl_ctx->remote_cur_dir, i-1, text);
        } else
-               snprintf(dirmask, sizeof(dirmask), "%s*", cur_dir);
+               asprintf(&dirmask, "%s*", rl_ctx->remote_cur_dir);
 
-       if (smbcli_list(cli->tree, dirmask, 
+       if (smbcli_list(rl_ctx->cli->tree, dirmask, 
                     FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN, 
                     completion_remote_filter, &info) < 0)
                goto cleanup;
@@ -2673,7 +2886,7 @@ static char **completion_fn(const char *text, int start, int end)
                char **matches;
                int i, len, samelen = 0, count=1;
 
-               matches = (char **)malloc(sizeof(matches[0])*MAX_COMPLETIONS);
+               matches = malloc_array_p(char *, MAX_COMPLETIONS);
                if (!matches) return NULL;
                matches[0] = NULL;
 
@@ -2710,9 +2923,10 @@ static char **completion_fn(const char *text, int start, int end)
                return matches;
 
 cleanup:
-               while (i >= 0) {
-                       free(matches[i]);
-                       i--;
+               count--;
+               while (count >= 0) {
+                       free(matches[count]);
+                       count--;
                }
                free(matches);
                return NULL;
@@ -2733,177 +2947,109 @@ static void readline_callback(void)
 
        last_t = t;
 
-       smbcli_transport_process(cli->transport);
+       smbcli_transport_process(rl_ctx->cli->transport);
 
-       if (cli->tree) {
-               smbcli_chkpath(cli->tree, "\\");
+       if (rl_ctx->cli->tree) {
+               smbcli_chkpath(rl_ctx->cli->tree, "\\");
        }
 }
 
+static int process_line(struct smbclient_context *ctx, const char *cline)
+{
+       const char **args;
+       int i;
+
+       /* and get the first part of the command */
+       args = str_list_make_shell(ctx, cline, NULL);
+       if (!args || !args[0])
+               return 0;
+
+       if ((i = process_tok(args[0])) >= 0) {
+               i = commands[i].fn(ctx, args);
+       } else if (i == -2) {
+               d_printf("%s: command abbreviation ambiguous\n",args[0]);
+       } else {
+               d_printf("%s: command not found\n",args[0]);
+       }
+
+       talloc_free(args);
+
+       return i;
+}
 
 /****************************************************************************
 process commands on stdin
 ****************************************************************************/
-static void process_stdin(void)
+static int process_stdin(struct smbclient_context *ctx)
 {
+       int rc = 0;
        while (1) {
-               fstring tok;
-               fstring the_prompt;
-               char *cline;
-               pstring line;
-               const char *ptr;
-               int i;
-               
                /* display a prompt */
-               slprintf(the_prompt, sizeof(the_prompt)-1, "smb: %s> ", cur_dir);
-               cline = smb_readline(the_prompt, readline_callback, completion_fn);
+               char *the_prompt = talloc_asprintf(ctx, "smb: %s> ", ctx->remote_cur_dir);
+               char *cline = smb_readline(the_prompt, readline_callback, completion_fn);
+               talloc_free(the_prompt);
                        
                if (!cline) break;
                
-               pstrcpy(line, cline);
-
                /* special case - first char is ! */
-               if (*line == '!') {
-                       system(line + 1);
+               if (*cline == '!') {
+                       system(cline + 1);
                        continue;
                }
-      
-               /* and get the first part of the command */
-               ptr = line;
-               if (!next_token(&ptr,tok,NULL,sizeof(tok))) continue;
-
-               if ((i = process_tok(tok)) >= 0) {
-                       commands[i].fn(&ptr);
-               } else if (i == -2) {
-                       d_printf("%s: command abbreviation ambiguous\n",tok);
-               } else {
-                       d_printf("%s: command not found\n",tok);
-               }
+
+               rc |= process_command_string(ctx, cline); 
        }
+
+       return rc;
 }
 
 
 /***************************************************** 
 return a connection to a server
 *******************************************************/
-static struct smbcli_state *do_connect(const char *server, const char *share)
+static struct smbclient_context *do_connect(TALLOC_CTX *mem_ctx, 
+                                      const char *specified_server, const char *specified_share, struct cli_credentials *cred)
 {
-       struct smbcli_state *c;
-       struct nmb_name called, calling;
-       const char *server_n;
-       fstring servicename;
-       char *sharename;
        NTSTATUS status;
-       
-       /* make a copy so we don't modify the global string 'service' */
-       fstrcpy(servicename, share);
-       sharename = servicename;
-       if (*sharename == '\\') {
-               server = sharename+2;
-               sharename = strchr_m(server,'\\');
-               if (!sharename) return NULL;
-               *sharename = 0;
-               sharename++;
-       }
-
-       asprintf(&sharename, "\\\\%s\\%s", server, sharename);
+       struct smbclient_context *ctx = talloc_zero(mem_ctx, struct smbclient_context);
+       char *server, *share;
 
-       server_n = dest_ip?dest_ip:server;
-       
-       make_nmb_name(&calling, lp_netbios_name(), 0x0);
-       choose_called_name(&called, server, name_type);
-
- again:
-       /* have to open a new connection */
-       if (!(c=smbcli_state_init(NULL)) || !smbcli_socket_connect(c, server_n)) {
-               d_printf("Connection to %s failed\n", server_n);
-               return NULL;
-       }
-
-       if (!smbcli_transport_establish(c, &calling, &called)) {
-               char *p;
-               d_printf("session request to %s failed\n", 
-                        called.name);
-               smbcli_shutdown(c);
-               if ((p=strchr_m(called.name, '.'))) {
-                       *p = 0;
-                       goto again;
-               }
-               if (strcmp(called.name, "*SMBSERVER")) {
-                       make_nmb_name(&called , "*SMBSERVER", 0x20);
-                       goto again;
-               }
+       if (!ctx) {
                return NULL;
        }
 
-       DEBUG(4,(" session request ok\n"));
+       rl_ctx = ctx; /* Ugly hack */
 
-       if (NT_STATUS_IS_ERR(smbcli_negprot(c))) {
-               d_printf("protocol negotiation failed\n");
-               smbcli_shutdown(c);
-               return NULL;
-       }
-
-       status = smbcli_session_setup(c, username, password, domain);
-       if (NT_STATUS_IS_ERR(status)) {
-               d_printf("authenticated session setup failed: %s\n", nt_errstr(status));
-               /* if a password was not supplied then try again with a null username */
-               if (password[0] || !username[0]) {
-                       status = smbcli_session_setup(c, "", "", lp_workgroup());
-               }
-               if (NT_STATUS_IS_ERR(status)) {
-                       d_printf("session setup failed: %s\n", nt_errstr(status));
-                       smbcli_shutdown(c);
-                       return NULL;
-               }
-               d_printf("Anonymous login successful\n");
+       if (strncmp(specified_share, "\\\\", 2) == 0 ||
+           strncmp(specified_share, "//", 2) == 0) {
+               smbcli_parse_unc(specified_share, ctx, &server, &share);
+       } else {
+               share = talloc_strdup(ctx, specified_share);
+               server = talloc_strdup(ctx, specified_server);
        }
 
-       DEBUG(4,(" session setup ok\n"));
-
-       if (NT_STATUS_IS_ERR(smbcli_send_tconX(c, sharename, "?????", password))) {
-               d_printf("tree connect failed: %s\n", smbcli_errstr(c->tree));
-               smbcli_shutdown(c);
+       ctx->remote_cur_dir = talloc_strdup(ctx, "\\");
+       
+       status = smbcli_full_connection(ctx, &ctx->cli, server,
+                                       share, NULL, cred, 
+                                       cli_credentials_get_event_context(cred));
+       if (!NT_STATUS_IS_OK(status)) {
+               d_printf("Connection to \\\\%s\\%s failed - %s\n", 
+                        server, share, nt_errstr(status));
+               talloc_free(ctx);
                return NULL;
        }
 
-       DEBUG(4,(" tconx ok\n"));
-
-       return c;
-}
-
-
-/****************************************************************************
-  process commands from the client
-****************************************************************************/
-static int process(char *base_directory)
-{
-       int rc = 0;
-
-       cli = do_connect(desthost, service);
-       if (!cli) {
-               return 1;
-       }
-
-       if (*base_directory) do_cd(base_directory);
-       
-       if (cmdstr) {
-               rc = process_command_string(cmdstr);
-       } else {
-               process_stdin();
-       }
-  
-       smbcli_shutdown(cli);
-       return rc;
+       return ctx;
 }
 
 /****************************************************************************
 handle a -L query
 ****************************************************************************/
-static int do_host_query(char *query_host)
+static int do_host_query(const char *query_host, const char *workgroup)
 {
        browse_host(query_host);
-       list_servers(lp_workgroup());
+       list_servers(workgroup);
        return(0);
 }
 
@@ -2911,15 +3057,17 @@ static int do_host_query(char *query_host)
 /****************************************************************************
 handle a message operation
 ****************************************************************************/
-static int do_message_op(void)
+static int do_message_op(const char *desthost, const char *destip, int name_type)
 {
-       struct nmb_name called, calling;
+       struct nbt_name called, calling;
        const char *server_name;
+       struct smbcli_state *cli;
+
+       make_nbt_name_client(&calling, lp_netbios_name());
 
-       make_nmb_name(&calling, lp_netbios_name(), 0x0);
-       choose_called_name(&called, desthost, name_type);
+       nbt_choose_called_name(NULL, &called, desthost, name_type);
 
-       server_name = dest_ip ? dest_ip : desthost;
+       server_name = destip ? destip : desthost;
 
        if (!(cli=smbcli_state_init(NULL)) || !smbcli_socket_connect(cli, server_name)) {
                d_printf("Connection to %s failed\n", server_name);
@@ -2928,52 +3076,43 @@ static int do_message_op(void)
 
        if (!smbcli_transport_establish(cli, &calling, &called)) {
                d_printf("session request failed\n");
-               smbcli_shutdown(cli);
+               talloc_free(cli);
                return 1;
        }
 
-       send_message();
-       smbcli_shutdown(cli);
+       send_message(cli, desthost);
+       talloc_free(cli);
 
        return 0;
 }
 
 
-/**
- * Process "-L hostname" option.
- *
- * We don't actually do anything yet -- we just stash the name in a
- * global variable and do the query when all options have been read.
- **/
-static void remember_query_host(const char *arg,
-                               pstring query_host)
-{
-       char *slash;
-       
-       while (*arg == '\\' || *arg == '/')
-               arg++;
-       pstrcpy(query_host, arg);
-       if ((slash = strchr(query_host, '/'))
-           || (slash = strchr(query_host, '\\'))) {
-               *slash = 0;
-       }
-}
-
-
 /****************************************************************************
   main program
 ****************************************************************************/
  int main(int argc,char *argv[])
 {
-       fstring base_directory;
+       const char *base_directory = NULL;
+       const char *dest_ip = NULL;
        int opt;
-       pstring query_host;
+       const char *query_host = NULL;
        BOOL message = False;
-       pstring term_code;
+       const char *desthost = NULL;
+#ifdef KANJI
+       const char *term_code = KANJI;
+#else
+       const char *term_code = "";
+#endif /* KANJI */
        poptContext pc;
+       const char *service = NULL;
+       int port = 0;
        char *p;
        int rc = 0;
+       int name_type = 0x20;
        TALLOC_CTX *mem_ctx;
+       struct smbclient_context *ctx;
+       const char *cmdstr = NULL;
+
        struct poptOption long_options[] = {
                POPT_AUTOHELP
 
@@ -2990,35 +3129,18 @@ static void remember_query_host(const char *arg,
                POPT_COMMON_CONNECTION
                POPT_COMMON_CREDENTIALS
                POPT_COMMON_VERSION
-               POPT_TABLEEND
+               { NULL }
        };
        
-#ifdef KANJI
-       pstrcpy(term_code, KANJI);
-#else /* KANJI */
-       *term_code = 0;
-#endif /* KANJI */
-
-       *query_host = 0;
-       *base_directory = 0;
-
-       setup_logging(argv[0],DEBUG_STDOUT);
        mem_ctx = talloc_init("client.c/main");
        if (!mem_ctx) {
                d_printf("\nclient.c: Not enough memory\n");
                exit(1);
        }
 
-       if (!lp_load(dyn_CONFIGFILE,True,False,False)) {
-               fprintf(stderr, "%s: Can't load %s - run testparm to debug it\n",
-                       argv[0], dyn_CONFIGFILE);
-       }
-       
        pc = poptGetContext("smbclient", argc, (const char **) argv, long_options, 0);
        poptSetOtherOptionHelp(pc, "[OPTIONS] service <password>");
 
-       in_client = True;   /* Make sure that we tell lp_load we are */
-
        while ((opt = poptGetNextOpt(pc)) != -1) {
                switch (opt) {
                case 'M':
@@ -3027,25 +3149,21 @@ static void remember_query_host(const char *arg,
                         * to port 139 instead of port 445. srl,crh
                         */
                        name_type = 0x03; 
-                       pstrcpy(desthost,poptGetOptArg(pc));
+                       desthost = strdup(poptGetOptArg(pc));
                        if( 0 == port ) port = 139;
                        message = True;
                        break;
                case 'I':
                        dest_ip = poptGetOptArg(pc);
                        break;
-               case 'E':
-                       setup_logging("client", DEBUG_STDERR);
-                       break;
-
                case 'L':
-                       remember_query_host(poptGetOptArg(pc), query_host);
+                       query_host = strdup(poptGetOptArg(pc));
                        break;
                case 't':
-                       pstrcpy(term_code, poptGetOptArg(pc));
+                       term_code = strdup(poptGetOptArg(pc));
                        break;
                case 'D':
-                       fstrcpy(base_directory,poptGetOptArg(pc));
+                       base_directory = strdup(poptGetOptArg(pc));
                        break;
                case 'b':
                        io_bufsize = MAX(1, atoi(poptGetOptArg(pc)));
@@ -3053,60 +3171,67 @@ static void remember_query_host(const char *arg,
                }
        }
 
-       load_interfaces();
-
-       smbclient_init_subsystems;
+       gensec_init();
 
        if(poptPeekArg(pc)) {
-               pstrcpy(service,poptGetArg(pc));  
+               char *s = strdup(poptGetArg(pc)); 
+
                /* Convert any '/' characters in the service name to '\' characters */
-               string_replace(service, '/','\\');
+               string_replace(s, '/','\\');
 
-               if (count_chars(service,'\\') < 3) {
-                       d_printf("\n%s: Not enough '\\' characters in service\n",service);
+               service = s;
+
+               if (count_chars(s,'\\') < 3) {
+                       d_printf("\n%s: Not enough '\\' characters in service\n",s);
                        poptPrintUsage(pc, stderr, 0);
                        exit(1);
                }
        }
 
        if (poptPeekArg(pc)) { 
-               cmdline_set_userpassword(poptGetArg(pc));
+               cli_credentials_set_password(cmdline_credentials, poptGetArg(pc), CRED_SPECIFIED);
        }
 
        /*init_names(); */
 
-       if (!*query_host && !*service && !message) {
+       if (!query_host && !service && !message) {
                poptPrintUsage(pc, stderr, 0);
                exit(1);
        }
 
        poptFreeContext(pc);
 
-       pstrcpy(username, cmdline_get_username());
-       pstrcpy(domain, cmdline_get_userdomain());
-       pstrcpy(password, cmdline_get_userpassword());
-
        DEBUG( 3, ( "Client started (version %s).\n", SAMBA_VERSION_STRING ) );
 
-       talloc_destroy(mem_ctx);
-
-       if ((p=strchr_m(query_host,'#'))) {
+       if (query_host && (p=strchr_m(query_host,'#'))) {
                *p = 0;
                p++;
                sscanf(p, "%x", &name_type);
        }
   
-       if (*query_host) {
-               return do_host_query(query_host);
+       if (query_host) {
+               return do_host_query(query_host, lp_workgroup());
        }
 
        if (message) {
-               return do_message_op();
+               return do_message_op(desthost, dest_ip, name_type);
        }
        
-       if (process(base_directory)) {
+
+       ctx = do_connect(mem_ctx, desthost, service, cmdline_credentials);
+       if (!ctx)
                return 1;
+
+       if (base_directory) 
+               do_cd(ctx, base_directory);
+       
+       if (cmdstr) {
+               rc = process_command_string(ctx, cmdstr);
+       } else {
+               rc = process_stdin(ctx);
        }
+  
+       talloc_free(mem_ctx);
 
        return rc;
 }