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