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