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