s4: fix various warnings (not "const" related ones)
[sfrench/samba-autobuild/.git] / source4 / client / client.c
1 /* 
2    Unix SMB/CIFS implementation.
3    SMB client
4    Copyright (C) Andrew Tridgell 1994-1998
5    Copyright (C) Simo Sorce 2001-2002
6    Copyright (C) Jelmer Vernooij 2003-2004
7    Copyright (C) James J Myers   2003 <myersjj@samba.org>
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 /* 
24  * TODO: remove this ... and don't use talloc_append_string()
25  *
26  * NOTE: I'm not changing the code yet, because I assume there're
27  *       some bugs in the existing code and I'm not sure how to fix
28  *       them correctly.
29  */
30 #define TALLOC_DEPRECATED 1
31
32 #include "includes.h"
33 #include "version.h"
34 #include "libcli/libcli.h"
35 #include "lib/events/events.h"
36 #include "lib/cmdline/popt_common.h"
37 #include "librpc/gen_ndr/ndr_srvsvc_c.h"
38 #include "librpc/gen_ndr/ndr_lsa.h"
39 #include "librpc/gen_ndr/ndr_security.h"
40 #include "libcli/raw/libcliraw.h"
41 #include "libcli/util/clilsa.h"
42 #include "system/dir.h"
43 #include "system/filesys.h"
44 #include "../lib/util/dlinklist.h"
45 #include "system/readline.h"
46 #include "auth/credentials/credentials.h"
47 #include "auth/gensec/gensec.h"
48 #include "system/time.h" /* needed by some systems for asctime() */
49 #include "libcli/resolve/resolve.h"
50 #include "libcli/security/security.h"
51 #include "lib/smbreadline/smbreadline.h"
52 #include "librpc/gen_ndr/ndr_nbt.h"
53 #include "param/param.h"
54 #include "librpc/rpc/dcerpc.h"
55 #include "libcli/raw/raw_proto.h"
56
57 /* the default pager to use for the client "more" command. Users can
58  *    override this with the PAGER environment variable */
59 #ifndef DEFAULT_PAGER
60 #define DEFAULT_PAGER "more"
61 #endif
62
63 struct smbclient_context {
64         char *remote_cur_dir;
65         struct smbcli_state *cli;
66         char *fileselection;
67         time_t newer_than;
68         bool prompt;
69         bool recurse;
70         int archive_level;
71         bool lowercase;
72         int printmode;
73         bool translation;
74         int io_bufsize;
75 };
76
77 /* timing globals */
78 static uint64_t get_total_size = 0;
79 static uint_t get_total_time_ms = 0;
80 static uint64_t put_total_size = 0;
81 static uint_t put_total_time_ms = 0;
82
83 /* Unfortunately, there is no way to pass the a context to the completion function as an argument */
84 static struct smbclient_context *rl_ctx; 
85
86 /* totals globals */
87 static double dir_total;
88
89 /*******************************************************************
90  Reduce a file name, removing .. elements.
91 ********************************************************************/
92 static void dos_clean_name(char *s)
93 {
94         char *p=NULL,*r;
95
96         DEBUG(3,("dos_clean_name [%s]\n",s));
97
98         /* remove any double slashes */
99         all_string_sub(s, "\\\\", "\\", 0);
100
101         while ((p = strstr(s,"\\..\\")) != NULL) {
102                 *p = '\0';
103                 if ((r = strrchr(s,'\\')) != NULL)
104                         memmove(r,p+3,strlen(p+3)+1);
105         }
106
107         trim_string(s,NULL,"\\..");
108
109         all_string_sub(s, "\\.\\", "\\", 0);
110 }
111
112 /****************************************************************************
113 write to a local file with CR/LF->LF translation if appropriate. return the 
114 number taken from the buffer. This may not equal the number written.
115 ****************************************************************************/
116 static int writefile(int f, const void *_b, int n, bool translation)
117 {
118         const uint8_t *b = (const uint8_t *)_b;
119         int i;
120
121         if (!translation) {
122                 return write(f,b,n);
123         }
124
125         i = 0;
126         while (i < n) {
127                 if (*b == '\r' && (i<(n-1)) && *(b+1) == '\n') {
128                         b++;i++;
129                 }
130                 if (write(f, b, 1) != 1) {
131                         break;
132                 }
133                 b++;
134                 i++;
135         }
136   
137         return(i);
138 }
139
140 /****************************************************************************
141   read from a file with LF->CR/LF translation if appropriate. return the 
142   number read. read approx n bytes.
143 ****************************************************************************/
144 static int readfile(void *_b, int n, XFILE *f, bool translation)
145 {
146         uint8_t *b = (uint8_t *)_b;
147         int i;
148         int c;
149
150         if (!translation)
151                 return x_fread(b,1,n,f);
152   
153         i = 0;
154         while (i < (n - 1)) {
155                 if ((c = x_getc(f)) == EOF) {
156                         break;
157                 }
158       
159                 if (c == '\n') { /* change all LFs to CR/LF */
160                         b[i++] = '\r';
161                 }
162       
163                 b[i++] = c;
164         }
165   
166         return(i);
167 }
168  
169
170 /****************************************************************************
171 send a message
172 ****************************************************************************/
173 static void send_message(struct smbcli_state *cli, const char *desthost)
174 {
175         char msg[1600];
176         int total_len = 0;
177         int grp_id;
178
179         if (!smbcli_message_start(cli->tree, desthost, cli_credentials_get_username(cmdline_credentials), &grp_id)) {
180                 d_printf("message start: %s\n", smbcli_errstr(cli->tree));
181                 return;
182         }
183
184
185         d_printf("Connected. Type your message, ending it with a Control-D\n");
186
187         while (!feof(stdin) && total_len < 1600) {
188                 int maxlen = MIN(1600 - total_len,127);
189                 int l=0;
190                 int c;
191
192                 for (l=0;l<maxlen && (c=fgetc(stdin))!=EOF;l++) {
193                         if (c == '\n')
194                                 msg[l++] = '\r';
195                         msg[l] = c;   
196                 }
197
198                 if (!smbcli_message_text(cli->tree, msg, l, grp_id)) {
199                         d_printf("SMBsendtxt failed (%s)\n",smbcli_errstr(cli->tree));
200                         return;
201                 }      
202                 
203                 total_len += l;
204         }
205
206         if (total_len >= 1600)
207                 d_printf("the message was truncated to 1600 bytes\n");
208         else
209                 d_printf("sent %d bytes\n",total_len);
210
211         if (!smbcli_message_end(cli->tree, grp_id)) {
212                 d_printf("SMBsendend failed (%s)\n",smbcli_errstr(cli->tree));
213                 return;
214         }      
215 }
216
217
218
219 /****************************************************************************
220 check the space on a device
221 ****************************************************************************/
222 static int do_dskattr(struct smbclient_context *ctx)
223 {
224         uint32_t bsize;
225         uint64_t total, avail;
226
227         if (NT_STATUS_IS_ERR(smbcli_dskattr(ctx->cli->tree, &bsize, &total, &avail))) {
228                 d_printf("Error in dskattr: %s\n",smbcli_errstr(ctx->cli->tree)); 
229                 return 1;
230         }
231
232         d_printf("\n\t\t%llu blocks of size %u. %llu blocks available\n",
233                  (unsigned long long)total, 
234                  (unsigned)bsize, 
235                  (unsigned long long)avail);
236
237         return 0;
238 }
239
240 /****************************************************************************
241 show cd/pwd
242 ****************************************************************************/
243 static int cmd_pwd(struct smbclient_context *ctx, const char **args)
244 {
245         d_printf("Current directory is %s\n", ctx->remote_cur_dir);
246         return 0;
247 }
248
249 /*
250   convert a string to dos format
251 */
252 static void dos_format(char *s)
253 {
254         string_replace(s, '/', '\\');
255 }
256
257 /****************************************************************************
258 change directory - inner section
259 ****************************************************************************/
260 static int do_cd(struct smbclient_context *ctx, const char *newdir)
261 {
262         char *dname;
263       
264         /* Save the current directory in case the
265            new directory is invalid */
266         if (newdir[0] == '\\')
267                 dname = talloc_strdup(ctx, newdir);
268         else
269                 dname = talloc_asprintf(ctx, "%s\\%s", ctx->remote_cur_dir, newdir);
270
271         dos_format(dname);
272
273         if (*(dname+strlen(dname)-1) != '\\') {
274                 dname = talloc_append_string(NULL, dname, "\\");
275         }
276         dos_clean_name(dname);
277         
278         if (NT_STATUS_IS_ERR(smbcli_chkpath(ctx->cli->tree, dname))) {
279                 d_printf("cd %s: %s\n", dname, smbcli_errstr(ctx->cli->tree));
280                 talloc_free(dname);
281         } else {
282                 ctx->remote_cur_dir = dname;
283         }
284         
285         return 0;
286 }
287
288 /****************************************************************************
289 change directory
290 ****************************************************************************/
291 static int cmd_cd(struct smbclient_context *ctx, const char **args)
292 {
293         int rc = 0;
294
295         if (args[1]) 
296                 rc = do_cd(ctx, args[1]);
297         else
298                 d_printf("Current directory is %s\n",ctx->remote_cur_dir);
299
300         return rc;
301 }
302
303
304 static bool mask_match(struct smbcli_state *c, const char *string, 
305                 const char *pattern, bool is_case_sensitive)
306 {
307         char *p2, *s2;
308         bool ret;
309
310         if (ISDOTDOT(string))
311                 string = ".";
312         if (ISDOT(pattern))
313                 return false;
314         
315         if (is_case_sensitive)
316                 return ms_fnmatch(pattern, string, 
317                                   c->transport->negotiate.protocol) == 0;
318
319         p2 = strlower_talloc(NULL, pattern);
320         s2 = strlower_talloc(NULL, string);
321         ret = ms_fnmatch(p2, s2, c->transport->negotiate.protocol) == 0;
322         talloc_free(p2);
323         talloc_free(s2);
324
325         return ret;
326 }
327
328
329
330 /*******************************************************************
331   decide if a file should be operated on
332   ********************************************************************/
333 static bool do_this_one(struct smbclient_context *ctx, struct clilist_file_info *finfo)
334 {
335         if (finfo->attrib & FILE_ATTRIBUTE_DIRECTORY) return(true);
336
337         if (ctx->fileselection && 
338             !mask_match(ctx->cli, finfo->name,ctx->fileselection,false)) {
339                 DEBUG(3,("mask_match %s failed\n", finfo->name));
340                 return false;
341         }
342
343         if (ctx->newer_than && finfo->mtime < ctx->newer_than) {
344                 DEBUG(3,("newer_than %s failed\n", finfo->name));
345                 return(false);
346         }
347
348         if ((ctx->archive_level==1 || ctx->archive_level==2) && !(finfo->attrib & FILE_ATTRIBUTE_ARCHIVE)) {
349                 DEBUG(3,("archive %s failed\n", finfo->name));
350                 return(false);
351         }
352         
353         return(true);
354 }
355
356 /****************************************************************************
357   display info about a file
358   ****************************************************************************/
359 static void display_finfo(struct smbclient_context *ctx, struct clilist_file_info *finfo)
360 {
361         if (do_this_one(ctx, finfo)) {
362                 time_t t = finfo->mtime; /* the time is assumed to be passed as GMT */
363                 char *astr = attrib_string(NULL, finfo->attrib);
364                 d_printf("  %-30s%7.7s %8.0f  %s",
365                          finfo->name,
366                          astr,
367                          (double)finfo->size,
368                          asctime(localtime(&t)));
369                 dir_total += finfo->size;
370                 talloc_free(astr);
371         }
372 }
373
374
375 /****************************************************************************
376    accumulate size of a file
377   ****************************************************************************/
378 static void do_du(struct smbclient_context *ctx, struct clilist_file_info *finfo)
379 {
380         if (do_this_one(ctx, finfo)) {
381                 dir_total += finfo->size;
382         }
383 }
384
385 static bool do_list_recurse;
386 static bool do_list_dirs;
387 static char *do_list_queue = 0;
388 static long do_list_queue_size = 0;
389 static long do_list_queue_start = 0;
390 static long do_list_queue_end = 0;
391 static void (*do_list_fn)(struct smbclient_context *, struct clilist_file_info *);
392
393 /****************************************************************************
394 functions for do_list_queue
395   ****************************************************************************/
396
397 /*
398  * The do_list_queue is a NUL-separated list of strings stored in a
399  * char*.  Since this is a FIFO, we keep track of the beginning and
400  * ending locations of the data in the queue.  When we overflow, we
401  * double the size of the char*.  When the start of the data passes
402  * the midpoint, we move everything back.  This is logically more
403  * complex than a linked list, but easier from a memory management
404  * angle.  In any memory error condition, do_list_queue is reset.
405  * Functions check to ensure that do_list_queue is non-NULL before
406  * accessing it.
407  */
408 static void reset_do_list_queue(void)
409 {
410         SAFE_FREE(do_list_queue);
411         do_list_queue_size = 0;
412         do_list_queue_start = 0;
413         do_list_queue_end = 0;
414 }
415
416 static void init_do_list_queue(void)
417 {
418         reset_do_list_queue();
419         do_list_queue_size = 1024;
420         do_list_queue = malloc_array_p(char, do_list_queue_size);
421         if (do_list_queue == 0) { 
422                 d_printf("malloc fail for size %d\n",
423                          (int)do_list_queue_size);
424                 reset_do_list_queue();
425         } else {
426                 memset(do_list_queue, 0, do_list_queue_size);
427         }
428 }
429
430 static void adjust_do_list_queue(void)
431 {
432         if (do_list_queue == NULL) return;
433
434         /*
435          * If the starting point of the queue is more than half way through,
436          * move everything toward the beginning.
437          */
438         if (do_list_queue_start == do_list_queue_end)
439         {
440                 DEBUG(4,("do_list_queue is empty\n"));
441                 do_list_queue_start = do_list_queue_end = 0;
442                 *do_list_queue = '\0';
443         }
444         else if (do_list_queue_start > (do_list_queue_size / 2))
445         {
446                 DEBUG(4,("sliding do_list_queue backward\n"));
447                 memmove(do_list_queue,
448                         do_list_queue + do_list_queue_start,
449                         do_list_queue_end - do_list_queue_start);
450                 do_list_queue_end -= do_list_queue_start;
451                 do_list_queue_start = 0;
452         }
453            
454 }
455
456 static void add_to_do_list_queue(const char* entry)
457 {
458         char *dlq;
459         long new_end = do_list_queue_end + ((long)strlen(entry)) + 1;
460         while (new_end > do_list_queue_size)
461         {
462                 do_list_queue_size *= 2;
463                 DEBUG(4,("enlarging do_list_queue to %d\n",
464                          (int)do_list_queue_size));
465                 dlq = realloc_p(do_list_queue, char, do_list_queue_size);
466                 if (! dlq) {
467                         d_printf("failure enlarging do_list_queue to %d bytes\n",
468                                  (int)do_list_queue_size);
469                         reset_do_list_queue();
470                 }
471                 else
472                 {
473                         do_list_queue = dlq;
474                         memset(do_list_queue + do_list_queue_size / 2,
475                                0, do_list_queue_size / 2);
476                 }
477         }
478         if (do_list_queue)
479         {
480                 safe_strcpy(do_list_queue + do_list_queue_end, entry, 
481                             do_list_queue_size - do_list_queue_end - 1);
482                 do_list_queue_end = new_end;
483                 DEBUG(4,("added %s to do_list_queue (start=%d, end=%d)\n",
484                          entry, (int)do_list_queue_start, (int)do_list_queue_end));
485         }
486 }
487
488 static char *do_list_queue_head(void)
489 {
490         return do_list_queue + do_list_queue_start;
491 }
492
493 static void remove_do_list_queue_head(void)
494 {
495         if (do_list_queue_end > do_list_queue_start)
496         {
497                 do_list_queue_start += strlen(do_list_queue_head()) + 1;
498                 adjust_do_list_queue();
499                 DEBUG(4,("removed head of do_list_queue (start=%d, end=%d)\n",
500                          (int)do_list_queue_start, (int)do_list_queue_end));
501         }
502 }
503
504 static int do_list_queue_empty(void)
505 {
506         return (! (do_list_queue && *do_list_queue));
507 }
508
509 /****************************************************************************
510 a helper for do_list
511   ****************************************************************************/
512 static void do_list_helper(struct clilist_file_info *f, const char *mask, void *state)
513 {
514         struct smbclient_context *ctx = (struct smbclient_context *)state;
515
516         if (f->attrib & FILE_ATTRIBUTE_DIRECTORY) {
517                 if (do_list_dirs && do_this_one(ctx, f)) {
518                         do_list_fn(ctx, f);
519                 }
520                 if (do_list_recurse && 
521                     !ISDOT(f->name) &&
522                     !ISDOTDOT(f->name)) {
523                         char *mask2;
524                         char *p;
525
526                         mask2 = talloc_strdup(NULL, mask);
527                         p = strrchr_m(mask2,'\\');
528                         if (!p) return;
529                         p[1] = 0;
530                         mask2 = talloc_asprintf_append_buffer(mask2, "%s\\*", f->name);
531                         add_to_do_list_queue(mask2);
532                 }
533                 return;
534         }
535
536         if (do_this_one(ctx, f)) {
537                 do_list_fn(ctx, f);
538         }
539 }
540
541
542 /****************************************************************************
543 a wrapper around smbcli_list that adds recursion
544   ****************************************************************************/
545 static void do_list(struct smbclient_context *ctx, const char *mask,uint16_t attribute,
546              void (*fn)(struct smbclient_context *, struct clilist_file_info *),bool rec, bool dirs)
547 {
548         static int in_do_list = 0;
549
550         if (in_do_list && rec)
551         {
552                 fprintf(stderr, "INTERNAL ERROR: do_list called recursively when the recursive flag is true\n");
553                 exit(1);
554         }
555
556         in_do_list = 1;
557
558         do_list_recurse = rec;
559         do_list_dirs = dirs;
560         do_list_fn = fn;
561
562         if (rec)
563         {
564                 init_do_list_queue();
565                 add_to_do_list_queue(mask);
566                 
567                 while (! do_list_queue_empty())
568                 {
569                         /*
570                          * Need to copy head so that it doesn't become
571                          * invalid inside the call to smbcli_list.  This
572                          * would happen if the list were expanded
573                          * during the call.
574                          * Fix from E. Jay Berkenbilt (ejb@ql.org)
575                          */
576                         char *head;
577                         head = do_list_queue_head();
578                         smbcli_list(ctx->cli->tree, head, attribute, do_list_helper, ctx);
579                         remove_do_list_queue_head();
580                         if ((! do_list_queue_empty()) && (fn == display_finfo))
581                         {
582                                 char* next_file = do_list_queue_head();
583                                 char* save_ch = 0;
584                                 if ((strlen(next_file) >= 2) &&
585                                     (next_file[strlen(next_file) - 1] == '*') &&
586                                     (next_file[strlen(next_file) - 2] == '\\'))
587                                 {
588                                         save_ch = next_file +
589                                                 strlen(next_file) - 2;
590                                         *save_ch = '\0';
591                                 }
592                                 d_printf("\n%s\n",next_file);
593                                 if (save_ch)
594                                 {
595                                         *save_ch = '\\';
596                                 }
597                         }
598                 }
599         }
600         else
601         {
602                 if (smbcli_list(ctx->cli->tree, mask, attribute, do_list_helper, ctx) == -1)
603                 {
604                         d_printf("%s listing %s\n", smbcli_errstr(ctx->cli->tree), mask);
605                 }
606         }
607
608         in_do_list = 0;
609         reset_do_list_queue();
610 }
611
612 /****************************************************************************
613   get a directory listing
614   ****************************************************************************/
615 static int cmd_dir(struct smbclient_context *ctx, const char **args)
616 {
617         uint16_t attribute = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
618         char *mask;
619         int rc;
620         
621         dir_total = 0;
622         
623         mask = talloc_strdup(ctx, ctx->remote_cur_dir);
624         if(mask[strlen(mask)-1]!='\\')
625                 mask = talloc_append_string(ctx, mask,"\\");
626         
627         if (args[1]) {
628                 mask = talloc_strdup(ctx, args[1]);
629                 if (mask[0] != '\\')
630                         mask = talloc_append_string(ctx, mask, "\\");
631                 dos_format(mask);
632         }
633         else {
634                 if (ctx->cli->tree->session->transport->negotiate.protocol <= 
635                     PROTOCOL_LANMAN1) { 
636                         mask = talloc_append_string(ctx, mask, "*.*");
637                 } else {
638                         mask = talloc_append_string(ctx, mask, "*");
639                 }
640         }
641
642         do_list(ctx, mask, attribute, display_finfo, ctx->recurse, true);
643
644         rc = do_dskattr(ctx);
645
646         DEBUG(3, ("Total bytes listed: %.0f\n", dir_total));
647
648         return rc;
649 }
650
651
652 /****************************************************************************
653   get a directory listing
654   ****************************************************************************/
655 static int cmd_du(struct smbclient_context *ctx, const char **args)
656 {
657         uint16_t attribute = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
658         int rc;
659         char *mask;
660         
661         dir_total = 0;
662         
663         if (args[1]) {
664                 if (args[1][0] == '\\')
665                         mask = talloc_strdup(ctx, args[1]);
666                 else
667                         mask = talloc_asprintf(ctx, "%s\\%s", ctx->remote_cur_dir, args[1]);
668                 dos_format(mask);
669         } else {
670                 mask = talloc_asprintf(ctx, "%s\\*", ctx->remote_cur_dir);
671         }
672
673         do_list(ctx, mask, attribute, do_du, ctx->recurse, true);
674
675         talloc_free(mask);
676
677         rc = do_dskattr(ctx);
678
679         d_printf("Total number of bytes: %.0f\n", dir_total);
680
681         return rc;
682 }
683
684
685 /****************************************************************************
686   get a file from rname to lname
687   ****************************************************************************/
688 static int do_get(struct smbclient_context *ctx, char *rname, const char *p_lname, bool reget)
689 {  
690         int handle = 0, fnum;
691         bool newhandle = false;
692         uint8_t *data;
693         struct timeval tp_start;
694         int read_size = ctx->io_bufsize;
695         uint16_t attr;
696         size_t size;
697         off_t start = 0;
698         off_t nread = 0;
699         int rc = 0;
700         char *lname;
701
702
703         lname = talloc_strdup(ctx, p_lname);
704         GetTimeOfDay(&tp_start);
705
706         if (ctx->lowercase) {
707                 strlower(lname);
708         }
709
710         fnum = smbcli_open(ctx->cli->tree, rname, O_RDONLY, DENY_NONE);
711
712         if (fnum == -1) {
713                 d_printf("%s opening remote file %s\n",smbcli_errstr(ctx->cli->tree),rname);
714                 return 1;
715         }
716
717         if(!strcmp(lname,"-")) {
718                 handle = fileno(stdout);
719         } else {
720                 if (reget) {
721                         handle = open(lname, O_WRONLY|O_CREAT, 0644);
722                         if (handle >= 0) {
723                                 start = lseek(handle, 0, SEEK_END);
724                                 if (start == -1) {
725                                         d_printf("Error seeking local file\n");
726                                         return 1;
727                                 }
728                         }
729                 } else {
730                         handle = open(lname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
731                 }
732                 newhandle = true;
733         }
734         if (handle < 0) {
735                 d_printf("Error opening local file %s\n",lname);
736                 return 1;
737         }
738
739
740         if (NT_STATUS_IS_ERR(smbcli_qfileinfo(ctx->cli->tree, fnum, 
741                            &attr, &size, NULL, NULL, NULL, NULL, NULL)) &&
742             NT_STATUS_IS_ERR(smbcli_getattrE(ctx->cli->tree, fnum, 
743                           &attr, &size, NULL, NULL, NULL))) {
744                 d_printf("getattrib: %s\n",smbcli_errstr(ctx->cli->tree));
745                 return 1;
746         }
747
748         DEBUG(2,("getting file %s of size %.0f as %s ", 
749                  rname, (double)size, lname));
750
751         if(!(data = (uint8_t *)malloc(read_size))) { 
752                 d_printf("malloc fail for size %d\n", read_size);
753                 smbcli_close(ctx->cli->tree, fnum);
754                 return 1;
755         }
756
757         while (1) {
758                 int n = smbcli_read(ctx->cli->tree, fnum, data, nread + start, read_size);
759
760                 if (n <= 0) break;
761  
762                 if (writefile(handle,data, n, ctx->translation) != n) {
763                         d_printf("Error writing local file\n");
764                         rc = 1;
765                         break;
766                 }
767       
768                 nread += n;
769         }
770
771         if (nread + start < size) {
772                 DEBUG (0, ("Short read when getting file %s. Only got %ld bytes.\n",
773                             rname, (long)nread));
774
775                 rc = 1;
776         }
777
778         SAFE_FREE(data);
779         
780         if (NT_STATUS_IS_ERR(smbcli_close(ctx->cli->tree, fnum))) {
781                 d_printf("Error %s closing remote file\n",smbcli_errstr(ctx->cli->tree));
782                 rc = 1;
783         }
784
785         if (newhandle) {
786                 close(handle);
787         }
788
789         if (ctx->archive_level >= 2 && (attr & FILE_ATTRIBUTE_ARCHIVE)) {
790                 smbcli_setatr(ctx->cli->tree, rname, attr & ~(uint16_t)FILE_ATTRIBUTE_ARCHIVE, 0);
791         }
792
793         {
794                 struct timeval tp_end;
795                 int this_time;
796                 
797                 GetTimeOfDay(&tp_end);
798                 this_time = 
799                         (tp_end.tv_sec - tp_start.tv_sec)*1000 +
800                         (tp_end.tv_usec - tp_start.tv_usec)/1000;
801                 get_total_time_ms += this_time;
802                 get_total_size += nread;
803                 
804                 DEBUG(2,("(%3.1f kb/s) (average %3.1f kb/s)\n",
805                          nread / (1.024*this_time + 1.0e-4),
806                          get_total_size / (1.024*get_total_time_ms)));
807         }
808         
809         return rc;
810 }
811
812
813 /****************************************************************************
814   get a file
815   ****************************************************************************/
816 static int cmd_get(struct smbclient_context *ctx, const char **args)
817 {
818         const char *lname;
819         char *rname;
820
821         if (!args[1]) {
822                 d_printf("get <filename>\n");
823                 return 1;
824         }
825
826         rname = talloc_asprintf(ctx, "%s\\%s", ctx->remote_cur_dir, args[1]);
827
828         if (args[2]) 
829                 lname = args[2];
830         else 
831                 lname = args[1];
832         
833         dos_clean_name(rname);
834         
835         return do_get(ctx, rname, lname, false);
836 }
837
838 /****************************************************************************
839  Put up a yes/no prompt.
840 ****************************************************************************/
841 static bool yesno(char *p)
842 {
843         char ans[4];
844         printf("%s",p);
845
846         if (!fgets(ans,sizeof(ans)-1,stdin))
847                 return(false);
848
849         if (*ans == 'y' || *ans == 'Y')
850                 return(true);
851
852         return(false);
853 }
854
855 /****************************************************************************
856   do a mget operation on one file
857   ****************************************************************************/
858 static void do_mget(struct smbclient_context *ctx, struct clilist_file_info *finfo)
859 {
860         char *rname;
861         char *quest;
862         char *mget_mask;
863         char *saved_curdir;
864         char *l_fname;
865
866         if (ISDOT(finfo->name) || ISDOTDOT(finfo->name))
867                 return;
868
869         if (finfo->attrib & FILE_ATTRIBUTE_DIRECTORY)
870                 asprintf(&quest, "Get directory %s? ",finfo->name);
871         else
872                 asprintf(&quest, "Get file %s? ",finfo->name);
873
874         if (ctx->prompt && !yesno(quest)) return;
875
876         SAFE_FREE(quest);
877
878         if (!(finfo->attrib & FILE_ATTRIBUTE_DIRECTORY)) {
879                 asprintf(&rname, "%s%s",ctx->remote_cur_dir,finfo->name);
880                 do_get(ctx, rname, finfo->name, false);
881                 SAFE_FREE(rname);
882                 return;
883         }
884
885         /* handle directories */
886         saved_curdir = talloc_strdup(ctx, ctx->remote_cur_dir);
887
888         ctx->remote_cur_dir = talloc_asprintf_append_buffer(NULL, "%s\\", finfo->name);
889
890         l_fname = talloc_strdup(ctx, finfo->name);
891
892         string_replace(l_fname, '\\', '/');
893         if (ctx->lowercase) {
894                 strlower(l_fname);
895         }
896         
897         if (!directory_exist(l_fname) &&
898             mkdir(l_fname, 0777) != 0) {
899                 d_printf("failed to create directory %s\n", l_fname);
900                 return;
901         }
902         
903         if (chdir(l_fname) != 0) {
904                 d_printf("failed to chdir to directory %s\n", l_fname);
905                 return;
906         }
907
908         mget_mask = talloc_asprintf(ctx, "%s*", ctx->remote_cur_dir);
909         
910         do_list(ctx, mget_mask, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY,do_mget,false, true);
911         chdir("..");
912         talloc_free(ctx->remote_cur_dir);
913
914         ctx->remote_cur_dir = saved_curdir;
915 }
916
917
918 /****************************************************************************
919 view the file using the pager
920 ****************************************************************************/
921 static int cmd_more(struct smbclient_context *ctx, const char **args)
922 {
923         char *rname;
924         char *pager_cmd;
925         char *lname;
926         char *pager;
927         int fd;
928         int rc = 0;
929
930         lname = talloc_asprintf(ctx, "%s/smbmore.XXXXXX",tmpdir());
931         fd = mkstemp(lname);
932         if (fd == -1) {
933                 d_printf("failed to create temporary file for more\n");
934                 return 1;
935         }
936         close(fd);
937
938         if (!args[1]) {
939                 d_printf("more <filename>\n");
940                 unlink(lname);
941                 return 1;
942         }
943         rname = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[1]);
944         dos_clean_name(rname);
945
946         rc = do_get(ctx, rname, lname, false);
947
948         pager=getenv("PAGER");
949
950         pager_cmd = talloc_asprintf(ctx, "%s %s",(pager? pager:DEFAULT_PAGER), lname);
951         system(pager_cmd);
952         unlink(lname);
953         
954         return rc;
955 }
956
957
958
959 /****************************************************************************
960 do a mget command
961 ****************************************************************************/
962 static int cmd_mget(struct smbclient_context *ctx, const char **args)
963 {
964         uint16_t attribute = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
965         char *mget_mask = NULL;
966         int i;
967
968         if (ctx->recurse)
969                 attribute |= FILE_ATTRIBUTE_DIRECTORY;
970         
971         for (i = 1; args[i]; i++) {
972                 mget_mask = talloc_strdup(ctx, ctx->remote_cur_dir);
973                 if(mget_mask[strlen(mget_mask)-1]!='\\')
974                         mget_mask = talloc_append_string(ctx, mget_mask, "\\");
975                 
976                 mget_mask = talloc_strdup(ctx, args[i]);
977                 if (mget_mask[0] != '\\')
978                         mget_mask = talloc_append_string(ctx, mget_mask, "\\");
979                 do_list(ctx, mget_mask, attribute,do_mget,false,true);
980
981                 talloc_free(mget_mask);
982         }
983
984         if (mget_mask == NULL) {
985                 mget_mask = talloc_asprintf(ctx, "%s\\*", ctx->remote_cur_dir);
986                 do_list(ctx, mget_mask, attribute,do_mget,false,true);
987                 talloc_free(mget_mask);
988         }
989         
990         return 0;
991 }
992
993
994 /****************************************************************************
995 make a directory of name "name"
996 ****************************************************************************/
997 static NTSTATUS do_mkdir(struct smbclient_context *ctx, char *name)
998 {
999         NTSTATUS status;
1000
1001         if (NT_STATUS_IS_ERR(status = smbcli_mkdir(ctx->cli->tree, name))) {
1002                 d_printf("%s making remote directory %s\n",
1003                          smbcli_errstr(ctx->cli->tree),name);
1004                 return status;
1005         }
1006
1007         return status;
1008 }
1009
1010
1011 /****************************************************************************
1012  Exit client.
1013 ****************************************************************************/
1014 static int cmd_quit(struct smbclient_context *ctx, const char **args)
1015 {
1016         talloc_free(ctx);
1017         exit(0);
1018         /* NOTREACHED */
1019         return 0;
1020 }
1021
1022
1023 /****************************************************************************
1024   make a directory
1025   ****************************************************************************/
1026 static int cmd_mkdir(struct smbclient_context *ctx, const char **args)
1027 {
1028         char *mask, *p;
1029   
1030         if (!args[1]) {
1031                 if (!ctx->recurse)
1032                         d_printf("mkdir <dirname>\n");
1033                 return 1;
1034         }
1035
1036         mask = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir,args[1]);
1037
1038         if (ctx->recurse) {
1039                 dos_clean_name(mask);
1040
1041                 trim_string(mask,".",NULL);
1042                 for (p = strtok(mask,"/\\"); p; p = strtok(p, "/\\")) {
1043                         char *parent = talloc_strndup(ctx, mask, PTR_DIFF(p, mask));
1044                         
1045                         if (NT_STATUS_IS_ERR(smbcli_chkpath(ctx->cli->tree, parent))) { 
1046                                 do_mkdir(ctx, parent);
1047                         }
1048
1049                         talloc_free(parent);
1050                 }        
1051         } else {
1052                 do_mkdir(ctx, mask);
1053         }
1054         
1055         return 0;
1056 }
1057
1058 /****************************************************************************
1059 show 8.3 name of a file
1060 ****************************************************************************/
1061 static int cmd_altname(struct smbclient_context *ctx, const char **args)
1062 {
1063         const char *altname;
1064         char *name;
1065   
1066         if (!args[1]) {
1067                 d_printf("altname <file>\n");
1068                 return 1;
1069         }
1070
1071         name = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[1]);
1072
1073         if (!NT_STATUS_IS_OK(smbcli_qpathinfo_alt_name(ctx->cli->tree, name, &altname))) {
1074                 d_printf("%s getting alt name for %s\n",
1075                          smbcli_errstr(ctx->cli->tree),name);
1076                 return(false);
1077         }
1078         d_printf("%s\n", altname);
1079
1080         return 0;
1081 }
1082
1083
1084 /****************************************************************************
1085   put a single file
1086   ****************************************************************************/
1087 static int do_put(struct smbclient_context *ctx, char *rname, char *lname, bool reput)
1088 {
1089         int fnum;
1090         XFILE *f;
1091         size_t start = 0;
1092         off_t nread = 0;
1093         uint8_t *buf = NULL;
1094         int maxwrite = ctx->io_bufsize;
1095         int rc = 0;
1096         
1097         struct timeval tp_start;
1098         GetTimeOfDay(&tp_start);
1099
1100         if (reput) {
1101                 fnum = smbcli_open(ctx->cli->tree, rname, O_RDWR|O_CREAT, DENY_NONE);
1102                 if (fnum >= 0) {
1103                         if (NT_STATUS_IS_ERR(smbcli_qfileinfo(ctx->cli->tree, fnum, NULL, &start, NULL, NULL, NULL, NULL, NULL)) &&
1104                             NT_STATUS_IS_ERR(smbcli_getattrE(ctx->cli->tree, fnum, NULL, &start, NULL, NULL, NULL))) {
1105                                 d_printf("getattrib: %s\n",smbcli_errstr(ctx->cli->tree));
1106                                 return 1;
1107                         }
1108                 }
1109         } else {
1110                 fnum = smbcli_open(ctx->cli->tree, rname, O_RDWR|O_CREAT|O_TRUNC, 
1111                                 DENY_NONE);
1112         }
1113   
1114         if (fnum == -1) {
1115                 d_printf("%s opening remote file %s\n",smbcli_errstr(ctx->cli->tree),rname);
1116                 return 1;
1117         }
1118
1119         /* allow files to be piped into smbclient
1120            jdblair 24.jun.98
1121
1122            Note that in this case this function will exit(0) rather
1123            than returning. */
1124         if (!strcmp(lname, "-")) {
1125                 f = x_stdin;
1126                 /* size of file is not known */
1127         } else {
1128                 f = x_fopen(lname,O_RDONLY, 0);
1129                 if (f && reput) {
1130                         if (x_tseek(f, start, SEEK_SET) == -1) {
1131                                 d_printf("Error seeking local file\n");
1132                                 return 1;
1133                         }
1134                 }
1135         }
1136
1137         if (!f) {
1138                 d_printf("Error opening local file %s\n",lname);
1139                 return 1;
1140         }
1141
1142   
1143         DEBUG(1,("putting file %s as %s ",lname,
1144                  rname));
1145   
1146         buf = (uint8_t *)malloc(maxwrite);
1147         if (!buf) {
1148                 d_printf("ERROR: Not enough memory!\n");
1149                 return 1;
1150         }
1151         while (!x_feof(f)) {
1152                 int n = maxwrite;
1153                 int ret;
1154
1155                 if ((n = readfile(buf,n,f,ctx->translation)) < 1) {
1156                         if((n == 0) && x_feof(f))
1157                                 break; /* Empty local file. */
1158
1159                         d_printf("Error reading local file: %s\n", strerror(errno));
1160                         rc = 1;
1161                         break;
1162                 }
1163
1164                 ret = smbcli_write(ctx->cli->tree, fnum, 0, buf, nread + start, n);
1165
1166                 if (n != ret) {
1167                         d_printf("Error writing file: %s\n", smbcli_errstr(ctx->cli->tree));
1168                         rc = 1;
1169                         break;
1170                 } 
1171
1172                 nread += n;
1173         }
1174
1175         if (NT_STATUS_IS_ERR(smbcli_close(ctx->cli->tree, fnum))) {
1176                 d_printf("%s closing remote file %s\n",smbcli_errstr(ctx->cli->tree),rname);
1177                 x_fclose(f);
1178                 SAFE_FREE(buf);
1179                 return 1;
1180         }
1181
1182         
1183         if (f != x_stdin) {
1184                 x_fclose(f);
1185         }
1186
1187         SAFE_FREE(buf);
1188
1189         {
1190                 struct timeval tp_end;
1191                 int this_time;
1192                 
1193                 GetTimeOfDay(&tp_end);
1194                 this_time = 
1195                         (tp_end.tv_sec - tp_start.tv_sec)*1000 +
1196                         (tp_end.tv_usec - tp_start.tv_usec)/1000;
1197                 put_total_time_ms += this_time;
1198                 put_total_size += nread;
1199                 
1200                 DEBUG(1,("(%3.1f kb/s) (average %3.1f kb/s)\n",
1201                          nread / (1.024*this_time + 1.0e-4),
1202                          put_total_size / (1.024*put_total_time_ms)));
1203         }
1204
1205         if (f == x_stdin) {
1206                 talloc_free(ctx);
1207                 exit(0);
1208         }
1209         
1210         return rc;
1211 }
1212
1213  
1214
1215 /****************************************************************************
1216   put a file
1217   ****************************************************************************/
1218 static int cmd_put(struct smbclient_context *ctx, const char **args)
1219 {
1220         char *lname;
1221         char *rname;
1222         
1223         if (!args[1]) {
1224                 d_printf("put <filename> [<remotename>]\n");
1225                 return 1;
1226         }
1227
1228         lname = talloc_strdup(ctx, args[1]);
1229   
1230         if (args[2]) {
1231                 if (args[2][0]=='\\')
1232                         rname = talloc_strdup(ctx, args[2]);
1233                 else
1234                         rname = talloc_asprintf(ctx, "%s\\%s", ctx->remote_cur_dir, args[2]);
1235         } else {
1236                 rname = talloc_asprintf(ctx, "%s\\%s", ctx->remote_cur_dir, lname);
1237         }
1238         
1239         dos_clean_name(rname);
1240
1241         /* allow '-' to represent stdin
1242            jdblair, 24.jun.98 */
1243         if (!file_exist(lname) && (strcmp(lname,"-"))) {
1244                 d_printf("%s does not exist\n",lname);
1245                 return 1;
1246         }
1247
1248         return do_put(ctx, rname, lname, false);
1249 }
1250
1251 /*************************************
1252   File list structure
1253 *************************************/
1254
1255 static struct file_list {
1256         struct file_list *prev, *next;
1257         char *file_path;
1258         bool isdir;
1259 } *file_list;
1260
1261 /****************************************************************************
1262   Free a file_list structure
1263 ****************************************************************************/
1264
1265 static void free_file_list (struct file_list * list)
1266 {
1267         struct file_list *tmp;
1268         
1269         while (list)
1270         {
1271                 tmp = list;
1272                 DLIST_REMOVE(list, list);
1273                 SAFE_FREE(tmp->file_path);
1274                 SAFE_FREE(tmp);
1275         }
1276 }
1277
1278 /****************************************************************************
1279   seek in a directory/file list until you get something that doesn't start with
1280   the specified name
1281   ****************************************************************************/
1282 static bool seek_list(struct file_list *list, char *name)
1283 {
1284         while (list) {
1285                 trim_string(list->file_path,"./","\n");
1286                 if (strncmp(list->file_path, name, strlen(name)) != 0) {
1287                         return(true);
1288                 }
1289                 list = list->next;
1290         }
1291       
1292         return(false);
1293 }
1294
1295 /****************************************************************************
1296   set the file selection mask
1297   ****************************************************************************/
1298 static int cmd_select(struct smbclient_context *ctx, const char **args)
1299 {
1300         talloc_free(ctx->fileselection);
1301         ctx->fileselection = talloc_strdup(ctx, args[1]);
1302
1303         return 0;
1304 }
1305
1306 /*******************************************************************
1307   A readdir wrapper which just returns the file name.
1308  ********************************************************************/
1309 static const char *readdirname(DIR *p)
1310 {
1311         struct dirent *ptr;
1312         char *dname;
1313
1314         if (!p)
1315                 return(NULL);
1316   
1317         ptr = (struct dirent *)readdir(p);
1318         if (!ptr)
1319                 return(NULL);
1320
1321         dname = ptr->d_name;
1322
1323 #ifdef NEXT2
1324         if (telldir(p) < 0)
1325                 return(NULL);
1326 #endif
1327
1328 #ifdef HAVE_BROKEN_READDIR
1329         /* using /usr/ucb/cc is BAD */
1330         dname = dname - 2;
1331 #endif
1332
1333         {
1334                 static char *buf;
1335                 int len = NAMLEN(ptr);
1336                 buf = talloc_strndup(NULL, dname, len);
1337                 dname = buf;
1338         }
1339
1340         return(dname);
1341 }
1342
1343 /****************************************************************************
1344   Recursive file matching function act as find
1345   match must be always set to true when calling this function
1346 ****************************************************************************/
1347 static int file_find(struct smbclient_context *ctx, struct file_list **list, const char *directory, 
1348                       const char *expression, bool match)
1349 {
1350         DIR *dir;
1351         struct file_list *entry;
1352         struct stat statbuf;
1353         int ret;
1354         char *path;
1355         bool isdir;
1356         const char *dname;
1357
1358         dir = opendir(directory);
1359         if (!dir) return -1;
1360         
1361         while ((dname = readdirname(dir))) {
1362                 if (ISDOT(dname) || ISDOTDOT(dname)) {
1363                         continue;
1364                 }
1365                 
1366                 if (asprintf(&path, "%s/%s", directory, dname) <= 0) {
1367                         continue;
1368                 }
1369
1370                 isdir = false;
1371                 if (!match || !gen_fnmatch(expression, dname)) {
1372                         if (ctx->recurse) {
1373                                 ret = stat(path, &statbuf);
1374                                 if (ret == 0) {
1375                                         if (S_ISDIR(statbuf.st_mode)) {
1376                                                 isdir = true;
1377                                                 ret = file_find(ctx, list, path, expression, false);
1378                                         }
1379                                 } else {
1380                                         d_printf("file_find: cannot stat file %s\n", path);
1381                                 }
1382                                 
1383                                 if (ret == -1) {
1384                                         SAFE_FREE(path);
1385                                         closedir(dir);
1386                                         return -1;
1387                                 }
1388                         }
1389                         entry = malloc_p(struct file_list);
1390                         if (!entry) {
1391                                 d_printf("Out of memory in file_find\n");
1392                                 closedir(dir);
1393                                 return -1;
1394                         }
1395                         entry->file_path = path;
1396                         entry->isdir = isdir;
1397                         DLIST_ADD(*list, entry);
1398                 } else {
1399                         SAFE_FREE(path);
1400                 }
1401         }
1402
1403         closedir(dir);
1404         return 0;
1405 }
1406
1407 /****************************************************************************
1408   mput some files
1409   ****************************************************************************/
1410 static int cmd_mput(struct smbclient_context *ctx, const char **args)
1411 {
1412         int i;
1413         
1414         for (i = 1; args[i]; i++) {
1415                 int ret;
1416                 struct file_list *temp_list;
1417                 char *quest, *lname, *rname;
1418
1419                 printf("%s\n", args[i]);
1420         
1421                 file_list = NULL;
1422
1423                 ret = file_find(ctx, &file_list, ".", args[i], true);
1424                 if (ret) {
1425                         free_file_list(file_list);
1426                         continue;
1427                 }
1428                 
1429                 quest = NULL;
1430                 lname = NULL;
1431                 rname = NULL;
1432                                 
1433                 for (temp_list = file_list; temp_list; 
1434                      temp_list = temp_list->next) {
1435
1436                         SAFE_FREE(lname);
1437                         if (asprintf(&lname, "%s/", temp_list->file_path) <= 0)
1438                                 continue;
1439                         trim_string(lname, "./", "/");
1440                         
1441                         /* check if it's a directory */
1442                         if (temp_list->isdir) {
1443                                 /* if (!recurse) continue; */
1444                                 
1445                                 SAFE_FREE(quest);
1446                                 if (asprintf(&quest, "Put directory %s? ", lname) < 0) break;
1447                                 if (ctx->prompt && !yesno(quest)) { /* No */
1448                                         /* Skip the directory */
1449                                         lname[strlen(lname)-1] = '/';
1450                                         if (!seek_list(temp_list, lname))
1451                                                 break;              
1452                                 } else { /* Yes */
1453                                         SAFE_FREE(rname);
1454                                         if(asprintf(&rname, "%s%s", ctx->remote_cur_dir, lname) < 0) break;
1455                                         dos_format(rname);
1456                                         if (NT_STATUS_IS_ERR(smbcli_chkpath(ctx->cli->tree, rname)) && 
1457                                             NT_STATUS_IS_ERR(do_mkdir(ctx, rname))) {
1458                                                 DEBUG (0, ("Unable to make dir, skipping..."));
1459                                                 /* Skip the directory */
1460                                                 lname[strlen(lname)-1] = '/';
1461                                                 if (!seek_list(temp_list, lname))
1462                                                         break;
1463                                         }
1464                                 }
1465                                 continue;
1466                         } else {
1467                                 SAFE_FREE(quest);
1468                                 if (asprintf(&quest,"Put file %s? ", lname) < 0) break;
1469                                 if (ctx->prompt && !yesno(quest)) /* No */
1470                                         continue;
1471                                 
1472                                 /* Yes */
1473                                 SAFE_FREE(rname);
1474                                 if (asprintf(&rname, "%s%s", ctx->remote_cur_dir, lname) < 0) break;
1475                         }
1476
1477                         dos_format(rname);
1478
1479                         do_put(ctx, rname, lname, false);
1480                 }
1481                 free_file_list(file_list);
1482                 SAFE_FREE(quest);
1483                 SAFE_FREE(lname);
1484                 SAFE_FREE(rname);
1485         }
1486
1487         return 0;
1488 }
1489
1490
1491 /****************************************************************************
1492   print a file
1493   ****************************************************************************/
1494 static int cmd_print(struct smbclient_context *ctx, const char **args)
1495 {
1496         char *lname, *rname;
1497         char *p;
1498
1499         if (!args[1]) {
1500                 d_printf("print <filename>\n");
1501                 return 1;
1502         }
1503
1504         lname = talloc_strdup(ctx, args[1]);
1505
1506         rname = talloc_strdup(ctx, lname);
1507         p = strrchr_m(rname,'/');
1508         if (p) {
1509                 slprintf(rname, sizeof(rname)-1, "%s-%d", p+1, (int)getpid());
1510         }
1511
1512         if (strequal(lname,"-")) {
1513                 slprintf(rname, sizeof(rname)-1, "stdin-%d", (int)getpid());
1514         }
1515
1516         return do_put(ctx, rname, lname, false);
1517 }
1518
1519
1520 static int cmd_rewrite(struct smbclient_context *ctx, const char **args)
1521 {
1522         d_printf("REWRITE: command not implemented (FIXME!)\n");
1523         
1524         return 0;
1525 }
1526
1527 /****************************************************************************
1528 delete some files
1529 ****************************************************************************/
1530 static int cmd_del(struct smbclient_context *ctx, const char **args)
1531 {
1532         char *mask;
1533         uint16_t attribute = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
1534
1535         if (ctx->recurse)
1536                 attribute |= FILE_ATTRIBUTE_DIRECTORY;
1537         
1538         if (!args[1]) {
1539                 d_printf("del <filename>\n");
1540                 return 1;
1541         }
1542         mask = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[1]);
1543
1544         if (NT_STATUS_IS_ERR(smbcli_unlink(ctx->cli->tree, mask))) {
1545                 d_printf("%s deleting remote file %s\n",smbcli_errstr(ctx->cli->tree),mask);
1546         }
1547         
1548         return 0;
1549 }
1550
1551
1552 /****************************************************************************
1553 delete a whole directory tree
1554 ****************************************************************************/
1555 static int cmd_deltree(struct smbclient_context *ctx, const char **args)
1556 {
1557         char *dname;
1558         int ret;
1559
1560         if (!args[1]) {
1561                 d_printf("deltree <dirname>\n");
1562                 return 1;
1563         }
1564
1565         dname = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[1]);
1566         
1567         ret = smbcli_deltree(ctx->cli->tree, dname);
1568
1569         if (ret == -1) {
1570                 printf("Failed to delete tree %s - %s\n", dname, smbcli_errstr(ctx->cli->tree));
1571                 return -1;
1572         }
1573
1574         printf("Deleted %d files in %s\n", ret, dname);
1575         
1576         return 0;
1577 }
1578
1579 typedef struct {
1580         const char  *level_name;
1581         enum smb_fsinfo_level level;
1582 } fsinfo_level_t;
1583
1584 fsinfo_level_t fsinfo_levels[] = {
1585         {"dskattr", RAW_QFS_DSKATTR},
1586         {"allocation", RAW_QFS_ALLOCATION},
1587         {"volume", RAW_QFS_VOLUME},
1588         {"volumeinfo", RAW_QFS_VOLUME_INFO},
1589         {"sizeinfo", RAW_QFS_SIZE_INFO},
1590         {"deviceinfo", RAW_QFS_DEVICE_INFO},
1591         {"attributeinfo", RAW_QFS_ATTRIBUTE_INFO},
1592         {"unixinfo", RAW_QFS_UNIX_INFO},
1593         {"volume-information", RAW_QFS_VOLUME_INFORMATION},
1594         {"size-information", RAW_QFS_SIZE_INFORMATION},
1595         {"device-information", RAW_QFS_DEVICE_INFORMATION},
1596         {"attribute-information", RAW_QFS_ATTRIBUTE_INFORMATION},
1597         {"quota-information", RAW_QFS_QUOTA_INFORMATION},
1598         {"fullsize-information", RAW_QFS_FULL_SIZE_INFORMATION},
1599         {"objectid", RAW_QFS_OBJECTID_INFORMATION},
1600         {NULL, RAW_QFS_GENERIC}
1601 };
1602
1603
1604 static int cmd_fsinfo(struct smbclient_context *ctx, const char **args)
1605 {
1606         union smb_fsinfo fsinfo;
1607         NTSTATUS status;
1608         fsinfo_level_t *fsinfo_level;
1609         
1610         if (!args[1]) {
1611                 d_printf("fsinfo <level>, where level is one of following:\n");
1612                 fsinfo_level = fsinfo_levels;
1613                 while(fsinfo_level->level_name) {
1614                         d_printf("%s\n", fsinfo_level->level_name);
1615                         fsinfo_level++;
1616                 }
1617                 return 1;
1618         }
1619         
1620         fsinfo_level = fsinfo_levels;
1621         while(fsinfo_level->level_name && !strequal(args[1],fsinfo_level->level_name)) {
1622                 fsinfo_level++;
1623         }
1624   
1625         if (!fsinfo_level->level_name) {
1626                 d_printf("wrong level name!\n");
1627                 return 1;
1628         }
1629   
1630         fsinfo.generic.level = fsinfo_level->level;
1631         status = smb_raw_fsinfo(ctx->cli->tree, ctx, &fsinfo);
1632         if (!NT_STATUS_IS_OK(status)) {
1633                 d_printf("fsinfo-level-%s - %s\n", fsinfo_level->level_name, nt_errstr(status));
1634                 return 1;
1635         }
1636
1637         d_printf("fsinfo-level-%s:\n", fsinfo_level->level_name);
1638         switch(fsinfo.generic.level) {
1639         case RAW_QFS_DSKATTR:
1640                 d_printf("\tunits_total:                %hu\n", 
1641                          (unsigned short) fsinfo.dskattr.out.units_total);
1642                 d_printf("\tblocks_per_unit:            %hu\n", 
1643                          (unsigned short) fsinfo.dskattr.out.blocks_per_unit);
1644                 d_printf("\tblocks_size:                %hu\n", 
1645                          (unsigned short) fsinfo.dskattr.out.block_size);
1646                 d_printf("\tunits_free:                 %hu\n", 
1647                          (unsigned short) fsinfo.dskattr.out.units_free);
1648                 break;
1649         case RAW_QFS_ALLOCATION:
1650                 d_printf("\tfs_id:                      %lu\n", 
1651                          (unsigned long) fsinfo.allocation.out.fs_id);
1652                 d_printf("\tsectors_per_unit:           %lu\n", 
1653                          (unsigned long) fsinfo.allocation.out.sectors_per_unit);
1654                 d_printf("\ttotal_alloc_units:          %lu\n", 
1655                          (unsigned long) fsinfo.allocation.out.total_alloc_units);
1656                 d_printf("\tavail_alloc_units:          %lu\n", 
1657                          (unsigned long) fsinfo.allocation.out.avail_alloc_units);
1658                 d_printf("\tbytes_per_sector:           %hu\n", 
1659                          (unsigned short) fsinfo.allocation.out.bytes_per_sector);
1660                 break;
1661         case RAW_QFS_VOLUME:
1662                 d_printf("\tserial_number:              %lu\n", 
1663                          (unsigned long) fsinfo.volume.out.serial_number);
1664                 d_printf("\tvolume_name:                %s\n", fsinfo.volume.out.volume_name.s);
1665                 break;
1666         case RAW_QFS_VOLUME_INFO:
1667         case RAW_QFS_VOLUME_INFORMATION:
1668                 d_printf("\tcreate_time:                %s\n",
1669                          nt_time_string(ctx,fsinfo.volume_info.out.create_time));
1670                 d_printf("\tserial_number:              %lu\n", 
1671                          (unsigned long) fsinfo.volume_info.out.serial_number);
1672                 d_printf("\tvolume_name:                %s\n", fsinfo.volume_info.out.volume_name.s);
1673                 break;
1674         case RAW_QFS_SIZE_INFO:
1675         case RAW_QFS_SIZE_INFORMATION:
1676                 d_printf("\ttotal_alloc_units:          %llu\n", 
1677                          (unsigned long long) fsinfo.size_info.out.total_alloc_units);
1678                 d_printf("\tavail_alloc_units:          %llu\n", 
1679                          (unsigned long long) fsinfo.size_info.out.avail_alloc_units);
1680                 d_printf("\tsectors_per_unit:           %lu\n", 
1681                          (unsigned long) fsinfo.size_info.out.sectors_per_unit);
1682                 d_printf("\tbytes_per_sector:           %lu\n", 
1683                          (unsigned long) fsinfo.size_info.out.bytes_per_sector);
1684                 break;
1685         case RAW_QFS_DEVICE_INFO:
1686         case RAW_QFS_DEVICE_INFORMATION:
1687                 d_printf("\tdevice_type:                %lu\n", 
1688                          (unsigned long) fsinfo.device_info.out.device_type);
1689                 d_printf("\tcharacteristics:            0x%lx\n", 
1690                          (unsigned long) fsinfo.device_info.out.characteristics);
1691                 break;
1692         case RAW_QFS_ATTRIBUTE_INFORMATION:
1693         case RAW_QFS_ATTRIBUTE_INFO:
1694                 d_printf("\tfs_attr:                    0x%lx\n", 
1695                          (unsigned long) fsinfo.attribute_info.out.fs_attr);
1696                 d_printf("\tmax_file_component_length:  %lu\n", 
1697                          (unsigned long) fsinfo.attribute_info.out.max_file_component_length);
1698                 d_printf("\tfs_type:                    %s\n", fsinfo.attribute_info.out.fs_type.s);
1699                 break;
1700         case RAW_QFS_UNIX_INFO:
1701                 d_printf("\tmajor_version:              %hu\n", 
1702                          (unsigned short) fsinfo.unix_info.out.major_version);
1703                 d_printf("\tminor_version:              %hu\n", 
1704                          (unsigned short) fsinfo.unix_info.out.minor_version);
1705                 d_printf("\tcapability:                 0x%llx\n", 
1706                          (unsigned long long) fsinfo.unix_info.out.capability);
1707                 break;
1708         case RAW_QFS_QUOTA_INFORMATION:
1709                 d_printf("\tunknown[3]:                 [%llu,%llu,%llu]\n", 
1710                          (unsigned long long) fsinfo.quota_information.out.unknown[0],
1711                          (unsigned long long) fsinfo.quota_information.out.unknown[1],
1712                          (unsigned long long) fsinfo.quota_information.out.unknown[2]);
1713                 d_printf("\tquota_soft:                 %llu\n", 
1714                          (unsigned long long) fsinfo.quota_information.out.quota_soft);
1715                 d_printf("\tquota_hard:                 %llu\n", 
1716                          (unsigned long long) fsinfo.quota_information.out.quota_hard);
1717                 d_printf("\tquota_flags:                0x%llx\n", 
1718                          (unsigned long long) fsinfo.quota_information.out.quota_flags);
1719                 break;
1720         case RAW_QFS_FULL_SIZE_INFORMATION:
1721                 d_printf("\ttotal_alloc_units:          %llu\n", 
1722                          (unsigned long long) fsinfo.full_size_information.out.total_alloc_units);
1723                 d_printf("\tcall_avail_alloc_units:     %llu\n", 
1724                          (unsigned long long) fsinfo.full_size_information.out.call_avail_alloc_units);
1725                 d_printf("\tactual_avail_alloc_units:   %llu\n", 
1726                          (unsigned long long) fsinfo.full_size_information.out.actual_avail_alloc_units);
1727                 d_printf("\tsectors_per_unit:           %lu\n", 
1728                          (unsigned long) fsinfo.full_size_information.out.sectors_per_unit);
1729                 d_printf("\tbytes_per_sector:           %lu\n", 
1730                          (unsigned long) fsinfo.full_size_information.out.bytes_per_sector);
1731                 break;
1732         case RAW_QFS_OBJECTID_INFORMATION:
1733                 d_printf("\tGUID:                       %s\n", 
1734                          GUID_string(ctx,&fsinfo.objectid_information.out.guid));
1735                 d_printf("\tunknown[6]:                 [%llu,%llu,%llu,%llu,%llu,%llu]\n", 
1736                          (unsigned long long) fsinfo.objectid_information.out.unknown[0],
1737                          (unsigned long long) fsinfo.objectid_information.out.unknown[1],
1738                          (unsigned long long) fsinfo.objectid_information.out.unknown[2],
1739                          (unsigned long long) fsinfo.objectid_information.out.unknown[3],
1740                          (unsigned long long) fsinfo.objectid_information.out.unknown[4],
1741                          (unsigned long long) fsinfo.objectid_information.out.unknown[5] );
1742                 break;
1743         case RAW_QFS_GENERIC:
1744                 d_printf("\twrong level returned\n");
1745                 break;
1746         }
1747   
1748         return 0;
1749 }
1750
1751 /****************************************************************************
1752 show as much information as possible about a file
1753 ****************************************************************************/
1754 static int cmd_allinfo(struct smbclient_context *ctx, const char **args)
1755 {
1756         char *fname;
1757         union smb_fileinfo finfo;
1758         NTSTATUS status;
1759         int fnum;
1760
1761         if (!args[1]) {
1762                 d_printf("allinfo <filename>\n");
1763                 return 1;
1764         }
1765         fname = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[1]);
1766
1767         /* first a ALL_INFO QPATHINFO */
1768         finfo.generic.level = RAW_FILEINFO_ALL_INFO;
1769         finfo.generic.in.file.path = fname;
1770         status = smb_raw_pathinfo(ctx->cli->tree, ctx, &finfo);
1771         if (!NT_STATUS_IS_OK(status)) {
1772                 d_printf("%s - %s\n", fname, nt_errstr(status));
1773                 return 1;
1774         }
1775
1776         d_printf("\tcreate_time:    %s\n", nt_time_string(ctx, finfo.all_info.out.create_time));
1777         d_printf("\taccess_time:    %s\n", nt_time_string(ctx, finfo.all_info.out.access_time));
1778         d_printf("\twrite_time:     %s\n", nt_time_string(ctx, finfo.all_info.out.write_time));
1779         d_printf("\tchange_time:    %s\n", nt_time_string(ctx, finfo.all_info.out.change_time));
1780         d_printf("\tattrib:         0x%x\n", finfo.all_info.out.attrib);
1781         d_printf("\talloc_size:     %lu\n", (unsigned long)finfo.all_info.out.alloc_size);
1782         d_printf("\tsize:           %lu\n", (unsigned long)finfo.all_info.out.size);
1783         d_printf("\tnlink:          %u\n", finfo.all_info.out.nlink);
1784         d_printf("\tdelete_pending: %u\n", finfo.all_info.out.delete_pending);
1785         d_printf("\tdirectory:      %u\n", finfo.all_info.out.directory);
1786         d_printf("\tea_size:        %u\n", finfo.all_info.out.ea_size);
1787         d_printf("\tfname:          '%s'\n", finfo.all_info.out.fname.s);
1788
1789         /* 8.3 name if any */
1790         finfo.generic.level = RAW_FILEINFO_ALT_NAME_INFO;
1791         status = smb_raw_pathinfo(ctx->cli->tree, ctx, &finfo);
1792         if (NT_STATUS_IS_OK(status)) {
1793                 d_printf("\talt_name:       %s\n", finfo.alt_name_info.out.fname.s);
1794         }
1795
1796         /* file_id if available */
1797         finfo.generic.level = RAW_FILEINFO_INTERNAL_INFORMATION;
1798         status = smb_raw_pathinfo(ctx->cli->tree, ctx, &finfo);
1799         if (NT_STATUS_IS_OK(status)) {
1800                 d_printf("\tfile_id         %.0f\n", 
1801                          (double)finfo.internal_information.out.file_id);
1802         }
1803
1804         /* the EAs, if any */
1805         finfo.generic.level = RAW_FILEINFO_ALL_EAS;
1806         status = smb_raw_pathinfo(ctx->cli->tree, ctx, &finfo);
1807         if (NT_STATUS_IS_OK(status)) {
1808                 int i;
1809                 for (i=0;i<finfo.all_eas.out.num_eas;i++) {
1810                         d_printf("\tEA[%d] flags=%d len=%d '%s'\n", i,
1811                                  finfo.all_eas.out.eas[i].flags,
1812                                  (int)finfo.all_eas.out.eas[i].value.length,
1813                                  finfo.all_eas.out.eas[i].name.s);
1814                 }
1815         }
1816
1817         /* streams, if available */
1818         finfo.generic.level = RAW_FILEINFO_STREAM_INFO;
1819         status = smb_raw_pathinfo(ctx->cli->tree, ctx, &finfo);
1820         if (NT_STATUS_IS_OK(status)) {
1821                 int i;
1822                 for (i=0;i<finfo.stream_info.out.num_streams;i++) {
1823                         d_printf("\tstream %d:\n", i);
1824                         d_printf("\t\tsize       %ld\n", 
1825                                  (long)finfo.stream_info.out.streams[i].size);
1826                         d_printf("\t\talloc size %ld\n", 
1827                                  (long)finfo.stream_info.out.streams[i].alloc_size);
1828                         d_printf("\t\tname       %s\n", finfo.stream_info.out.streams[i].stream_name.s);
1829                 }
1830         }       
1831
1832         /* dev/inode if available */
1833         finfo.generic.level = RAW_FILEINFO_COMPRESSION_INFORMATION;
1834         status = smb_raw_pathinfo(ctx->cli->tree, ctx, &finfo);
1835         if (NT_STATUS_IS_OK(status)) {
1836                 d_printf("\tcompressed size %ld\n", (long)finfo.compression_info.out.compressed_size);
1837                 d_printf("\tformat          %ld\n", (long)finfo.compression_info.out.format);
1838                 d_printf("\tunit_shift      %ld\n", (long)finfo.compression_info.out.unit_shift);
1839                 d_printf("\tchunk_shift     %ld\n", (long)finfo.compression_info.out.chunk_shift);
1840                 d_printf("\tcluster_shift   %ld\n", (long)finfo.compression_info.out.cluster_shift);
1841         }
1842
1843         /* shadow copies if available */
1844         fnum = smbcli_open(ctx->cli->tree, fname, O_RDONLY, DENY_NONE);
1845         if (fnum != -1) {
1846                 struct smb_shadow_copy info;
1847                 int i;
1848                 info.in.file.fnum = fnum;
1849                 info.in.max_data = ~0;
1850                 status = smb_raw_shadow_data(ctx->cli->tree, ctx, &info);
1851                 if (NT_STATUS_IS_OK(status)) {
1852                         d_printf("\tshadow_copy: %u volumes  %u names\n",
1853                                  info.out.num_volumes, info.out.num_names);
1854                         for (i=0;i<info.out.num_names;i++) {
1855                                 d_printf("\t%s\n", info.out.names[i]);
1856                                 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
1857                                 finfo.generic.in.file.path = talloc_asprintf(ctx, "%s%s", 
1858                                                                              info.out.names[i], fname); 
1859                                 status = smb_raw_pathinfo(ctx->cli->tree, ctx, &finfo);
1860                                 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_NOT_FOUND) ||
1861                                     NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1862                                         continue;
1863                                 }
1864                                 if (!NT_STATUS_IS_OK(status)) {
1865                                         d_printf("%s - %s\n", finfo.generic.in.file.path, 
1866                                                  nt_errstr(status));
1867                                         return 1;
1868                                 }
1869                                 
1870                                 d_printf("\t\tcreate_time:    %s\n", nt_time_string(ctx, finfo.all_info.out.create_time));
1871                                 d_printf("\t\twrite_time:     %s\n", nt_time_string(ctx, finfo.all_info.out.write_time));
1872                                 d_printf("\t\tchange_time:    %s\n", nt_time_string(ctx, finfo.all_info.out.change_time));
1873                                 d_printf("\t\tsize:           %lu\n", (unsigned long)finfo.all_info.out.size);
1874                         }
1875                 }
1876         }
1877         
1878         return 0;
1879 }
1880
1881
1882 /****************************************************************************
1883 shows EA contents
1884 ****************************************************************************/
1885 static int cmd_eainfo(struct smbclient_context *ctx, const char **args)
1886 {
1887         char *fname;
1888         union smb_fileinfo finfo;
1889         NTSTATUS status;
1890         int i;
1891
1892         if (!args[1]) {
1893                 d_printf("eainfo <filename>\n");
1894                 return 1;
1895         }
1896         fname = talloc_strdup(ctx, args[1]);
1897
1898         finfo.generic.level = RAW_FILEINFO_ALL_EAS;
1899         finfo.generic.in.file.path = fname;
1900         status = smb_raw_pathinfo(ctx->cli->tree, ctx, &finfo);
1901         
1902         if (!NT_STATUS_IS_OK(status)) {
1903                 d_printf("RAW_FILEINFO_ALL_EAS - %s\n", nt_errstr(status));
1904                 return 1;
1905         }
1906
1907         d_printf("%s has %d EAs\n", fname, finfo.all_eas.out.num_eas);
1908
1909         for (i=0;i<finfo.all_eas.out.num_eas;i++) {
1910                 d_printf("\tEA[%d] flags=%d len=%d '%s'\n", i,
1911                          finfo.all_eas.out.eas[i].flags,
1912                          (int)finfo.all_eas.out.eas[i].value.length,
1913                          finfo.all_eas.out.eas[i].name.s);
1914                 fflush(stdout);
1915                 dump_data(0, 
1916                           finfo.all_eas.out.eas[i].value.data,
1917                           finfo.all_eas.out.eas[i].value.length);
1918         }
1919
1920         return 0;
1921 }
1922
1923
1924 /****************************************************************************
1925 show any ACL on a file
1926 ****************************************************************************/
1927 static int cmd_acl(struct smbclient_context *ctx, const char **args)
1928 {
1929         char *fname;
1930         union smb_fileinfo query;
1931         NTSTATUS status;
1932         int fnum;
1933
1934         if (!args[1]) {
1935                 d_printf("acl <filename>\n");
1936                 return 1;
1937         }
1938         fname = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[1]);
1939
1940         fnum = smbcli_nt_create_full(ctx->cli->tree, fname, 0, 
1941                                      SEC_STD_READ_CONTROL,
1942                                      0,
1943                                      NTCREATEX_SHARE_ACCESS_DELETE|
1944                                      NTCREATEX_SHARE_ACCESS_READ|
1945                                      NTCREATEX_SHARE_ACCESS_WRITE, 
1946                                      NTCREATEX_DISP_OPEN,
1947                                      0, 0);
1948         if (fnum == -1) {
1949                 d_printf("%s - %s\n", fname, smbcli_errstr(ctx->cli->tree));
1950                 return -1;
1951         }
1952
1953         query.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
1954         query.query_secdesc.in.file.fnum = fnum;
1955         query.query_secdesc.in.secinfo_flags = 0x7;
1956
1957         status = smb_raw_fileinfo(ctx->cli->tree, ctx, &query);
1958         if (!NT_STATUS_IS_OK(status)) {
1959                 d_printf("%s - %s\n", fname, nt_errstr(status));
1960                 return 1;
1961         }
1962
1963         NDR_PRINT_DEBUG(security_descriptor, query.query_secdesc.out.sd);
1964
1965         return 0;
1966 }
1967
1968 /****************************************************************************
1969 lookup a name or sid
1970 ****************************************************************************/
1971 static int cmd_lookup(struct smbclient_context *ctx, const char **args)
1972 {
1973         NTSTATUS status;
1974         struct dom_sid *sid;
1975
1976         if (!args[1]) {
1977                 d_printf("lookup <sid|name>\n");
1978                 return 1;
1979         }
1980
1981         sid = dom_sid_parse_talloc(ctx, args[1]);
1982         if (sid == NULL) {
1983                 const char *sidstr;
1984                 status = smblsa_lookup_name(ctx->cli, args[1], ctx, &sidstr);
1985                 if (!NT_STATUS_IS_OK(status)) {
1986                         d_printf("lsa_LookupNames - %s\n", nt_errstr(status));
1987                         return 1;
1988                 }
1989
1990                 d_printf("%s\n", sidstr);
1991         } else {
1992                 const char *name;
1993                 status = smblsa_lookup_sid(ctx->cli, args[1], ctx, &name);
1994                 if (!NT_STATUS_IS_OK(status)) {
1995                         d_printf("lsa_LookupSids - %s\n", nt_errstr(status));
1996                         return 1;
1997                 }
1998
1999                 d_printf("%s\n", name);
2000         }
2001
2002         return 0;
2003 }
2004
2005 /****************************************************************************
2006 show privileges for a user
2007 ****************************************************************************/
2008 static int cmd_privileges(struct smbclient_context *ctx, const char **args)
2009 {
2010         NTSTATUS status;
2011         struct dom_sid *sid;
2012         struct lsa_RightSet rights;
2013         unsigned i;
2014
2015         if (!args[1]) {
2016                 d_printf("privileges <sid|name>\n");
2017                 return 1;
2018         }
2019
2020         sid = dom_sid_parse_talloc(ctx, args[1]);
2021         if (sid == NULL) {
2022                 const char *sid_str;
2023                 status = smblsa_lookup_name(ctx->cli, args[1], ctx, &sid_str);
2024                 if (!NT_STATUS_IS_OK(status)) {
2025                         d_printf("lsa_LookupNames - %s\n", nt_errstr(status));
2026                         return 1;
2027                 }
2028                 sid = dom_sid_parse_talloc(ctx, sid_str);
2029         }
2030
2031         status = smblsa_sid_privileges(ctx->cli, sid, ctx, &rights);
2032         if (!NT_STATUS_IS_OK(status)) {
2033                 d_printf("lsa_EnumAccountRights - %s\n", nt_errstr(status));
2034                 return 1;
2035         }
2036
2037         for (i=0;i<rights.count;i++) {
2038                 d_printf("\t%s\n", rights.names[i].string);
2039         }
2040
2041         return 0;
2042 }
2043
2044
2045 /****************************************************************************
2046 add privileges for a user
2047 ****************************************************************************/
2048 static int cmd_addprivileges(struct smbclient_context *ctx, const char **args)
2049 {
2050         NTSTATUS status;
2051         struct dom_sid *sid;
2052         struct lsa_RightSet rights;
2053         int i;
2054
2055         if (!args[1]) {
2056                 d_printf("addprivileges <sid|name> <privilege...>\n");
2057                 return 1;
2058         }
2059
2060         sid = dom_sid_parse_talloc(ctx, args[1]);
2061         if (sid == NULL) {
2062                 const char *sid_str;
2063                 status = smblsa_lookup_name(ctx->cli, args[1], ctx, &sid_str);
2064                 if (!NT_STATUS_IS_OK(status)) {
2065                         d_printf("lsa_LookupNames - %s\n", nt_errstr(status));
2066                         return 1;
2067                 }
2068                 sid = dom_sid_parse_talloc(ctx, sid_str);
2069         }
2070
2071         ZERO_STRUCT(rights);
2072         for (i = 2; args[i]; i++) {
2073                 rights.names = talloc_realloc(ctx, rights.names, 
2074                                               struct lsa_StringLarge, rights.count+1);
2075                 rights.names[rights.count].string = talloc_strdup(ctx, args[i]);
2076                 rights.count++;
2077         }
2078
2079
2080         status = smblsa_sid_add_privileges(ctx->cli, sid, ctx, &rights);
2081         if (!NT_STATUS_IS_OK(status)) {
2082                 d_printf("lsa_AddAccountRights - %s\n", nt_errstr(status));
2083                 return 1;
2084         }
2085
2086         return 0;
2087 }
2088
2089 /****************************************************************************
2090 delete privileges for a user
2091 ****************************************************************************/
2092 static int cmd_delprivileges(struct smbclient_context *ctx, const char **args)
2093 {
2094         NTSTATUS status;
2095         struct dom_sid *sid;
2096         struct lsa_RightSet rights;
2097         int i;
2098
2099         if (!args[1]) {
2100                 d_printf("delprivileges <sid|name> <privilege...>\n");
2101                 return 1;
2102         }
2103
2104         sid = dom_sid_parse_talloc(ctx, args[1]);
2105         if (sid == NULL) {
2106                 const char *sid_str;
2107                 status = smblsa_lookup_name(ctx->cli, args[1], ctx, &sid_str);
2108                 if (!NT_STATUS_IS_OK(status)) {
2109                         d_printf("lsa_LookupNames - %s\n", nt_errstr(status));
2110                         return 1;
2111                 }
2112                 sid = dom_sid_parse_talloc(ctx, sid_str);
2113         }
2114
2115         ZERO_STRUCT(rights);
2116         for (i = 2; args[i]; i++) {
2117                 rights.names = talloc_realloc(ctx, rights.names, 
2118                                               struct lsa_StringLarge, rights.count+1);
2119                 rights.names[rights.count].string = talloc_strdup(ctx, args[i]);
2120                 rights.count++;
2121         }
2122
2123
2124         status = smblsa_sid_del_privileges(ctx->cli, sid, ctx, &rights);
2125         if (!NT_STATUS_IS_OK(status)) {
2126                 d_printf("lsa_RemoveAccountRights - %s\n", nt_errstr(status));
2127                 return 1;
2128         }
2129
2130         return 0;
2131 }
2132
2133
2134 /****************************************************************************
2135 ****************************************************************************/
2136 static int cmd_open(struct smbclient_context *ctx, const char **args)
2137 {
2138         char *mask;
2139         
2140         if (!args[1]) {
2141                 d_printf("open <filename>\n");
2142                 return 1;
2143         }
2144         mask = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[1]);
2145
2146         smbcli_open(ctx->cli->tree, mask, O_RDWR, DENY_ALL);
2147
2148         return 0;
2149 }
2150
2151
2152 /****************************************************************************
2153 remove a directory
2154 ****************************************************************************/
2155 static int cmd_rmdir(struct smbclient_context *ctx, const char **args)
2156 {
2157         char *mask;
2158   
2159         if (!args[1]) {
2160                 d_printf("rmdir <dirname>\n");
2161                 return 1;
2162         }
2163         mask = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[1]);
2164
2165         if (NT_STATUS_IS_ERR(smbcli_rmdir(ctx->cli->tree, mask))) {
2166                 d_printf("%s removing remote directory file %s\n",
2167                          smbcli_errstr(ctx->cli->tree),mask);
2168         }
2169         
2170         return 0;
2171 }
2172
2173 /****************************************************************************
2174  UNIX hardlink.
2175 ****************************************************************************/
2176 static int cmd_link(struct smbclient_context *ctx, const char **args)
2177 {
2178         char *src,*dest;
2179   
2180         if (!(ctx->cli->transport->negotiate.capabilities & CAP_UNIX)) {
2181                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2182                 return 1;
2183         }
2184
2185         
2186         if (!args[1] || !args[2]) {
2187                 d_printf("link <src> <dest>\n");
2188                 return 1;
2189         }
2190
2191         src = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[1]);
2192         dest = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[2]);
2193
2194         if (NT_STATUS_IS_ERR(smbcli_unix_hardlink(ctx->cli->tree, src, dest))) {
2195                 d_printf("%s linking files (%s -> %s)\n", smbcli_errstr(ctx->cli->tree), src, dest);
2196                 return 1;
2197         }  
2198
2199         return 0;
2200 }
2201
2202 /****************************************************************************
2203  UNIX symlink.
2204 ****************************************************************************/
2205
2206 static int cmd_symlink(struct smbclient_context *ctx, const char **args)
2207 {
2208         char *src,*dest;
2209   
2210         if (!(ctx->cli->transport->negotiate.capabilities & CAP_UNIX)) {
2211                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2212                 return 1;
2213         }
2214
2215         if (!args[1] || !args[2]) {
2216                 d_printf("symlink <src> <dest>\n");
2217                 return 1;
2218         }
2219
2220         src = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[1]);
2221         dest = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[2]);
2222
2223         if (NT_STATUS_IS_ERR(smbcli_unix_symlink(ctx->cli->tree, src, dest))) {
2224                 d_printf("%s symlinking files (%s -> %s)\n",
2225                         smbcli_errstr(ctx->cli->tree), src, dest);
2226                 return 1;
2227         } 
2228
2229         return 0;
2230 }
2231
2232 /****************************************************************************
2233  UNIX chmod.
2234 ****************************************************************************/
2235
2236 static int cmd_chmod(struct smbclient_context *ctx, const char **args)
2237 {
2238         char *src;
2239         mode_t mode;
2240   
2241         if (!(ctx->cli->transport->negotiate.capabilities & CAP_UNIX)) {
2242                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2243                 return 1;
2244         }
2245
2246         if (!args[1] || !args[2]) {
2247                 d_printf("chmod mode file\n");
2248                 return 1;
2249         }
2250
2251         src = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[2]);
2252         
2253         mode = (mode_t)strtol(args[1], NULL, 8);
2254
2255         if (NT_STATUS_IS_ERR(smbcli_unix_chmod(ctx->cli->tree, src, mode))) {
2256                 d_printf("%s chmod file %s 0%o\n",
2257                         smbcli_errstr(ctx->cli->tree), src, (mode_t)mode);
2258                 return 1;
2259         } 
2260
2261         return 0;
2262 }
2263
2264 /****************************************************************************
2265  UNIX chown.
2266 ****************************************************************************/
2267
2268 static int cmd_chown(struct smbclient_context *ctx, const char **args)
2269 {
2270         char *src;
2271         uid_t uid;
2272         gid_t gid;
2273   
2274         if (!(ctx->cli->transport->negotiate.capabilities & CAP_UNIX)) {
2275                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2276                 return 1;
2277         }
2278
2279         if (!args[1] || !args[2] || !args[3]) {
2280                 d_printf("chown uid gid file\n");
2281                 return 1;
2282         }
2283
2284         uid = (uid_t)atoi(args[1]);
2285         gid = (gid_t)atoi(args[2]);
2286         src = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[3]);
2287
2288         if (NT_STATUS_IS_ERR(smbcli_unix_chown(ctx->cli->tree, src, uid, gid))) {
2289                 d_printf("%s chown file %s uid=%d, gid=%d\n",
2290                         smbcli_errstr(ctx->cli->tree), src, (int)uid, (int)gid);
2291                 return 1;
2292         } 
2293
2294         return 0;
2295 }
2296
2297 /****************************************************************************
2298 rename some files
2299 ****************************************************************************/
2300 static int cmd_rename(struct smbclient_context *ctx, const char **args)
2301 {
2302         char *src,*dest;
2303   
2304         if (!args[1] || !args[2]) {
2305                 d_printf("rename <src> <dest>\n");
2306                 return 1;
2307         }
2308
2309         src = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[1]);
2310         dest = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[2]);
2311
2312         if (NT_STATUS_IS_ERR(smbcli_rename(ctx->cli->tree, src, dest))) {
2313                 d_printf("%s renaming files\n",smbcli_errstr(ctx->cli->tree));
2314                 return 1;
2315         }
2316         
2317         return 0;
2318 }
2319
2320
2321 /****************************************************************************
2322 toggle the prompt flag
2323 ****************************************************************************/
2324 static int cmd_prompt(struct smbclient_context *ctx, const char **args)
2325 {
2326         ctx->prompt = !ctx->prompt;
2327         DEBUG(2,("prompting is now %s\n",ctx->prompt?"on":"off"));
2328         
2329         return 1;
2330 }
2331
2332
2333 /****************************************************************************
2334 set the newer than time
2335 ****************************************************************************/
2336 static int cmd_newer(struct smbclient_context *ctx, const char **args)
2337 {
2338         struct stat sbuf;
2339
2340         if (args[1] && (stat(args[1],&sbuf) == 0)) {
2341                 ctx->newer_than = sbuf.st_mtime;
2342                 DEBUG(1,("Getting files newer than %s",
2343                          asctime(localtime(&ctx->newer_than))));
2344         } else {
2345                 ctx->newer_than = 0;
2346         }
2347
2348         if (args[1] && ctx->newer_than == 0) {
2349                 d_printf("Error setting newer-than time\n");
2350                 return 1;
2351         }
2352
2353         return 0;
2354 }
2355
2356 /****************************************************************************
2357 set the archive level
2358 ****************************************************************************/
2359 static int cmd_archive(struct smbclient_context *ctx, const char **args)
2360 {
2361         if (args[1]) {
2362                 ctx->archive_level = atoi(args[1]);
2363         } else
2364                 d_printf("Archive level is %d\n",ctx->archive_level);
2365
2366         return 0;
2367 }
2368
2369 /****************************************************************************
2370 toggle the lowercaseflag
2371 ****************************************************************************/
2372 static int cmd_lowercase(struct smbclient_context *ctx, const char **args)
2373 {
2374         ctx->lowercase = !ctx->lowercase;
2375         DEBUG(2,("filename lowercasing is now %s\n",ctx->lowercase?"on":"off"));
2376
2377         return 0;
2378 }
2379
2380
2381
2382
2383 /****************************************************************************
2384 toggle the recurse flag
2385 ****************************************************************************/
2386 static int cmd_recurse(struct smbclient_context *ctx, const char **args)
2387 {
2388         ctx->recurse = !ctx->recurse;
2389         DEBUG(2,("directory recursion is now %s\n",ctx->recurse?"on":"off"));
2390
2391         return 0;
2392 }
2393
2394 /****************************************************************************
2395 toggle the translate flag
2396 ****************************************************************************/
2397 static int cmd_translate(struct smbclient_context *ctx, const char **args)
2398 {
2399         ctx->translation = !ctx->translation;
2400         DEBUG(2,("CR/LF<->LF and print text translation now %s\n",
2401                  ctx->translation?"on":"off"));
2402
2403         return 0;
2404 }
2405
2406
2407 /****************************************************************************
2408 do a printmode command
2409 ****************************************************************************/
2410 static int cmd_printmode(struct smbclient_context *ctx, const char **args)
2411 {
2412         if (args[1]) {
2413                 if (strequal(args[1],"text")) {
2414                         ctx->printmode = 0;      
2415                 } else {
2416                         if (strequal(args[1],"graphics"))
2417                                 ctx->printmode = 1;
2418                         else
2419                                 ctx->printmode = atoi(args[1]);
2420                 }
2421         }
2422
2423         switch(ctx->printmode)
2424         {
2425                 case 0: 
2426                         DEBUG(2,("the printmode is now text\n"));
2427                         break;
2428                 case 1: 
2429                         DEBUG(2,("the printmode is now graphics\n"));
2430                         break;
2431                 default: 
2432                         DEBUG(2,("the printmode is now %d\n", ctx->printmode));
2433                         break;
2434         }
2435         
2436         return 0;
2437 }
2438
2439 /****************************************************************************
2440  do the lcd command
2441  ****************************************************************************/
2442 static int cmd_lcd(struct smbclient_context *ctx, const char **args)
2443 {
2444         char d[PATH_MAX];
2445         
2446         if (args[1]) 
2447                 chdir(args[1]);
2448         DEBUG(2,("the local directory is now %s\n",getcwd(d, PATH_MAX)));
2449
2450         return 0;
2451 }
2452
2453 /****************************************************************************
2454 history
2455 ****************************************************************************/
2456 static int cmd_history(struct smbclient_context *ctx, const char **args)
2457 {
2458 #if defined(HAVE_LIBREADLINE) && defined(HAVE_HISTORY_LIST)
2459         HIST_ENTRY **hlist;
2460         int i;
2461
2462         hlist = history_list();
2463         
2464         for (i = 0; hlist && hlist[i]; i++) {
2465                 DEBUG(0, ("%d: %s\n", i, hlist[i]->line));
2466         }
2467 #else
2468         DEBUG(0,("no history without readline support\n"));
2469 #endif
2470
2471         return 0;
2472 }
2473
2474 /****************************************************************************
2475  get a file restarting at end of local file
2476  ****************************************************************************/
2477 static int cmd_reget(struct smbclient_context *ctx, const char **args)
2478 {
2479         char *local_name;
2480         char *remote_name;
2481
2482         if (!args[1]) {
2483                 d_printf("reget <filename>\n");
2484                 return 1;
2485         }
2486         remote_name = talloc_asprintf(ctx, "%s\\%s", ctx->remote_cur_dir, args[1]);
2487         dos_clean_name(remote_name);
2488         
2489         if (args[2]) 
2490                 local_name = talloc_strdup(ctx, args[2]);
2491         else
2492                 local_name = talloc_strdup(ctx, args[1]);
2493         
2494         return do_get(ctx, remote_name, local_name, true);
2495 }
2496
2497 /****************************************************************************
2498  put a file restarting at end of local file
2499  ****************************************************************************/
2500 static int cmd_reput(struct smbclient_context *ctx, const char **args)
2501 {
2502         char *local_name;
2503         char *remote_name;
2504         
2505         if (!args[1]) {
2506                 d_printf("reput <filename>\n");
2507                 return 1;
2508         }
2509         local_name = talloc_asprintf(ctx, "%s\\%s", ctx->remote_cur_dir, args[1]);
2510   
2511         if (!file_exist(local_name)) {
2512                 d_printf("%s does not exist\n", local_name);
2513                 return 1;
2514         }
2515
2516         if (args[2]) 
2517                 remote_name = talloc_strdup(ctx, args[2]);
2518         else
2519                 remote_name = talloc_strdup(ctx, args[1]);
2520         
2521         dos_clean_name(remote_name);
2522
2523         return do_put(ctx, remote_name, local_name, true);
2524 }
2525
2526
2527 /*
2528   return a string representing a share type
2529 */
2530 static const char *share_type_str(uint32_t type)
2531 {
2532         switch (type & 0xF) {
2533         case STYPE_DISKTREE: 
2534                 return "Disk";
2535         case STYPE_PRINTQ: 
2536                 return "Printer";
2537         case STYPE_DEVICE: 
2538                 return "Device";
2539         case STYPE_IPC: 
2540                 return "IPC";
2541         default:
2542                 return "Unknown";
2543         }
2544 }
2545
2546
2547 /*
2548   display a list of shares from a level 1 share enum
2549 */
2550 static void display_share_result(struct srvsvc_NetShareCtr1 *ctr1)
2551 {
2552         int i;
2553
2554         for (i=0;i<ctr1->count;i++) {
2555                 struct srvsvc_NetShareInfo1 *info = ctr1->array+i;
2556
2557                 printf("\t%-15s %-10.10s %s\n", 
2558                        info->name, 
2559                        share_type_str(info->type), 
2560                        info->comment);
2561         }
2562 }
2563
2564
2565
2566 /****************************************************************************
2567 try and browse available shares on a host
2568 ****************************************************************************/
2569 static bool browse_host(struct loadparm_context *lp_ctx,
2570                         struct tevent_context *ev_ctx,
2571                         const char *query_host)
2572 {
2573         struct dcerpc_pipe *p;
2574         char *binding;
2575         NTSTATUS status;
2576         struct srvsvc_NetShareEnumAll r;
2577         struct srvsvc_NetShareInfoCtr info_ctr;
2578         uint32_t resume_handle = 0;
2579         TALLOC_CTX *mem_ctx = talloc_init("browse_host");
2580         struct srvsvc_NetShareCtr1 ctr1;
2581         uint32_t totalentries = 0;
2582
2583         binding = talloc_asprintf(mem_ctx, "ncacn_np:%s", query_host);
2584
2585         status = dcerpc_pipe_connect(mem_ctx, &p, binding, 
2586                                          &ndr_table_srvsvc,
2587                                      cmdline_credentials, ev_ctx,
2588                                      lp_ctx);
2589         if (!NT_STATUS_IS_OK(status)) {
2590                 d_printf("Failed to connect to %s - %s\n", 
2591                          binding, nt_errstr(status));
2592                 talloc_free(mem_ctx);
2593                 return false;
2594         }
2595
2596         info_ctr.level = 1;
2597         info_ctr.ctr.ctr1 = &ctr1;
2598
2599         r.in.server_unc = talloc_asprintf(mem_ctx,"\\\\%s",dcerpc_server_name(p));
2600         r.in.info_ctr = &info_ctr;
2601         r.in.max_buffer = ~0;
2602         r.in.resume_handle = &resume_handle;
2603         r.out.resume_handle = &resume_handle;
2604         r.out.totalentries = &totalentries;
2605         r.out.info_ctr = &info_ctr;
2606
2607         d_printf("\n\tSharename       Type       Comment\n");
2608         d_printf("\t---------       ----       -------\n");
2609
2610         do {
2611                 ZERO_STRUCT(ctr1);
2612                 status = dcerpc_srvsvc_NetShareEnumAll(p, mem_ctx, &r);
2613
2614                 if (NT_STATUS_IS_OK(status) && 
2615                     (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA) ||
2616                      W_ERROR_IS_OK(r.out.result)) &&
2617                     r.out.info_ctr->ctr.ctr1) {
2618                         display_share_result(r.out.info_ctr->ctr.ctr1);
2619                         resume_handle += r.out.info_ctr->ctr.ctr1->count;
2620                 }
2621         } while (NT_STATUS_IS_OK(status) && W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA));
2622
2623         talloc_free(mem_ctx);
2624
2625         if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(r.out.result)) {
2626                 d_printf("Failed NetShareEnumAll %s - %s/%s\n", 
2627                          binding, nt_errstr(status), win_errstr(r.out.result));
2628                 return false;
2629         }
2630
2631         return false;
2632 }
2633
2634 /****************************************************************************
2635 try and browse available connections on a host
2636 ****************************************************************************/
2637 static bool list_servers(const char *wk_grp)
2638 {
2639         d_printf("REWRITE: list servers not implemented\n");
2640         return false;
2641 }
2642
2643 /* Some constants for completing filename arguments */
2644
2645 #define COMPL_NONE        0          /* No completions */
2646 #define COMPL_REMOTE      1          /* Complete remote filename */
2647 #define COMPL_LOCAL       2          /* Complete local filename */
2648
2649 static int cmd_help(struct smbclient_context *ctx, const char **args);
2650
2651 /* This defines the commands supported by this client.
2652  * NOTE: The "!" must be the last one in the list because it's fn pointer
2653  *       field is NULL, and NULL in that field is used in process_tok()
2654  *       (below) to indicate the end of the list.  crh
2655  */
2656 static struct
2657 {
2658   const char *name;
2659   int (*fn)(struct smbclient_context *ctx, const char **args);
2660   const char *description;
2661   char compl_args[2];      /* Completion argument info */
2662 } commands[] = 
2663 {
2664   {"?",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
2665   {"addprivileges",cmd_addprivileges,"<sid|name> <privilege...> add privileges for a user",{COMPL_NONE,COMPL_NONE}},
2666   {"altname",cmd_altname,"<file> show alt name",{COMPL_NONE,COMPL_NONE}},
2667   {"acl",cmd_acl,"<file> show file ACL",{COMPL_NONE,COMPL_NONE}},
2668   {"allinfo",cmd_allinfo,"<file> show all possible info about a file",{COMPL_NONE,COMPL_NONE}},
2669   {"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}},
2670   {"cancel",cmd_rewrite,"<jobid> cancel a print queue entry",{COMPL_NONE,COMPL_NONE}},
2671   {"cd",cmd_cd,"[directory] change/report the remote directory",{COMPL_REMOTE,COMPL_NONE}},
2672   {"chmod",cmd_chmod,"<src> <mode> chmod a file using UNIX permission",{COMPL_REMOTE,COMPL_REMOTE}},
2673   {"chown",cmd_chown,"<src> <uid> <gid> chown a file using UNIX uids and gids",{COMPL_REMOTE,COMPL_REMOTE}},
2674   {"del",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
2675   {"delprivileges",cmd_delprivileges,"<sid|name> <privilege...> remove privileges for a user",{COMPL_NONE,COMPL_NONE}},
2676   {"deltree",cmd_deltree,"<dir> delete a whole directory tree",{COMPL_REMOTE,COMPL_NONE}},
2677   {"dir",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
2678   {"du",cmd_du,"<mask> computes the total size of the current directory",{COMPL_REMOTE,COMPL_NONE}},
2679   {"eainfo",cmd_eainfo,"<file> show EA contents for a file",{COMPL_NONE,COMPL_NONE}},
2680   {"exit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
2681   {"fsinfo",cmd_fsinfo,"query file system info",{COMPL_NONE,COMPL_NONE}},
2682   {"get",cmd_get,"<remote name> [local name] get a file",{COMPL_REMOTE,COMPL_LOCAL}},
2683   {"help",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
2684   {"history",cmd_history,"displays the command history",{COMPL_NONE,COMPL_NONE}},
2685   {"lcd",cmd_lcd,"[directory] change/report the local current working directory",{COMPL_LOCAL,COMPL_NONE}},
2686   {"link",cmd_link,"<src> <dest> create a UNIX hard link",{COMPL_REMOTE,COMPL_REMOTE}},
2687   {"lookup",cmd_lookup,"<sid|name> show SID for name or name for SID",{COMPL_NONE,COMPL_NONE}},
2688   {"lowercase",cmd_lowercase,"toggle lowercasing of filenames for get",{COMPL_NONE,COMPL_NONE}},  
2689   {"ls",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
2690   {"mask",cmd_select,"<mask> mask all filenames against this",{COMPL_REMOTE,COMPL_NONE}},
2691   {"md",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
2692   {"mget",cmd_mget,"<mask> get all the matching files",{COMPL_REMOTE,COMPL_NONE}},
2693   {"mkdir",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
2694   {"more",cmd_more,"<remote name> view a remote file with your pager",{COMPL_REMOTE,COMPL_NONE}},  
2695   {"mput",cmd_mput,"<mask> put all matching files",{COMPL_REMOTE,COMPL_NONE}},
2696   {"newer",cmd_newer,"<file> only mget files newer than the specified local file",{COMPL_LOCAL,COMPL_NONE}},
2697   {"open",cmd_open,"<mask> open a file",{COMPL_REMOTE,COMPL_NONE}},
2698   {"privileges",cmd_privileges,"<user> show privileges for a user",{COMPL_NONE,COMPL_NONE}},
2699   {"print",cmd_print,"<file name> print a file",{COMPL_NONE,COMPL_NONE}},
2700   {"printmode",cmd_printmode,"<graphics or text> set the print mode",{COMPL_NONE,COMPL_NONE}},
2701   {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput",{COMPL_NONE,COMPL_NONE}},  
2702   {"put",cmd_put,"<local name> [remote name] put a file",{COMPL_LOCAL,COMPL_REMOTE}},
2703   {"pwd",cmd_pwd,"show current remote directory (same as 'cd' with no args)",{COMPL_NONE,COMPL_NONE}},
2704   {"q",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
2705   {"queue",cmd_rewrite,"show the print queue",{COMPL_NONE,COMPL_NONE}},
2706   {"quit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
2707   {"rd",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
2708   {"recurse",cmd_recurse,"toggle directory recursion for mget and mput",{COMPL_NONE,COMPL_NONE}},  
2709   {"reget",cmd_reget,"<remote name> [local name] get a file restarting at end of local file",{COMPL_REMOTE,COMPL_LOCAL}},
2710   {"rename",cmd_rename,"<src> <dest> rename some files",{COMPL_REMOTE,COMPL_REMOTE}},
2711   {"reput",cmd_reput,"<local name> [remote name] put a file restarting at end of remote file",{COMPL_LOCAL,COMPL_REMOTE}},
2712   {"rm",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
2713   {"rmdir",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
2714   {"symlink",cmd_symlink,"<src> <dest> create a UNIX symlink",{COMPL_REMOTE,COMPL_REMOTE}},
2715   {"translate",cmd_translate,"toggle text translation for printing",{COMPL_NONE,COMPL_NONE}},
2716   
2717   /* Yes, this must be here, see crh's comment above. */
2718   {"!",NULL,"run a shell command on the local system",{COMPL_NONE,COMPL_NONE}},
2719   {NULL,NULL,NULL,{COMPL_NONE,COMPL_NONE}}
2720 };
2721
2722
2723 /*******************************************************************
2724   lookup a command string in the list of commands, including 
2725   abbreviations
2726   ******************************************************************/
2727 static int process_tok(const char *tok)
2728 {
2729         int i = 0, matches = 0;
2730         int cmd=0;
2731         int tok_len = strlen(tok);
2732         
2733         while (commands[i].fn != NULL) {
2734                 if (strequal(commands[i].name,tok)) {
2735                         matches = 1;
2736                         cmd = i;
2737                         break;
2738                 } else if (strncasecmp(commands[i].name, tok, tok_len) == 0) {
2739                         matches++;
2740                         cmd = i;
2741                 }
2742                 i++;
2743         }
2744   
2745         if (matches == 0)
2746                 return(-1);
2747         else if (matches == 1)
2748                 return(cmd);
2749         else
2750                 return(-2);
2751 }
2752
2753 /****************************************************************************
2754 help
2755 ****************************************************************************/
2756 static int cmd_help(struct smbclient_context *ctx, const char **args)
2757 {
2758         int i=0,j;
2759         
2760         if (args[1]) {
2761                 if ((i = process_tok(args[1])) >= 0)
2762                         d_printf("HELP %s:\n\t%s\n\n",commands[i].name,commands[i].description);
2763         } else {
2764                 while (commands[i].description) {
2765                         for (j=0; commands[i].description && (j<5); j++) {
2766                                 d_printf("%-15s",commands[i].name);
2767                                 i++;
2768                         }
2769                         d_printf("\n");
2770                 }
2771         }
2772         return 0;
2773 }
2774
2775 static int process_line(struct smbclient_context *ctx, const char *cline);
2776 /****************************************************************************
2777 process a -c command string
2778 ****************************************************************************/
2779 static int process_command_string(struct smbclient_context *ctx, const char *cmd)
2780 {
2781         char **lines;
2782         int i, rc = 0;
2783
2784         lines = str_list_make(NULL, cmd, ";");
2785         for (i = 0; lines[i]; i++) {
2786                 rc |= process_line(ctx, lines[i]);
2787         }
2788         talloc_free(lines);
2789
2790         return rc;
2791 }       
2792
2793 #define MAX_COMPLETIONS 100
2794
2795 typedef struct {
2796         char *dirmask;
2797         char **matches;
2798         int count, samelen;
2799         const char *text;
2800         int len;
2801 } completion_remote_t;
2802
2803 static void completion_remote_filter(struct clilist_file_info *f, const char *mask, void *state)
2804 {
2805         completion_remote_t *info = (completion_remote_t *)state;
2806
2807         if ((info->count < MAX_COMPLETIONS - 1) && (strncmp(info->text, f->name, info->len) == 0) && (!ISDOT(f->name)) && (!ISDOTDOT(f->name))) {
2808                 if ((info->dirmask[0] == 0) && !(f->attrib & FILE_ATTRIBUTE_DIRECTORY))
2809                         info->matches[info->count] = strdup(f->name);
2810                 else {
2811                         char *tmp;
2812
2813                         if (info->dirmask[0] != 0)
2814                                 tmp = talloc_asprintf(NULL, "%s/%s", info->dirmask, f->name);
2815                         else
2816                                 tmp = talloc_strdup(NULL, f->name);
2817                         
2818                         if (f->attrib & FILE_ATTRIBUTE_DIRECTORY)
2819                                 tmp = talloc_append_string(NULL, tmp, "/");
2820                         info->matches[info->count] = tmp;
2821                 }
2822                 if (info->matches[info->count] == NULL)
2823                         return;
2824                 if (f->attrib & FILE_ATTRIBUTE_DIRECTORY)
2825                         smb_readline_ca_char(0);
2826
2827                 if (info->count == 1)
2828                         info->samelen = strlen(info->matches[info->count]);
2829                 else
2830                         while (strncmp(info->matches[info->count], info->matches[info->count-1], info->samelen) != 0)
2831                                 info->samelen--;
2832                 info->count++;
2833         }
2834 }
2835
2836 static char **remote_completion(const char *text, int len)
2837 {
2838         char *dirmask;
2839         int i;
2840         completion_remote_t info;
2841
2842         info.samelen = len;
2843         info.text = text;
2844         info.len = len;
2845  
2846         if (len >= PATH_MAX)
2847                 return(NULL);
2848
2849         info.matches = malloc_array_p(char *, MAX_COMPLETIONS);
2850         if (!info.matches) return NULL;
2851         info.matches[0] = NULL;
2852
2853         for (i = len-1; i >= 0; i--)
2854                 if ((text[i] == '/') || (text[i] == '\\'))
2855                         break;
2856         info.text = text+i+1;
2857         info.samelen = info.len = len-i-1;
2858
2859         if (i > 0) {
2860                 info.dirmask = talloc_strndup(NULL, text, i+1);
2861                 info.dirmask[i+1] = 0;
2862                 asprintf(&dirmask, "%s%*s*", rl_ctx->remote_cur_dir, i-1, text);
2863         } else
2864                 asprintf(&dirmask, "%s*", rl_ctx->remote_cur_dir);
2865
2866         if (smbcli_list(rl_ctx->cli->tree, dirmask, 
2867                      FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN, 
2868                      completion_remote_filter, &info) < 0)
2869                 goto cleanup;
2870
2871         if (info.count == 2)
2872                 info.matches[0] = strdup(info.matches[1]);
2873         else {
2874                 info.matches[0] = malloc_array_p(char, info.samelen+1);
2875                 if (!info.matches[0])
2876                         goto cleanup;
2877                 strncpy(info.matches[0], info.matches[1], info.samelen);
2878                 info.matches[0][info.samelen] = 0;
2879         }
2880         info.matches[info.count] = NULL;
2881         return info.matches;
2882
2883 cleanup:
2884         for (i = 0; i < info.count; i++)
2885                 free(info.matches[i]);
2886         free(info.matches);
2887         return NULL;
2888 }
2889
2890 static char **completion_fn(const char *text, int start, int end)
2891 {
2892         smb_readline_ca_char(' ');
2893
2894         if (start) {
2895                 const char *buf, *sp;
2896                 int i;
2897                 char compl_type;
2898
2899                 buf = smb_readline_get_line_buffer();
2900                 if (buf == NULL)
2901                         return NULL;
2902                 
2903                 sp = strchr(buf, ' ');
2904                 if (sp == NULL)
2905                         return NULL;
2906                 
2907                 for (i = 0; commands[i].name; i++)
2908                         if ((strncmp(commands[i].name, text, sp - buf) == 0) && (commands[i].name[sp - buf] == 0))
2909                                 break;
2910                 if (commands[i].name == NULL)
2911                         return NULL;
2912
2913                 while (*sp == ' ')
2914                         sp++;
2915
2916                 if (sp == (buf + start))
2917                         compl_type = commands[i].compl_args[0];
2918                 else
2919                         compl_type = commands[i].compl_args[1];
2920
2921                 if (compl_type == COMPL_REMOTE)
2922                         return remote_completion(text, end - start);
2923                 else /* fall back to local filename completion */
2924                         return NULL;
2925         } else {
2926                 char **matches;
2927                 int i, len, samelen = 0, count=1;
2928
2929                 matches = malloc_array_p(char *, MAX_COMPLETIONS);
2930                 if (!matches) return NULL;
2931                 matches[0] = NULL;
2932
2933                 len = strlen(text);
2934                 for (i=0;commands[i].fn && count < MAX_COMPLETIONS-1;i++) {
2935                         if (strncmp(text, commands[i].name, len) == 0) {
2936                                 matches[count] = strdup(commands[i].name);
2937                                 if (!matches[count])
2938                                         goto cleanup;
2939                                 if (count == 1)
2940                                         samelen = strlen(matches[count]);
2941                                 else
2942                                         while (strncmp(matches[count], matches[count-1], samelen) != 0)
2943                                                 samelen--;
2944                                 count++;
2945                         }
2946                 }
2947
2948                 switch (count) {
2949                 case 0: /* should never happen */
2950                 case 1:
2951                         goto cleanup;
2952                 case 2:
2953                         matches[0] = strdup(matches[1]);
2954                         break;
2955                 default:
2956                         matches[0] = malloc_array_p(char, samelen+1);
2957                         if (!matches[0])
2958                                 goto cleanup;
2959                         strncpy(matches[0], matches[1], samelen);
2960                         matches[0][samelen] = 0;
2961                 }
2962                 matches[count] = NULL;
2963                 return matches;
2964
2965 cleanup:
2966                 count--;
2967                 while (count >= 0) {
2968                         free(matches[count]);
2969                         count--;
2970                 }
2971                 free(matches);
2972                 return NULL;
2973         }
2974 }
2975
2976 /****************************************************************************
2977 make sure we swallow keepalives during idle time
2978 ****************************************************************************/
2979 static void readline_callback(void)
2980 {
2981         static time_t last_t;
2982         time_t t;
2983
2984         t = time(NULL);
2985
2986         if (t - last_t < 5) return;
2987
2988         last_t = t;
2989
2990         smbcli_transport_process(rl_ctx->cli->transport);
2991
2992         if (rl_ctx->cli->tree) {
2993                 smbcli_chkpath(rl_ctx->cli->tree, "\\");
2994         }
2995 }
2996
2997 static int process_line(struct smbclient_context *ctx, const char *cline)
2998 {
2999         const char **args;
3000         int i;
3001
3002         /* and get the first part of the command */
3003         args = (const char **) str_list_make_shell(ctx, cline, NULL);
3004         if (!args || !args[0])
3005                 return 0;
3006
3007         if ((i = process_tok(args[0])) >= 0) {
3008                 i = commands[i].fn(ctx, args);
3009         } else if (i == -2) {
3010                 d_printf("%s: command abbreviation ambiguous\n",args[0]);
3011         } else {
3012                 d_printf("%s: command not found\n",args[0]);
3013         }
3014
3015         talloc_free(args);
3016
3017         return i;
3018 }
3019
3020 /****************************************************************************
3021 process commands on stdin
3022 ****************************************************************************/
3023 static int process_stdin(struct smbclient_context *ctx)
3024 {
3025         int rc = 0;
3026         while (1) {
3027                 /* display a prompt */
3028                 char *the_prompt = talloc_asprintf(ctx, "smb: %s> ", ctx->remote_cur_dir);
3029                 char *cline = smb_readline(the_prompt, readline_callback, completion_fn);
3030                 talloc_free(the_prompt);
3031
3032                 if (!cline) break;
3033
3034                 /* special case - first char is ! */
3035                 if (*cline == '!') {
3036                         system(cline + 1);
3037                         free(cline);
3038                         continue;
3039                 }
3040
3041                 rc |= process_command_string(ctx, cline);
3042                 free(cline);
3043
3044         }
3045
3046         return rc;
3047 }
3048
3049
3050 /***************************************************** 
3051 return a connection to a server
3052 *******************************************************/
3053 static bool do_connect(struct smbclient_context *ctx, 
3054                        struct tevent_context *ev_ctx,
3055                        struct resolve_context *resolve_ctx,
3056                        const char *specified_server, const char **ports, 
3057                        const char *specified_share, 
3058                            const char *socket_options,
3059                        struct cli_credentials *cred, 
3060                        struct smbcli_options *options,
3061                        struct smbcli_session_options *session_options,
3062                            struct smb_iconv_convenience *iconv_convenience,
3063                            struct gensec_settings *gensec_settings)
3064 {
3065         NTSTATUS status;
3066         char *server, *share;
3067
3068         rl_ctx = ctx; /* Ugly hack */
3069
3070         if (strncmp(specified_share, "\\\\", 2) == 0 ||
3071             strncmp(specified_share, "//", 2) == 0) {
3072                 smbcli_parse_unc(specified_share, ctx, &server, &share);
3073         } else {
3074                 share = talloc_strdup(ctx, specified_share);
3075                 server = talloc_strdup(ctx, specified_server);
3076         }
3077
3078         ctx->remote_cur_dir = talloc_strdup(ctx, "\\");
3079         
3080         status = smbcli_full_connection(ctx, &ctx->cli, server, ports,
3081                                         share, NULL, 
3082                                         socket_options,
3083                                         cred, resolve_ctx, 
3084                                         ev_ctx, options, session_options,
3085                                         iconv_convenience,
3086                                         gensec_settings);
3087         if (!NT_STATUS_IS_OK(status)) {
3088                 d_printf("Connection to \\\\%s\\%s failed - %s\n", 
3089                          server, share, nt_errstr(status));
3090                 talloc_free(ctx);
3091                 return NULL;
3092         }
3093
3094         return ctx;
3095 }
3096
3097 /****************************************************************************
3098 handle a -L query
3099 ****************************************************************************/
3100 static int do_host_query(struct loadparm_context *lp_ctx,
3101                          struct tevent_context *ev_ctx,
3102                          const char *query_host,
3103                          const char *workgroup)
3104 {
3105         browse_host(lp_ctx, ev_ctx, query_host);
3106         list_servers(workgroup);
3107         return(0);
3108 }
3109
3110
3111 /****************************************************************************
3112 handle a message operation
3113 ****************************************************************************/
3114 static int do_message_op(const char *netbios_name, const char *desthost,
3115                          const char **destports, const char *destip,
3116                          int name_type,
3117                          struct tevent_context *ev_ctx,
3118                          struct resolve_context *resolve_ctx,
3119                          struct smbcli_options *options,
3120                          struct smb_iconv_convenience *iconv_convenience,
3121              const char *socket_options)
3122 {
3123         struct nbt_name called, calling;
3124         const char *server_name;
3125         struct smbcli_state *cli;
3126
3127         make_nbt_name_client(&calling, netbios_name);
3128
3129         nbt_choose_called_name(NULL, &called, desthost, name_type);
3130
3131         server_name = destip ? destip : desthost;
3132
3133         if (!(cli = smbcli_state_init(NULL)) ||
3134             !smbcli_socket_connect(cli, server_name, destports,