r25026: Move param/param.h out of includes.h
[kai/samba-autobuild/.git] / source4 / client / client.c
index 34d0fc20f1a8dbd52c377e5557471ad4b64e5f2f..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 "version.h"
-#include "dynconfig.h"
-#include "clilist.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
-
-static struct smbcli_state *cli;
-extern BOOL in_client;
-static int port = 0;
-static pstring cur_dir = "\\";
-static pstring cd_path = "";
-static pstring service;
-static pstring desthost;
-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, struct cli_credentials *cred);
-
-
 /*******************************************************************
  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));
 
@@ -116,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,"\\..");
 
@@ -137,7 +96,7 @@ 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, const void *_b, int n)
+static int writefile(int f, const void *_b, int n, BOOL translation)
 {
        const uint8_t *b = _b;
        int i;
@@ -165,7 +124,7 @@ static int writefile(int f, const void *_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(void *_b, int n, XFILE *f)
+static int readfile(void *_b, int n, XFILE *f, BOOL translation)
 {
        uint8_t *b = _b;
        int i;
@@ -194,8 +153,9 @@ static int readfile(void *_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;
 
@@ -209,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_STRUCT(msg);
-
                for (l=0;l<maxlen && (c=fgetc(stdin))!=EOF;l++) {
                        if (c == '\n')
                                msg[l++] = '\r';
@@ -245,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;
        }
 
@@ -263,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;
 }
 
@@ -281,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;
 }
 
 
@@ -359,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);
        }
@@ -385,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",
@@ -404,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;
        }
 }
@@ -417,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
@@ -458,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;
@@ -538,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);
        }
 }
 
@@ -568,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;
 
@@ -599,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))
                        {
@@ -625,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);
                }
        }
 
@@ -638,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));
 
@@ -680,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);
 
@@ -716,7 +665,7 @@ 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;
@@ -731,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;
        }
 
@@ -765,11 +714,11 @@ 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;
        }
 
@@ -778,16 +727,16 @@ static int do_get(char *rname, const char *lname, BOOL reget)
 
        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;
@@ -805,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;
        }
 
@@ -814,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);
        }
 
        {
@@ -841,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);
 }
 
 /****************************************************************************
@@ -869,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))
@@ -884,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;
+       char *rname;
+       char *quest;
+       char *mget_mask;
+       char *saved_curdir;
 
-       if (strequal(finfo->name,".") || strequal(finfo->name,".."))
+       if (ISDOT(finfo->name) || ISDOTDOT(finfo->name))
                return;
 
-       if (abort_mget) {
-               d_printf("mget aborted\n");
-               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 (ctx->prompt && !yesno(quest)) return;
 
-       if (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) && 
            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);
        
@@ -993,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;
@@ -1034,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;
@@ -1079,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;
 }
@@ -1144,7 +1058,7 @@ 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;
@@ -1158,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;
        }
 
@@ -1212,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. */
 
@@ -1221,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;
                } 
@@ -1232,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;
@@ -1263,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);
        }
        
@@ -1275,26 +1189,22 @@ 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);
 
@@ -1305,7 +1215,7 @@ static int cmd_put(const char **cmd_ptr)
                return 1;
        }
 
-       return do_put(rname, lname, False);
+       return do_put(ctx, rname, lname, False);
 }
 
 /*************************************
@@ -1355,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;
 }
@@ -1391,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;
        }
 
@@ -1405,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;
@@ -1420,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;
@@ -1429,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);
@@ -1467,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;
@@ -1503,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] = '/';
@@ -1525,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);
@@ -1547,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());
@@ -1602,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;
 }
@@ -1619,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;
@@ -1647,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);
+
+       dname = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[1]);
        
-       ret = smbcli_deltree(cli->tree, dname);
+       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;
        }
 
@@ -1698,16 +1571,13 @@ fsinfo_level_t fsinfo_levels[] = {
 };
 
 
-static int cmd_fsinfo(const char **cmd_ptr)
+static int cmd_fsinfo(struct smbclient_context *ctx, const char **args)
 {
-       fstring buf;
-       int ret = 0;
        union smb_fsinfo fsinfo;
        NTSTATUS status;
-       TALLOC_CTX *mem_ctx;
        fsinfo_level_t *fsinfo_level;
        
-       if (!next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
+       if (!args[1]) {
                d_printf("fsinfo <level>, where level is one of following:\n");
                fsinfo_level = fsinfo_levels;
                while(fsinfo_level->level_name) {
@@ -1718,7 +1588,7 @@ static int cmd_fsinfo(const char **cmd_ptr)
        }
        
        fsinfo_level = fsinfo_levels;
-       while(fsinfo_level->level_name && !strequal(buf,fsinfo_level->level_name)) {
+       while(fsinfo_level->level_name && !strequal(args[1],fsinfo_level->level_name)) {
                fsinfo_level++;
        }
   
@@ -1727,13 +1597,11 @@ static int cmd_fsinfo(const char **cmd_ptr)
                return 1;
        }
   
-       mem_ctx = talloc_init("fsinfo-level-%s", fsinfo_level->level_name);
        fsinfo.generic.level = fsinfo_level->level;
-       status = smb_raw_fsinfo(cli->tree, mem_ctx, &fsinfo);
+       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));
-               ret = 1;
-               goto done;
+               return 1;
        }
 
        d_printf("fsinfo-level-%s:\n", fsinfo_level->level_name);
@@ -1768,7 +1636,7 @@ static int cmd_fsinfo(const char **cmd_ptr)
        case RAW_QFS_VOLUME_INFO:
        case RAW_QFS_VOLUME_INFORMATION:
                d_printf("\tcreate_time:                %s\n",
-                        nt_time_string(mem_ctx,fsinfo.volume_info.out.create_time));
+                        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);
@@ -1833,58 +1701,52 @@ static int cmd_fsinfo(const char **cmd_ptr)
                break;
        case RAW_QFS_OBJECTID_INFORMATION:
                d_printf("\tGUID:                       %s\n", 
-                        GUID_string(mem_ctx,&fsinfo.objectid_information.out.guid));
+                        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],
-                        (unsigned long long) fsinfo.objectid_information.out.unknown[6] );
+                        (unsigned long long) fsinfo.objectid_information.out.unknown[5] );
+               break;
+       case RAW_QFS_GENERIC:
+               d_printf("\twrong level returned\n");
                break;
        }
   
- done:
-       talloc_free(mem_ctx);
-       return ret;
+       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);
@@ -1896,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);
@@ -1911,20 +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 len=%d '%s'\n", i,
                                 finfo.all_eas.out.eas[i].flags,
-                                finfo.all_eas.out.eas[i].value.length,
+                                (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++) {
@@ -1939,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);
@@ -1948,43 +1810,67 @@ static int cmd_allinfo(const char **cmd_ptr)
                d_printf("\tcluster_shift   %ld\n", (long)finfo.compression_info.out.cluster_shift);
        }
 
-       talloc_free(mem_ctx);
-
-done:
-       return ret;
+       /* 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;
 }
 
 
 /****************************************************************************
 shows EA contents
 ****************************************************************************/
-static int cmd_eainfo(const char **cmd_ptr)
+static int cmd_eainfo(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 i;
 
-       pstrcpy(fname,cur_dir);
-       
-       if (!next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
+       if (!args[1]) {
                d_printf("eainfo <filename>\n");
                return 1;
        }
-       pstrcat(fname,buf);
-
-       mem_ctx = talloc_init("%s", fname);
+       fname = talloc_strdup(ctx, args[1]);
 
-       finfo.generic.in.fname = fname;
        finfo.generic.level = RAW_FILEINFO_ALL_EAS;
-       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("RAW_FILEINFO_ALL_EAS - %s\n", nt_errstr(status));
-               talloc_free(mem_ctx);
                return 1;
        }
 
@@ -1993,7 +1879,7 @@ static int cmd_eainfo(const char **cmd_ptr)
        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,
-                        finfo.all_eas.out.eas[i].value.length,
+                        (int)finfo.all_eas.out.eas[i].value.length,
                         finfo.all_eas.out.eas[i].name.s);
                fflush(stdout);
                dump_data(0, 
@@ -2001,34 +1887,27 @@ static int cmd_eainfo(const char **cmd_ptr)
                          finfo.all_eas.out.eas[i].value.length);
        }
 
-       talloc_free(mem_ctx);
-
-       return ret;
+       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_nt_create_full(cli->tree, fname, 0, 
+       fnum = smbcli_nt_create_full(ctx->cli->tree, fname, 0, 
                                     SEC_STD_READ_CONTROL,
                                     0,
                                     NTCREATEX_SHARE_ACCESS_DELETE|
@@ -2037,109 +1916,91 @@ static int cmd_acl(const char **cmd_ptr)
                                     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.secinfo_flags = 0x7;
+       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_free(mem_ctx);
-
-done:
-       return ret;
+       return 0;
 }
 
 /****************************************************************************
 lookup a name or sid
 ****************************************************************************/
-static int cmd_lookup(const char **cmd_ptr)
+static int cmd_lookup(struct smbclient_context *ctx, const char **args)
 {
-       fstring buf;
-       TALLOC_CTX *mem_ctx = talloc_new(NULL);
        NTSTATUS status;
        struct dom_sid *sid;
 
-       if (!next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
+       if (!args[1]) {
                d_printf("lookup <sid|name>\n");
-               talloc_free(mem_ctx);
                return 1;
        }
 
-       sid = dom_sid_parse_talloc(mem_ctx, buf);
+       sid = dom_sid_parse_talloc(ctx, args[1]);
        if (sid == NULL) {
                const char *sidstr;
-               status = smblsa_lookup_name(cli, buf, mem_ctx, &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));
-                       talloc_free(mem_ctx);
                        return 1;
                }
 
                d_printf("%s\n", sidstr);
        } else {
                const char *name;
-               status = smblsa_lookup_sid(cli, buf, mem_ctx, &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));
-                       talloc_free(mem_ctx);
                        return 1;
                }
 
                d_printf("%s\n", name);
        }
 
-       talloc_free(mem_ctx);
-
        return 0;
 }
 
 /****************************************************************************
 show privileges for a user
 ****************************************************************************/
-static int cmd_privileges(const char **cmd_ptr)
+static int cmd_privileges(struct smbclient_context *ctx, const char **args)
 {
-       fstring buf;
-       TALLOC_CTX *mem_ctx = talloc_new(NULL);
        NTSTATUS status;
        struct dom_sid *sid;
        struct lsa_RightSet rights;
        unsigned i;
 
-       if (!next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
+       if (!args[1]) {
                d_printf("privileges <sid|name>\n");
-               talloc_free(mem_ctx);
                return 1;
        }
 
-       sid = dom_sid_parse_talloc(mem_ctx, buf);
+       sid = dom_sid_parse_talloc(ctx, args[1]);
        if (sid == NULL) {
                const char *sid_str;
-               status = smblsa_lookup_name(cli, buf, mem_ctx, &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));
-                       talloc_free(mem_ctx);
                        return 1;
                }
-               sid = dom_sid_parse_talloc(mem_ctx, sid_str);
+               sid = dom_sid_parse_talloc(ctx, sid_str);
        }
 
-       status = smblsa_sid_privileges(cli, sid, mem_ctx, &rights);
+       status = smblsa_sid_privileges(ctx->cli, sid, ctx, &rights);
        if (!NT_STATUS_IS_OK(status)) {
                d_printf("lsa_EnumAccountRights - %s\n", nt_errstr(status));
-               talloc_free(mem_ctx);
                return 1;
        }
 
@@ -2147,8 +2008,6 @@ static int cmd_privileges(const char **cmd_ptr)
                d_printf("\t%s\n", rights.names[i].string);
        }
 
-       talloc_free(mem_ctx);
-
        return 0;
 }
 
@@ -2156,120 +2015,105 @@ static int cmd_privileges(const char **cmd_ptr)
 /****************************************************************************
 add privileges for a user
 ****************************************************************************/
-static int cmd_addprivileges(const char **cmd_ptr)
+static int cmd_addprivileges(struct smbclient_context *ctx, const char **args)
 {
-       fstring buf;
-       TALLOC_CTX *mem_ctx = talloc_new(NULL);
        NTSTATUS status;
        struct dom_sid *sid;
        struct lsa_RightSet rights;
+       int i;
 
-       if (!next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
+       if (!args[1]) {
                d_printf("addprivileges <sid|name> <privilege...>\n");
-               talloc_free(mem_ctx);
                return 1;
        }
 
-       sid = dom_sid_parse_talloc(mem_ctx, buf);
+       sid = dom_sid_parse_talloc(ctx, args[1]);
        if (sid == NULL) {
                const char *sid_str;
-               status = smblsa_lookup_name(cli, buf, mem_ctx, &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));
-                       talloc_free(mem_ctx);
                        return 1;
                }
-               sid = dom_sid_parse_talloc(mem_ctx, sid_str);
+               sid = dom_sid_parse_talloc(ctx, sid_str);
        }
 
        ZERO_STRUCT(rights);
-       while (next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
-               rights.names = talloc_realloc(mem_ctx, rights.names, 
-                                               struct lsa_String, rights.count+1);
-               rights.names[rights.count].string = talloc_strdup(mem_ctx, buf);
+       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(cli, sid, mem_ctx, &rights);
+       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));
-               talloc_free(mem_ctx);
                return 1;
        }
 
-       talloc_free(mem_ctx);
-
        return 0;
 }
 
 /****************************************************************************
 delete privileges for a user
 ****************************************************************************/
-static int cmd_delprivileges(const char **cmd_ptr)
+static int cmd_delprivileges(struct smbclient_context *ctx, const char **args)
 {
-       fstring buf;
-       TALLOC_CTX *mem_ctx = talloc_new(NULL);
        NTSTATUS status;
        struct dom_sid *sid;
        struct lsa_RightSet rights;
+       int i;
 
-       if (!next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
+       if (!args[1]) {
                d_printf("delprivileges <sid|name> <privilege...>\n");
-               talloc_free(mem_ctx);
                return 1;
        }
 
-       sid = dom_sid_parse_talloc(mem_ctx, buf);
+       sid = dom_sid_parse_talloc(ctx, args[1]);
        if (sid == NULL) {
                const char *sid_str;
-               status = smblsa_lookup_name(cli, buf, mem_ctx, &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));
-                       talloc_free(mem_ctx);
                        return 1;
                }
-               sid = dom_sid_parse_talloc(mem_ctx, sid_str);
+               sid = dom_sid_parse_talloc(ctx, sid_str);
        }
 
        ZERO_STRUCT(rights);
-       while (next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
-               rights.names = talloc_realloc(mem_ctx, rights.names, 
-                                               struct lsa_String, rights.count+1);
-               rights.names[rights.count].string = talloc_strdup(mem_ctx, buf);
+       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(cli, sid, mem_ctx, &rights);
+       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));
-               talloc_free(mem_ctx);
                return 1;
        }
 
-       talloc_free(mem_ctx);
-
        return 0;
 }
 
 
 /****************************************************************************
 ****************************************************************************/
-static int cmd_open(const char **cmd_ptr)
+static int cmd_open(struct smbclient_context *ctx, const char **args)
 {
-       pstring mask;
-       fstring buf;
-       
-       pstrcpy(mask,cur_dir);
+       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;
 }
@@ -2278,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;
@@ -2302,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;
        }  
 
@@ -2336,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;
        } 
 
@@ -2371,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;
        } 
 
@@ -2406,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;
        } 
 
@@ -2443,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;
        }
        
@@ -2472,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;
 }
@@ -2484,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;
        }
@@ -2510,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;
 }
@@ -2525,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;
 }
@@ -2539,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;
 }
@@ -2550,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;
 }
@@ -2563,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)
 {
-       fstring buf;
-       pstring d;
+       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)
+{
+#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;
 }
@@ -2615,61 +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;
+       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)) {
                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);
 }
 
 
@@ -2728,9 +2549,8 @@ static BOOL browse_host(const char *query_host)
        binding = talloc_asprintf(mem_ctx, "ncacn_np:%s", query_host);
 
        status = dcerpc_pipe_connect(mem_ctx, &p, binding, 
-                                    DCERPC_SRVSVC_UUID, 
-                                    DCERPC_SRVSVC_VERSION,
-                                    cmdline_credentials);
+                                        &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));
@@ -2786,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()
@@ -2794,7 +2616,7 @@ 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[] = 
@@ -2805,7 +2627,7 @@ static struct
   {"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}},
@@ -2840,7 +2662,7 @@ static struct
   {"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}},  
@@ -2862,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;
@@ -2891,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) {
@@ -2911,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, cmdline_credentials);
-               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;
@@ -2974,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;
@@ -3005,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;
@@ -3027,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;
@@ -3133,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;
@@ -3156,112 +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, struct cli_credentials *cred)
+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;
        NTSTATUS status;
+       struct smbclient_context *ctx = talloc_zero(mem_ctx, struct smbclient_context);
+       char *server, *share;
 
-       if (strncmp(share, "\\\\", 2) == 0 ||
-           strncmp(share, "//", 2) == 0) {
-               smbcli_parse_unc(share, NULL, &server, &share);
-       }
-       
-       status = smbcli_full_connection(NULL, &c, server,
-                                       share, NULL, cred);
-       if (!NT_STATUS_IS_OK(status)) {
-               d_printf("Connection to \\\\%s\\%s failed - %s\n", 
-                        server, share, nt_errstr(status));
+       if (!ctx) {
                return NULL;
        }
 
-       return c;
-}
+       rl_ctx = ctx; /* Ugly hack */
 
-
-/****************************************************************************
-  process commands from the client
-****************************************************************************/
-static int process(char *base_directory)
-{
-       int rc = 0;
-
-       cli = do_connect(desthost, service, cmdline_credentials);
-       if (!cli) {
-               return 1;
+       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);
        }
 
-       if (*base_directory) do_cd(base_directory);
+       ctx->remote_cur_dir = talloc_strdup(ctx, "\\");
        
-       if (cmdstr) {
-               rc = process_command_string(cmdstr);
-       } else {
-               process_stdin();
+       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;
        }
-  
-       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);
 }
 
@@ -3269,16 +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 nbt_name called, calling;
        const char *server_name;
+       struct smbcli_state *cli;
 
        make_nbt_name_client(&calling, lp_netbios_name());
 
        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);
@@ -3287,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
 
@@ -3349,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':
@@ -3386,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)));
@@ -3412,17 +3171,18 @@ 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, '/','\\');
+
+               service = s;
 
-               if (count_chars(service,'\\') < 3) {
-                       d_printf("\n%s: Not enough '\\' characters in service\n",service);
+               if (count_chars(s,'\\') < 3) {
+                       d_printf("\n%s: Not enough '\\' characters in service\n",s);
                        poptPrintUsage(pc, stderr, 0);
                        exit(1);
                }
@@ -3434,7 +3194,7 @@ static void remember_query_host(const char *arg,
 
        /*init_names(); */
 
-       if (!*query_host && !*service && !message) {
+       if (!query_host && !service && !message) {
                poptPrintUsage(pc, stderr, 0);
                exit(1);
        }
@@ -3443,25 +3203,35 @@ static void remember_query_host(const char *arg,
 
        DEBUG( 3, ( "Client started (version %s).\n", SAMBA_VERSION_STRING ) );
 
-       talloc_free(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;
 }