r5917: First step in using the new cli_credentials structure. This patch
[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 struct smbcli_state *cli;
42 extern BOOL in_client;
43 static int port = 0;
44 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
1677 /****************************************************************************
1678 show as much information as possible about a file
1679 ****************************************************************************/
1680 static int cmd_allinfo(const char **cmd_ptr)
1681 {
1682         pstring fname;
1683         fstring buf;
1684         int ret = 0;
1685         TALLOC_CTX *mem_ctx;
1686         union smb_fileinfo finfo;
1687         NTSTATUS status;
1688
1689         pstrcpy(fname,cur_dir);
1690         
1691         if (!next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
1692                 d_printf("allinfo <filename>\n");
1693                 return 1;
1694         }
1695         pstrcat(fname,buf);
1696
1697         mem_ctx = talloc_init("%s", fname);
1698
1699         /* first a ALL_INFO QPATHINFO */
1700         finfo.generic.level = RAW_FILEINFO_ALL_INFO;
1701         finfo.generic.in.fname = fname;
1702         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
1703         if (!NT_STATUS_IS_OK(status)) {
1704                 d_printf("%s - %s\n", fname, nt_errstr(status));
1705                 ret = 1;
1706                 goto done;
1707         }
1708
1709         d_printf("\tcreate_time:    %s\n", nt_time_string(mem_ctx, finfo.all_info.out.create_time));
1710         d_printf("\taccess_time:    %s\n", nt_time_string(mem_ctx, finfo.all_info.out.access_time));
1711         d_printf("\twrite_time:     %s\n", nt_time_string(mem_ctx, finfo.all_info.out.write_time));
1712         d_printf("\tchange_time:    %s\n", nt_time_string(mem_ctx, finfo.all_info.out.change_time));
1713         d_printf("\tattrib:         0x%x\n", finfo.all_info.out.attrib);
1714         d_printf("\talloc_size:     %lu\n", (unsigned long)finfo.all_info.out.alloc_size);
1715         d_printf("\tsize:           %lu\n", (unsigned long)finfo.all_info.out.size);
1716         d_printf("\tnlink:          %u\n", finfo.all_info.out.nlink);
1717         d_printf("\tdelete_pending: %u\n", finfo.all_info.out.delete_pending);
1718         d_printf("\tdirectory:      %u\n", finfo.all_info.out.directory);
1719         d_printf("\tea_size:        %u\n", finfo.all_info.out.ea_size);
1720         d_printf("\tfname:          '%s'\n", finfo.all_info.out.fname.s);
1721
1722         /* 8.3 name if any */
1723         finfo.generic.level = RAW_FILEINFO_ALT_NAME_INFO;
1724         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
1725         if (NT_STATUS_IS_OK(status)) {
1726                 d_printf("\talt_name:       %s\n", finfo.alt_name_info.out.fname.s);
1727         }
1728
1729         /* file_id if available */
1730         finfo.generic.level = RAW_FILEINFO_INTERNAL_INFORMATION;
1731         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
1732         if (NT_STATUS_IS_OK(status)) {
1733                 d_printf("\tfile_id         %.0f\n", 
1734                          (double)finfo.internal_information.out.file_id);
1735         }
1736
1737         /* the EAs, if any */
1738         finfo.generic.level = RAW_FILEINFO_ALL_EAS;
1739         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
1740         if (NT_STATUS_IS_OK(status)) {
1741                 int i;
1742                 for (i=0;i<finfo.all_eas.out.num_eas;i++) {
1743                         d_printf("\tEA[%d] flags=%d len=%d '%s'\n", i,
1744                                  finfo.all_eas.out.eas[i].flags,
1745                                  finfo.all_eas.out.eas[i].value.length,
1746                                  finfo.all_eas.out.eas[i].name.s);
1747                 }
1748         }
1749
1750         /* streams, if available */
1751         finfo.generic.level = RAW_FILEINFO_STREAM_INFO;
1752         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
1753         if (NT_STATUS_IS_OK(status)) {
1754                 int i;
1755                 for (i=0;i<finfo.stream_info.out.num_streams;i++) {
1756                         d_printf("\tstream %d:\n", i);
1757                         d_printf("\t\tsize       %ld\n", 
1758                                  (long)finfo.stream_info.out.streams[i].size);
1759                         d_printf("\t\talloc size %ld\n", 
1760                                  (long)finfo.stream_info.out.streams[i].alloc_size);
1761                         d_printf("\t\tname       %s\n", finfo.stream_info.out.streams[i].stream_name.s);
1762                 }
1763         }       
1764
1765         /* dev/inode if available */
1766         finfo.generic.level = RAW_FILEINFO_COMPRESSION_INFORMATION;
1767         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
1768         if (NT_STATUS_IS_OK(status)) {
1769                 d_printf("\tcompressed size %ld\n", (long)finfo.compression_info.out.compressed_size);
1770                 d_printf("\tformat          %ld\n", (long)finfo.compression_info.out.format);
1771                 d_printf("\tunit_shift      %ld\n", (long)finfo.compression_info.out.unit_shift);
1772                 d_printf("\tchunk_shift     %ld\n", (long)finfo.compression_info.out.chunk_shift);
1773                 d_printf("\tcluster_shift   %ld\n", (long)finfo.compression_info.out.cluster_shift);
1774         }
1775
1776         talloc_free(mem_ctx);
1777
1778 done:
1779         return ret;
1780 }
1781
1782
1783 /****************************************************************************
1784 shows EA contents
1785 ****************************************************************************/
1786 static int cmd_eainfo(const char **cmd_ptr)
1787 {
1788         pstring fname;
1789         fstring buf;
1790         int ret = 0;
1791         TALLOC_CTX *mem_ctx;
1792         union smb_fileinfo finfo;
1793         NTSTATUS status;
1794         int i;
1795
1796         pstrcpy(fname,cur_dir);
1797         
1798         if (!next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
1799                 d_printf("eainfo <filename>\n");
1800                 return 1;
1801         }
1802         pstrcat(fname,buf);
1803
1804         mem_ctx = talloc_init("%s", fname);
1805
1806         finfo.generic.in.fname = fname;
1807         finfo.generic.level = RAW_FILEINFO_ALL_EAS;
1808         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
1809         
1810         if (!NT_STATUS_IS_OK(status)) {
1811                 d_printf("RAW_FILEINFO_ALL_EAS - %s\n", nt_errstr(status));
1812                 talloc_free(mem_ctx);
1813                 return 1;
1814         }
1815
1816         d_printf("%s has %d EAs\n", fname, finfo.all_eas.out.num_eas);
1817
1818         for (i=0;i<finfo.all_eas.out.num_eas;i++) {
1819                 d_printf("\tEA[%d] flags=%d len=%d '%s'\n", i,
1820                          finfo.all_eas.out.eas[i].flags,
1821                          finfo.all_eas.out.eas[i].value.length,
1822                          finfo.all_eas.out.eas[i].name.s);
1823                 fflush(stdout);
1824                 dump_data(0, 
1825                           finfo.all_eas.out.eas[i].value.data,
1826                           finfo.all_eas.out.eas[i].value.length);
1827         }
1828
1829         talloc_free(mem_ctx);
1830
1831         return ret;
1832 }
1833
1834
1835 /****************************************************************************
1836 show any ACL on a file
1837 ****************************************************************************/
1838 static int cmd_acl(const char **cmd_ptr)
1839 {
1840         pstring fname;
1841         fstring buf;
1842         int ret = 0;
1843         TALLOC_CTX *mem_ctx;
1844         union smb_fileinfo query;
1845         NTSTATUS status;
1846         int fnum;
1847
1848         pstrcpy(fname,cur_dir);
1849         
1850         if (!next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
1851                 d_printf("acl <filename>\n");
1852                 return 1;
1853         }
1854         pstrcat(fname,buf);
1855
1856         fnum = smbcli_nt_create_full(cli->tree, fname, 0, 
1857                                      SEC_STD_READ_CONTROL,
1858                                      0,
1859                                      NTCREATEX_SHARE_ACCESS_DELETE|
1860                                      NTCREATEX_SHARE_ACCESS_READ|
1861                                      NTCREATEX_SHARE_ACCESS_WRITE, 
1862                                      NTCREATEX_DISP_OPEN,
1863                                      0, 0);
1864         if (fnum == -1) {
1865                 d_printf("%s - %s\n", fname, smbcli_errstr(cli->tree));
1866                 return -1;
1867         }
1868
1869         mem_ctx = talloc_init("%s", fname);
1870
1871         query.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
1872         query.query_secdesc.in.fnum = fnum;
1873         query.query_secdesc.in.secinfo_flags = 0x7;
1874
1875         status = smb_raw_fileinfo(cli->tree, mem_ctx, &query);
1876         if (!NT_STATUS_IS_OK(status)) {
1877                 d_printf("%s - %s\n", fname, nt_errstr(status));
1878                 ret = 1;
1879                 goto done;
1880         }
1881
1882         NDR_PRINT_DEBUG(security_descriptor, query.query_secdesc.out.sd);
1883
1884         talloc_free(mem_ctx);
1885
1886 done:
1887         return ret;
1888 }
1889
1890 /****************************************************************************
1891 lookup a name or sid
1892 ****************************************************************************/
1893 static int cmd_lookup(const char **cmd_ptr)
1894 {
1895         fstring buf;
1896         TALLOC_CTX *mem_ctx = talloc_new(NULL);
1897         NTSTATUS status;
1898         struct dom_sid *sid;
1899
1900         if (!next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
1901                 d_printf("lookup <sid|name>\n");
1902                 talloc_free(mem_ctx);
1903                 return 1;
1904         }
1905
1906         sid = dom_sid_parse_talloc(mem_ctx, buf);
1907         if (sid == NULL) {
1908                 const char *sidstr;
1909                 status = smblsa_lookup_name(cli, buf, mem_ctx, &sidstr);
1910                 if (!NT_STATUS_IS_OK(status)) {
1911                         d_printf("lsa_LookupNames - %s\n", nt_errstr(status));
1912                         talloc_free(mem_ctx);
1913                         return 1;
1914                 }
1915
1916                 d_printf("%s\n", sidstr);
1917         } else {
1918                 const char *name;
1919                 status = smblsa_lookup_sid(cli, buf, mem_ctx, &name);
1920                 if (!NT_STATUS_IS_OK(status)) {
1921                         d_printf("lsa_LookupSids - %s\n", nt_errstr(status));
1922                         talloc_free(mem_ctx);
1923                         return 1;
1924                 }
1925
1926                 d_printf("%s\n", name);
1927         }
1928
1929         talloc_free(mem_ctx);
1930
1931         return 0;
1932 }
1933
1934 /****************************************************************************
1935 show privileges for a user
1936 ****************************************************************************/
1937 static int cmd_privileges(const char **cmd_ptr)
1938 {
1939         fstring buf;
1940         TALLOC_CTX *mem_ctx = talloc_new(NULL);
1941         NTSTATUS status;
1942         struct dom_sid *sid;
1943         struct lsa_RightSet rights;
1944         unsigned i;
1945
1946         if (!next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
1947                 d_printf("privileges <sid|name>\n");
1948                 talloc_free(mem_ctx);
1949                 return 1;
1950         }
1951
1952         sid = dom_sid_parse_talloc(mem_ctx, buf);
1953         if (sid == NULL) {
1954                 const char *sid_str;
1955                 status = smblsa_lookup_name(cli, buf, mem_ctx, &sid_str);
1956                 if (!NT_STATUS_IS_OK(status)) {
1957                         d_printf("lsa_LookupNames - %s\n", nt_errstr(status));
1958                         talloc_free(mem_ctx);
1959                         return 1;
1960                 }
1961                 sid = dom_sid_parse_talloc(mem_ctx, sid_str);
1962         }
1963
1964         status = smblsa_sid_privileges(cli, sid, mem_ctx, &rights);
1965         if (!NT_STATUS_IS_OK(status)) {
1966                 d_printf("lsa_EnumAccountRights - %s\n", nt_errstr(status));
1967                 talloc_free(mem_ctx);
1968                 return 1;
1969         }
1970
1971         for (i=0;i<rights.count;i++) {
1972                 d_printf("\t%s\n", rights.names[i].string);
1973         }
1974
1975         talloc_free(mem_ctx);
1976
1977         return 0;
1978 }
1979
1980
1981 /****************************************************************************
1982 add privileges for a user
1983 ****************************************************************************/
1984 static int cmd_addprivileges(const char **cmd_ptr)
1985 {
1986         fstring buf;
1987         TALLOC_CTX *mem_ctx = talloc_new(NULL);
1988         NTSTATUS status;
1989         struct dom_sid *sid;
1990         struct lsa_RightSet rights;
1991
1992         if (!next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
1993                 d_printf("addprivileges <sid|name> <privilege...>\n");
1994                 talloc_free(mem_ctx);
1995                 return 1;
1996         }
1997
1998         sid = dom_sid_parse_talloc(mem_ctx, buf);
1999         if (sid == NULL) {
2000                 const char *sid_str;
2001                 status = smblsa_lookup_name(cli, buf, mem_ctx, &sid_str);
2002                 if (!NT_STATUS_IS_OK(status)) {
2003                         d_printf("lsa_LookupNames - %s\n", nt_errstr(status));
2004                         talloc_free(mem_ctx);
2005                         return 1;
2006                 }
2007                 sid = dom_sid_parse_talloc(mem_ctx, sid_str);
2008         }
2009
2010         ZERO_STRUCT(rights);
2011         while (next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
2012                 rights.names = talloc_realloc(mem_ctx, rights.names, 
2013                                                 struct lsa_String, rights.count+1);
2014                 rights.names[rights.count].string = talloc_strdup(mem_ctx, buf);
2015                 rights.count++;
2016         }
2017
2018
2019         status = smblsa_sid_add_privileges(cli, sid, mem_ctx, &rights);
2020         if (!NT_STATUS_IS_OK(status)) {
2021                 d_printf("lsa_AddAccountRights - %s\n", nt_errstr(status));
2022                 talloc_free(mem_ctx);
2023                 return 1;
2024         }
2025
2026         talloc_free(mem_ctx);
2027
2028         return 0;
2029 }
2030
2031 /****************************************************************************
2032 delete privileges for a user
2033 ****************************************************************************/
2034 static int cmd_delprivileges(const char **cmd_ptr)
2035 {
2036         fstring buf;
2037         TALLOC_CTX *mem_ctx = talloc_new(NULL);
2038         NTSTATUS status;
2039         struct dom_sid *sid;
2040         struct lsa_RightSet rights;
2041
2042         if (!next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
2043                 d_printf("delprivileges <sid|name> <privilege...>\n");
2044                 talloc_free(mem_ctx);
2045                 return 1;
2046         }
2047
2048         sid = dom_sid_parse_talloc(mem_ctx, buf);
2049         if (sid == NULL) {
2050                 const char *sid_str;
2051                 status = smblsa_lookup_name(cli, buf, mem_ctx, &sid_str);
2052                 if (!NT_STATUS_IS_OK(status)) {
2053                         d_printf("lsa_LookupNames - %s\n", nt_errstr(status));
2054                         talloc_free(mem_ctx);
2055                         return 1;
2056                 }
2057                 sid = dom_sid_parse_talloc(mem_ctx, sid_str);
2058         }
2059
2060         ZERO_STRUCT(rights);
2061         while (next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
2062                 rights.names = talloc_realloc(mem_ctx, rights.names, 
2063                                                 struct lsa_String, rights.count+1);
2064                 rights.names[rights.count].string = talloc_strdup(mem_ctx, buf);
2065                 rights.count++;
2066         }
2067
2068
2069         status = smblsa_sid_del_privileges(cli, sid, mem_ctx, &rights);
2070         if (!NT_STATUS_IS_OK(status)) {
2071                 d_printf("lsa_RemoveAccountRights - %s\n", nt_errstr(status));
2072                 talloc_free(mem_ctx);
2073                 return 1;
2074         }
2075
2076         talloc_free(mem_ctx);
2077
2078         return 0;
2079 }
2080
2081
2082 /****************************************************************************
2083 ****************************************************************************/
2084 static int cmd_open(const char **cmd_ptr)
2085 {
2086         pstring mask;
2087         fstring buf;
2088         
2089         pstrcpy(mask,cur_dir);
2090         
2091         if (!next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
2092                 d_printf("open <filename>\n");
2093                 return 1;
2094         }
2095         pstrcat(mask,buf);
2096
2097         smbcli_open(cli->tree, mask, O_RDWR, DENY_ALL);
2098
2099         return 0;
2100 }
2101
2102
2103 /****************************************************************************
2104 remove a directory
2105 ****************************************************************************/
2106 static int cmd_rmdir(const char **cmd_ptr)
2107 {
2108         pstring mask;
2109         fstring buf;
2110   
2111         pstrcpy(mask,cur_dir);
2112         
2113         if (!next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
2114                 d_printf("rmdir <dirname>\n");
2115                 return 1;
2116         }
2117         pstrcat(mask,buf);
2118
2119         if (NT_STATUS_IS_ERR(smbcli_rmdir(cli->tree, mask))) {
2120                 d_printf("%s removing remote directory file %s\n",
2121                          smbcli_errstr(cli->tree),mask);
2122         }
2123         
2124         return 0;
2125 }
2126
2127 /****************************************************************************
2128  UNIX hardlink.
2129 ****************************************************************************/
2130 static int cmd_link(const char **cmd_ptr)
2131 {
2132         pstring src,dest;
2133         fstring buf,buf2;
2134   
2135         if (!(cli->transport->negotiate.capabilities & CAP_UNIX)) {
2136                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2137                 return 1;
2138         }
2139
2140         pstrcpy(src,cur_dir);
2141         pstrcpy(dest,cur_dir);
2142   
2143         if (!next_token(cmd_ptr,buf,NULL,sizeof(buf)) || 
2144             !next_token(cmd_ptr,buf2,NULL, sizeof(buf2))) {
2145                 d_printf("link <src> <dest>\n");
2146                 return 1;
2147         }
2148
2149         pstrcat(src,buf);
2150         pstrcat(dest,buf2);
2151
2152         if (NT_STATUS_IS_ERR(smbcli_unix_hardlink(cli->tree, src, dest))) {
2153                 d_printf("%s linking files (%s -> %s)\n", smbcli_errstr(cli->tree), src, dest);
2154                 return 1;
2155         }  
2156
2157         return 0;
2158 }
2159
2160 /****************************************************************************
2161  UNIX symlink.
2162 ****************************************************************************/
2163
2164 static int cmd_symlink(const char **cmd_ptr)
2165 {
2166         pstring src,dest;
2167         fstring buf,buf2;
2168   
2169         if (!(cli->transport->negotiate.capabilities & CAP_UNIX)) {
2170                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2171                 return 1;
2172         }
2173
2174         pstrcpy(src,cur_dir);
2175         pstrcpy(dest,cur_dir);
2176         
2177         if (!next_token(cmd_ptr,buf,NULL,sizeof(buf)) || 
2178             !next_token(cmd_ptr,buf2,NULL, sizeof(buf2))) {
2179                 d_printf("symlink <src> <dest>\n");
2180                 return 1;
2181         }
2182
2183         pstrcat(src,buf);
2184         pstrcat(dest,buf2);
2185
2186         if (NT_STATUS_IS_ERR(smbcli_unix_symlink(cli->tree, src, dest))) {
2187                 d_printf("%s symlinking files (%s -> %s)\n",
2188                         smbcli_errstr(cli->tree), src, dest);
2189                 return 1;
2190         } 
2191
2192         return 0;
2193 }
2194
2195 /****************************************************************************
2196  UNIX chmod.
2197 ****************************************************************************/
2198
2199 static int cmd_chmod(const char **cmd_ptr)
2200 {
2201         pstring src;
2202         mode_t mode;
2203         fstring buf, buf2;
2204   
2205         if (!(cli->transport->negotiate.capabilities & CAP_UNIX)) {
2206                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2207                 return 1;
2208         }
2209
2210         pstrcpy(src,cur_dir);
2211         
2212         if (!next_token(cmd_ptr,buf,NULL,sizeof(buf)) || 
2213             !next_token(cmd_ptr,buf2,NULL, sizeof(buf2))) {
2214                 d_printf("chmod mode file\n");
2215                 return 1;
2216         }
2217
2218         mode = (mode_t)strtol(buf, NULL, 8);
2219         pstrcat(src,buf2);
2220
2221         if (NT_STATUS_IS_ERR(smbcli_unix_chmod(cli->tree, src, mode))) {
2222                 d_printf("%s chmod file %s 0%o\n",
2223                         smbcli_errstr(cli->tree), src, (uint_t)mode);
2224                 return 1;
2225         } 
2226
2227         return 0;
2228 }
2229
2230 /****************************************************************************
2231  UNIX chown.
2232 ****************************************************************************/
2233
2234 static int cmd_chown(const char **cmd_ptr)
2235 {
2236         pstring src;
2237         uid_t uid;
2238         gid_t gid;
2239         fstring buf, buf2, buf3;
2240   
2241         if (!(cli->transport->negotiate.capabilities & CAP_UNIX)) {
2242                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2243                 return 1;
2244         }
2245
2246         pstrcpy(src,cur_dir);
2247         
2248         if (!next_token(cmd_ptr,buf,NULL,sizeof(buf)) || 
2249             !next_token(cmd_ptr,buf2,NULL, sizeof(buf2)) ||
2250             !next_token(cmd_ptr,buf3,NULL, sizeof(buf3))) {
2251                 d_printf("chown uid gid file\n");
2252                 return 1;
2253         }
2254
2255         uid = (uid_t)atoi(buf);
2256         gid = (gid_t)atoi(buf2);
2257         pstrcat(src,buf3);
2258
2259         if (NT_STATUS_IS_ERR(smbcli_unix_chown(cli->tree, src, uid, gid))) {
2260                 d_printf("%s chown file %s uid=%d, gid=%d\n",
2261                         smbcli_errstr(cli->tree), src, (int)uid, (int)gid);
2262                 return 1;
2263         } 
2264
2265         return 0;
2266 }
2267
2268 /****************************************************************************
2269 rename some files
2270 ****************************************************************************/
2271 static int cmd_rename(const char **cmd_ptr)
2272 {
2273         pstring src,dest;
2274         fstring buf,buf2;
2275   
2276         pstrcpy(src,cur_dir);
2277         pstrcpy(dest,cur_dir);
2278         
2279         if (!next_token(cmd_ptr,buf,NULL,sizeof(buf)) || 
2280             !next_token(cmd_ptr,buf2,NULL, sizeof(buf2))) {
2281                 d_printf("rename <src> <dest>\n");
2282                 return 1;
2283         }
2284
2285         pstrcat(src,buf);
2286         pstrcat(dest,buf2);
2287
2288         if (NT_STATUS_IS_ERR(smbcli_rename(cli->tree, src, dest))) {
2289                 d_printf("%s renaming files\n",smbcli_errstr(cli->tree));
2290                 return 1;
2291         }
2292         
2293         return 0;
2294 }
2295
2296
2297 /****************************************************************************
2298 toggle the prompt flag
2299 ****************************************************************************/
2300 static int cmd_prompt(const char **cmd_ptr)
2301 {
2302         prompt = !prompt;
2303         DEBUG(2,("prompting is now %s\n",prompt?"on":"off"));
2304         
2305         return 1;
2306 }
2307
2308
2309 /****************************************************************************
2310 set the newer than time
2311 ****************************************************************************/
2312 static int cmd_newer(const char **cmd_ptr)
2313 {
2314         fstring buf;
2315         BOOL ok;
2316         struct stat sbuf;
2317
2318         ok = next_token(cmd_ptr,buf,NULL,sizeof(buf));
2319         if (ok && (stat(buf,&sbuf) == 0)) {
2320                 newer_than = sbuf.st_mtime;
2321                 DEBUG(1,("Getting files newer than %s",
2322                          asctime(localtime(&newer_than))));
2323         } else {
2324                 newer_than = 0;
2325         }
2326
2327         if (ok && newer_than == 0) {
2328                 d_printf("Error setting newer-than time\n");
2329                 return 1;
2330         }
2331
2332         return 0;
2333 }
2334
2335 /****************************************************************************
2336 set the archive level
2337 ****************************************************************************/
2338 static int cmd_archive(const char **cmd_ptr)
2339 {
2340         fstring buf;
2341
2342         if (next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
2343                 archive_level = atoi(buf);
2344         } else
2345                 d_printf("Archive level is %d\n",archive_level);
2346
2347         return 0;
2348 }
2349
2350 /****************************************************************************
2351 toggle the lowercaseflag
2352 ****************************************************************************/
2353 static int cmd_lowercase(const char **cmd_ptr)
2354 {
2355         lowercase = !lowercase;
2356         DEBUG(2,("filename lowercasing is now %s\n",lowercase?"on":"off"));
2357
2358         return 0;
2359 }
2360
2361
2362
2363
2364 /****************************************************************************
2365 toggle the recurse flag
2366 ****************************************************************************/
2367 static int cmd_recurse(const char **cmd_ptr)
2368 {
2369         recurse = !recurse;
2370         DEBUG(2,("directory recursion is now %s\n",recurse?"on":"off"));
2371
2372         return 0;
2373 }
2374
2375 /****************************************************************************
2376 toggle the translate flag
2377 ****************************************************************************/
2378 static int cmd_translate(const char **cmd_ptr)
2379 {
2380         translation = !translation;
2381         DEBUG(2,("CR/LF<->LF and print text translation now %s\n",
2382                  translation?"on":"off"));
2383
2384         return 0;
2385 }
2386
2387
2388 /****************************************************************************
2389 do a printmode command
2390 ****************************************************************************/
2391 static int cmd_printmode(const char **cmd_ptr)
2392 {
2393         fstring buf;
2394         fstring mode;
2395
2396         if (next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
2397                 if (strequal(buf,"text")) {
2398                         printmode = 0;      
2399                 } else {
2400                         if (strequal(buf,"graphics"))
2401                                 printmode = 1;
2402                         else
2403                                 printmode = atoi(buf);
2404                 }
2405         }
2406
2407         switch(printmode)
2408                 {
2409                 case 0: 
2410                         fstrcpy(mode,"text");
2411                         break;
2412                 case 1: 
2413                         fstrcpy(mode,"graphics");
2414                         break;
2415                 default: 
2416                         slprintf(mode,sizeof(mode)-1,"%d",printmode);
2417                         break;
2418                 }
2419         
2420         DEBUG(2,("the printmode is now %s\n",mode));
2421
2422         return 0;
2423 }
2424
2425 /****************************************************************************
2426  do the lcd command
2427  ****************************************************************************/
2428 static int cmd_lcd(const char **cmd_ptr)
2429 {
2430         fstring buf;
2431         pstring d;
2432         
2433         if (next_token(cmd_ptr,buf,NULL,sizeof(buf)))
2434                 chdir(buf);
2435         DEBUG(2,("the local directory is now %s\n",sys_getwd(d)));
2436
2437         return 0;
2438 }
2439
2440 /****************************************************************************
2441  get a file restarting at end of local file
2442  ****************************************************************************/
2443 static int cmd_reget(const char **cmd_ptr)
2444 {
2445         pstring local_name;
2446         pstring remote_name;
2447         char *p;
2448
2449         pstrcpy(remote_name, cur_dir);
2450         pstrcat(remote_name, "\\");
2451         
2452         p = remote_name + strlen(remote_name);
2453         
2454         if (!next_token(cmd_ptr, p, NULL, sizeof(remote_name) - strlen(remote_name))) {
2455                 d_printf("reget <filename>\n");
2456                 return 1;
2457         }
2458         pstrcpy(local_name, p);
2459         dos_clean_name(remote_name);
2460         
2461         next_token(cmd_ptr, local_name, NULL, sizeof(local_name));
2462         
2463         return do_get(remote_name, local_name, True);
2464 }
2465
2466 /****************************************************************************
2467  put a file restarting at end of local file
2468  ****************************************************************************/
2469 static int cmd_reput(const char **cmd_ptr)
2470 {
2471         pstring local_name;
2472         pstring remote_name;
2473         fstring buf;
2474         char *p = buf;
2475         
2476         pstrcpy(remote_name, cur_dir);
2477         pstrcat(remote_name, "\\");
2478   
2479         if (!next_token(cmd_ptr, p, NULL, sizeof(buf))) {
2480                 d_printf("reput <filename>\n");
2481                 return 1;
2482         }
2483         pstrcpy(local_name, p);
2484   
2485         if (!file_exist(local_name)) {
2486                 d_printf("%s does not exist\n", local_name);
2487                 return 1;
2488         }
2489
2490         if (next_token(cmd_ptr, p, NULL, sizeof(buf)))
2491                 pstrcat(remote_name, p);
2492         else
2493                 pstrcat(remote_name, local_name);
2494         
2495         dos_clean_name(remote_name);
2496
2497         return do_put(remote_name, local_name, True);
2498 }
2499
2500
2501 /*
2502   return a string representing a share type
2503 */
2504 static const char *share_type_str(uint32_t type)
2505 {
2506         switch (type & 0xF) {
2507         case STYPE_DISKTREE: 
2508                 return "Disk";
2509         case STYPE_PRINTQ: 
2510                 return "Printer";
2511         case STYPE_DEVICE: 
2512                 return "Device";
2513         case STYPE_IPC: 
2514                 return "IPC";
2515         default:
2516                 return "Unknown";
2517         }
2518 }
2519
2520
2521 /*
2522   display a list of shares from a level 1 share enum
2523 */
2524 static void display_share_result(struct srvsvc_NetShareCtr1 *ctr1)
2525 {
2526         int i;
2527
2528         for (i=0;i<ctr1->count;i++) {
2529                 struct srvsvc_NetShareInfo1 *info = ctr1->array+i;
2530
2531                 printf("\t%-15s %-10.10s %s\n", 
2532                        info->name, 
2533                        share_type_str(info->type), 
2534                        info->comment);
2535         }
2536 }
2537
2538
2539
2540 /****************************************************************************
2541 try and browse available shares on a host
2542 ****************************************************************************/
2543 static BOOL browse_host(const char *query_host)
2544 {
2545         struct dcerpc_pipe *p;
2546         char *binding;
2547         NTSTATUS status;
2548         struct srvsvc_NetShareEnumAll r;
2549         uint32_t resume_handle = 0;
2550         TALLOC_CTX *mem_ctx = talloc_init("browse_host");
2551         struct srvsvc_NetShareCtr1 ctr1;
2552
2553         binding = talloc_asprintf(mem_ctx, "ncacn_np:%s", query_host);
2554
2555         status = dcerpc_pipe_connect(&p, binding, 
2556                                      DCERPC_SRVSVC_UUID, 
2557                                      DCERPC_SRVSVC_VERSION,
2558                                      lp_netbios_name(),
2559                                      cli_credentials_get_domain(cmdline_credentials), 
2560                                      cli_credentials_get_username(cmdline_credentials), 
2561                                          cli_credentials_get_password(cmdline_credentials));
2562         if (!NT_STATUS_IS_OK(status)) {
2563                 d_printf("Failed to connect to %s - %s\n", 
2564                          binding, nt_errstr(status));
2565                 talloc_free(mem_ctx);
2566                 return False;
2567         }
2568         talloc_steal(mem_ctx, p);
2569
2570         r.in.server_unc = talloc_asprintf(mem_ctx,"\\\\%s",dcerpc_server_name(p));
2571         r.in.level = 1;
2572         r.in.ctr.ctr1 = &ctr1;
2573         r.in.max_buffer = ~0;
2574         r.in.resume_handle = &resume_handle;
2575
2576         d_printf("\n\tSharename       Type       Comment\n");
2577         d_printf("\t---------       ----       -------\n");
2578
2579         do {
2580                 ZERO_STRUCT(ctr1);
2581                 status = dcerpc_srvsvc_NetShareEnumAll(p, mem_ctx, &r);
2582
2583                 if (NT_STATUS_IS_OK(status) && 
2584                     (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA) ||
2585                      W_ERROR_IS_OK(r.out.result)) &&
2586                     r.out.ctr.ctr1) {
2587                         display_share_result(r.out.ctr.ctr1);
2588                         resume_handle += r.out.ctr.ctr1->count;
2589                 }
2590         } while (NT_STATUS_IS_OK(status) && W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA));
2591
2592         talloc_free(mem_ctx);
2593
2594         if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(r.out.result)) {
2595                 d_printf("Failed NetShareEnumAll %s - %s/%s\n", 
2596                          binding, nt_errstr(status), win_errstr(r.out.result));
2597                 return False;
2598         }
2599
2600         return False;
2601 }
2602
2603 /****************************************************************************
2604 try and browse available connections on a host
2605 ****************************************************************************/
2606 static BOOL list_servers(const char *wk_grp)
2607 {
2608         d_printf("REWRITE: list servers not implemented\n");
2609         return False;
2610 }
2611
2612 /* Some constants for completing filename arguments */
2613
2614 #define COMPL_NONE        0          /* No completions */
2615 #define COMPL_REMOTE      1          /* Complete remote filename */
2616 #define COMPL_LOCAL       2          /* Complete local filename */
2617
2618 /* This defines the commands supported by this client.
2619  * NOTE: The "!" must be the last one in the list because it's fn pointer
2620  *       field is NULL, and NULL in that field is used in process_tok()
2621  *       (below) to indicate the end of the list.  crh
2622  */
2623 static struct
2624 {
2625   const char *name;
2626   int (*fn)(const char **cmd_ptr);
2627   const char *description;
2628   char compl_args[2];      /* Completion argument info */
2629 } commands[] = 
2630 {
2631   {"?",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
2632   {"addprivileges",cmd_addprivileges,"<sid|name> <privilege...> add privileges for a user",{COMPL_NONE,COMPL_NONE}},
2633   {"altname",cmd_altname,"<file> show alt name",{COMPL_NONE,COMPL_NONE}},
2634   {"acl",cmd_acl,"<file> show file ACL",{COMPL_NONE,COMPL_NONE}},
2635   {"allinfo",cmd_allinfo,"<file> show all possible info about a file",{COMPL_NONE,COMPL_NONE}},
2636   {"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}},
2637   {"cancel",cmd_cancel,"<jobid> cancel a print queue entry",{COMPL_NONE,COMPL_NONE}},
2638   {"cd",cmd_cd,"[directory] change/report the remote directory",{COMPL_REMOTE,COMPL_NONE}},
2639   {"chmod",cmd_chmod,"<src> <mode> chmod a file using UNIX permission",{COMPL_REMOTE,COMPL_REMOTE}},
2640   {"chown",cmd_chown,"<src> <uid> <gid> chown a file using UNIX uids and gids",{COMPL_REMOTE,COMPL_REMOTE}},
2641   {"del",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
2642   {"delprivileges",cmd_delprivileges,"<sid|name> <privilege...> remove privileges for a user",{COMPL_NONE,COMPL_NONE}},
2643   {"deltree",cmd_deltree,"<dir> delete a whole directory tree",{COMPL_REMOTE,COMPL_NONE}},
2644   {"dir",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
2645   {"du",cmd_du,"<mask> computes the total size of the current directory",{COMPL_REMOTE,COMPL_NONE}},
2646   {"eainfo",cmd_eainfo,"<file> show EA contents for a file",{COMPL_NONE,COMPL_NONE}},
2647   {"exit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
2648   {"get",cmd_get,"<remote name> [local name] get a file",{COMPL_REMOTE,COMPL_LOCAL}},
2649   {"help",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
2650   {"history",cmd_history,"displays the command history",{COMPL_NONE,COMPL_NONE}},
2651   {"lcd",cmd_lcd,"[directory] change/report the local current working directory",{COMPL_LOCAL,COMPL_NONE}},
2652   {"link",cmd_link,"<src> <dest> create a UNIX hard link",{COMPL_REMOTE,COMPL_REMOTE}},
2653   {"lookup",cmd_lookup,"<sid|name> show SID for name or name for SID",{COMPL_NONE,COMPL_NONE}},
2654   {"lowercase",cmd_lowercase,"toggle lowercasing of filenames for get",{COMPL_NONE,COMPL_NONE}},  
2655   {"ls",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
2656   {"mask",cmd_select,"<mask> mask all filenames against this",{COMPL_REMOTE,COMPL_NONE}},
2657   {"md",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
2658   {"mget",cmd_mget,"<mask> get all the matching files",{COMPL_REMOTE,COMPL_NONE}},
2659   {"mkdir",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
2660   {"more",cmd_more,"<remote name> view a remote file with your pager",{COMPL_REMOTE,COMPL_NONE}},  
2661   {"mput",cmd_mput,"<mask> put all matching files",{COMPL_REMOTE,COMPL_NONE}},
2662   {"newer",cmd_newer,"<file> only mget files newer than the specified local file",{COMPL_LOCAL,COMPL_NONE}},
2663   {"open",cmd_open,"<mask> open a file",{COMPL_REMOTE,COMPL_NONE}},
2664   {"privileges",cmd_privileges,"<user> show privileges for a user",{COMPL_NONE,COMPL_NONE}},
2665   {"print",cmd_print,"<file name> print a file",{COMPL_NONE,COMPL_NONE}},
2666   {"printmode",cmd_printmode,"<graphics or text> set the print mode",{COMPL_NONE,COMPL_NONE}},
2667   {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput",{COMPL_NONE,COMPL_NONE}},  
2668   {"put",cmd_put,"<local name> [remote name] put a file",{COMPL_LOCAL,COMPL_REMOTE}},
2669   {"pwd",cmd_pwd,"show current remote directory (same as 'cd' with no args)",{COMPL_NONE,COMPL_NONE}},
2670   {"q",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
2671   {"queue",cmd_queue,"show the print queue",{COMPL_NONE,COMPL_NONE}},
2672   {"quit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
2673   {"rd",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
2674   {"recurse",cmd_recurse,"toggle directory recursion for mget and mput",{COMPL_NONE,COMPL_NONE}},  
2675   {"reget",cmd_reget,"<remote name> [local name] get a file restarting at end of local file",{COMPL_REMOTE,COMPL_LOCAL}},
2676   {"rename",cmd_rename,"<src> <dest> rename some files",{COMPL_REMOTE,COMPL_REMOTE}},
2677   {"reput",cmd_reput,"<local name> [remote name] put a file restarting at end of remote file",{COMPL_LOCAL,COMPL_REMOTE}},
2678   {"rm",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
2679   {"rmdir",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
2680   {"symlink",cmd_symlink,"<src> <dest> create a UNIX symlink",{COMPL_REMOTE,COMPL_REMOTE}},
2681   {"translate",cmd_translate,"toggle text translation for printing",{COMPL_NONE,COMPL_NONE}},
2682   
2683   /* Yes, this must be here, see crh's comment above. */
2684   {"!",NULL,"run a shell command on the local system",{COMPL_NONE,COMPL_NONE}},
2685   {NULL,NULL,NULL,{COMPL_NONE,COMPL_NONE}}
2686 };
2687
2688
2689 /*******************************************************************
2690   lookup a command string in the list of commands, including 
2691   abbreviations
2692   ******************************************************************/
2693 static int process_tok(fstring tok)
2694 {
2695         int i = 0, matches = 0;
2696         int cmd=0;
2697         int tok_len = strlen(tok);
2698         
2699         while (commands[i].fn != NULL) {
2700                 if (strequal(commands[i].name,tok)) {
2701                         matches = 1;
2702                         cmd = i;
2703                         break;
2704                 } else if (strncasecmp(commands[i].name, tok, tok_len) == 0) {
2705                         matches++;
2706                         cmd = i;
2707                 }
2708                 i++;
2709         }
2710   
2711         if (matches == 0)
2712                 return(-1);
2713         else if (matches == 1)
2714                 return(cmd);
2715         else
2716                 return(-2);
2717 }
2718
2719 /****************************************************************************
2720 help
2721 ****************************************************************************/
2722 static int cmd_help(const char **cmd_ptr)
2723 {
2724         int i=0,j;
2725         fstring buf;
2726         
2727         if (next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
2728                 if ((i = process_tok(buf)) >= 0)
2729                         d_printf("HELP %s:\n\t%s\n\n",commands[i].name,commands[i].description);
2730         } else {
2731                 while (commands[i].description) {
2732                         for (j=0; commands[i].description && (j<5); j++) {
2733                                 d_printf("%-15s",commands[i].name);
2734                                 i++;
2735                         }
2736                         d_printf("\n");
2737                 }
2738         }
2739         return 0;
2740 }
2741
2742 /****************************************************************************
2743 process a -c command string
2744 ****************************************************************************/
2745 static int process_command_string(char *cmd)
2746 {
2747         pstring line;
2748         const char *ptr;
2749         int rc = 0;
2750
2751         /* establish the connection if not already */
2752         
2753         if (!cli) {
2754                 cli = do_connect(desthost, service, cmdline_credentials);
2755                 if (!cli)
2756                         return 0;
2757         }
2758         
2759         while (cmd[0] != '\0')    {
2760                 char *p;
2761                 fstring tok;
2762                 int i;
2763                 
2764                 if ((p = strchr_m(cmd, ';')) == 0) {
2765                         strncpy(line, cmd, 999);
2766                         line[1000] = '\0';
2767                         cmd += strlen(cmd);
2768                 } else {
2769                         if (p - cmd > 999) p = cmd + 999;
2770                         strncpy(line, cmd, p - cmd);
2771                         line[p - cmd] = '\0';
2772                         cmd = p + 1;
2773                 }
2774                 
2775                 /* and get the first part of the command */
2776                 ptr = line;
2777                 if (!next_token(&ptr,tok,NULL,sizeof(tok))) continue;
2778                 
2779                 if ((i = process_tok(tok)) >= 0) {
2780                         rc = commands[i].fn(&ptr);
2781                 } else if (i == -2) {
2782                         d_printf("%s: command abbreviation ambiguous\n",tok);
2783                 } else {
2784                         d_printf("%s: command not found\n",tok);
2785                 }
2786         }
2787         
2788         return rc;
2789 }       
2790
2791 #define MAX_COMPLETIONS 100
2792
2793 typedef struct {
2794         pstring dirmask;
2795         char **matches;
2796         int count, samelen;
2797         const char *text;
2798         int len;
2799 } completion_remote_t;
2800
2801 static void completion_remote_filter(struct clilist_file_info *f, const char *mask, void *state)
2802 {
2803         completion_remote_t *info = (completion_remote_t *)state;
2804
2805         if ((info->count < MAX_COMPLETIONS - 1) && (strncmp(info->text, f->name, info->len) == 0) && (strcmp(f->name, ".") != 0) && (strcmp(f->name, "..") != 0)) {
2806                 if ((info->dirmask[0] == 0) && !(f->attrib & FILE_ATTRIBUTE_DIRECTORY))
2807                         info->matches[info->count] = strdup(f->name);
2808                 else {
2809                         pstring tmp;
2810
2811                         if (info->dirmask[0] != 0)
2812                                 pstrcpy(tmp, info->dirmask);
2813                         else
2814                                 tmp[0] = 0;
2815                         pstrcat(tmp, f->name);
2816                         if (f->attrib & FILE_ATTRIBUTE_DIRECTORY)
2817                                 pstrcat(tmp, "/");
2818                         info->matches[info->count] = strdup(tmp);
2819                 }
2820                 if (info->matches[info->count] == NULL)
2821                         return;
2822                 if (f->attrib & FILE_ATTRIBUTE_DIRECTORY)
2823                         smb_readline_ca_char(0);
2824
2825                 if (info->count == 1)
2826                         info->samelen = strlen(info->matches[info->count]);
2827                 else
2828                         while (strncmp(info->matches[info->count], info->matches[info->count-1], info->samelen) != 0)
2829                                 info->samelen--;
2830                 info->count++;
2831         }
2832 }
2833
2834 static char **remote_completion(const char *text, int len)
2835 {
2836         pstring dirmask;
2837         int i;
2838         completion_remote_t info = { "", NULL, 1, 0, NULL, 0 };
2839
2840         info.samelen = len;
2841         info.text = text;
2842         info.len = len;
2843  
2844         if (len >= PATH_MAX)
2845                 return(NULL);
2846
2847         info.matches = malloc_array_p(char *, MAX_COMPLETIONS);
2848         if (!info.matches) return NULL;
2849         info.matches[0] = NULL;
2850
2851         for (i = len-1; i >= 0; i--)
2852                 if ((text[i] == '/') || (text[i] == '\\'))
2853                         break;
2854         info.text = text+i+1;
2855         info.samelen = info.len = len-i-1;
2856
2857         if (i > 0) {
2858                 strncpy(info.dirmask, text, i+1);
2859                 info.dirmask[i+1] = 0;
2860                 snprintf(dirmask, sizeof(dirmask), "%s%*s*", cur_dir, i-1, text);
2861         } else
2862                 snprintf(dirmask, sizeof(dirmask), "%s*", cur_dir);
2863
2864         if (smbcli_list(cli->tree, dirmask, 
2865                      FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN, 
2866                      completion_remote_filter, &info) < 0)
2867                 goto cleanup;
2868
2869         if (info.count == 2)
2870                 info.matches[0] = strdup(info.matches[1]);
2871         else {
2872                 info.matches[0] = malloc(info.samelen+1);
2873                 if (!info.matches[0])
2874                         goto cleanup;
2875                 strncpy(info.matches[0], info.matches[1], info.samelen);
2876                 info.matches[0][info.samelen] = 0;
2877         }
2878         info.matches[info.count] = NULL;
2879         return info.matches;
2880
2881 cleanup:
2882         for (i = 0; i < info.count; i++)
2883                 free(info.matches[i]);
2884         free(info.matches);
2885         return NULL;
2886 }
2887
2888 static char **completion_fn(const char *text, int start, int end)
2889 {
2890         smb_readline_ca_char(' ');
2891
2892         if (start) {
2893                 const char *buf, *sp;
2894                 int i;
2895                 char compl_type;
2896
2897                 buf = smb_readline_get_line_buffer();
2898                 if (buf == NULL)
2899                         return NULL;
2900                 
2901                 sp = strchr(buf, ' ');
2902                 if (sp == NULL)
2903                         return NULL;
2904                 
2905                 for (i = 0; commands[i].name; i++)
2906                         if ((strncmp(commands[i].name, text, sp - buf) == 0) && (commands[i].name[sp - buf] == 0))
2907                                 break;
2908                 if (commands[i].name == NULL)
2909                         return NULL;
2910
2911                 while (*sp == ' ')
2912                         sp++;
2913
2914                 if (sp == (buf + start))
2915                         compl_type = commands[i].compl_args[0];
2916                 else
2917                         compl_type = commands[i].compl_args[1];
2918
2919                 if (compl_type == COMPL_REMOTE)
2920                         return remote_completion(text, end - start);
2921                 else /* fall back to local filename completion */
2922                         return NULL;
2923         } else {
2924                 char **matches;
2925                 int i, len, samelen = 0, count=1;
2926
2927                 matches = malloc_array_p(char *, MAX_COMPLETIONS);
2928                 if (!matches) return NULL;
2929                 matches[0] = NULL;
2930
2931                 len = strlen(text);
2932                 for (i=0;commands[i].fn && count < MAX_COMPLETIONS-1;i++) {
2933                         if (strncmp(text, commands[i].name, len) == 0) {
2934                                 matches[count] = strdup(commands[i].name);
2935                                 if (!matches[count])
2936                                         goto cleanup;
2937                                 if (count == 1)
2938                                         samelen = strlen(matches[count]);
2939                                 else
2940                                         while (strncmp(matches[count], matches[count-1], samelen) != 0)
2941                                                 samelen--;
2942                                 count++;
2943                         }
2944                 }
2945
2946                 switch (count) {
2947                 case 0: /* should never happen */
2948                 case 1:
2949                         goto cleanup;
2950                 case 2:
2951                         matches[0] = strdup(matches[1]);
2952                         break;
2953                 default:
2954                         matches[0] = malloc(samelen+1);
2955                         if (!matches[0])
2956                                 goto cleanup;
2957                         strncpy(matches[0], matches[1], samelen);
2958                         matches[0][samelen] = 0;
2959                 }
2960                 matches[count] = NULL;
2961                 return matches;
2962
2963 cleanup:
2964                 while (i >= 0) {
2965                         free(matches[i]);
2966                         i--;
2967                 }
2968                 free(matches);
2969                 return NULL;
2970         }
2971 }
2972
2973 /****************************************************************************
2974 make sure we swallow keepalives during idle time
2975 ****************************************************************************/
2976 static void readline_callback(void)
2977 {
2978         static time_t last_t;
2979         time_t t;
2980
2981         t = time(NULL);
2982
2983         if (t - last_t < 5) return;
2984
2985         last_t = t;
2986
2987         smbcli_transport_process(cli->transport);
2988
2989         if (cli->tree) {
2990                 smbcli_chkpath(cli->tree, "\\");
2991         }
2992 }
2993
2994
2995 /****************************************************************************
2996 process commands on stdin
2997 ****************************************************************************/
2998 static void process_stdin(void)
2999 {
3000         while (1) {
3001                 fstring tok;
3002                 fstring the_prompt;
3003                 char *cline;
3004                 pstring line;
3005                 const char *ptr;
3006                 int i;
3007                 
3008                 /* display a prompt */
3009                 slprintf(the_prompt, sizeof(the_prompt)-1, "smb: %s> ", cur_dir);
3010                 cline = smb_readline(the_prompt, readline_callback, completion_fn);
3011                         
3012                 if (!cline) break;
3013                 
3014                 pstrcpy(line, cline);
3015
3016                 /* special case - first char is ! */
3017                 if (*line == '!') {
3018                         system(line + 1);
3019                         continue;
3020                 }
3021       
3022                 /* and get the first part of the command */
3023                 ptr = line;
3024                 if (!next_token(&ptr,tok,NULL,sizeof(tok))) continue;
3025
3026                 if ((i = process_tok(tok)) >= 0) {
3027                         commands[i].fn(&ptr);
3028                 } else if (i == -2) {
3029                         d_printf("%s: command abbreviation ambiguous\n",tok);
3030                 } else {
3031                         d_printf("%s: command not found\n",tok);
3032                 }
3033         }
3034 }
3035
3036
3037 /***************************************************** 
3038 return a connection to a server
3039 *******************************************************/
3040 static struct smbcli_state *do_connect(const char *server, const char *share, struct cli_credentials *cred)
3041 {
3042         struct smbcli_state *c;
3043         NTSTATUS status;
3044
3045         if (strncmp(share, "\\\\", 2) == 0 ||
3046             strncmp(share, "//", 2) == 0) {
3047                 smbcli_parse_unc(share, NULL, &server, &share);
3048         }
3049         
3050         status = smbcli_full_connection(NULL, &c, lp_netbios_name(), server,
3051                                         share, NULL, cli_credentials_get_username(cred), 
3052                                                                  cli_credentials_get_domain(cred), 
3053                                                                  cli_credentials_get_password(cred));
3054         if (!NT_STATUS_IS_OK(status)) {
3055                 d_printf("Connection to \\\\%s\\%s failed - %s\n", 
3056                          server, share, nt_errstr(status));
3057                 return NULL;
3058         }
3059
3060         return c;
3061 }
3062
3063
3064 /****************************************************************************
3065   process commands from the client
3066 ****************************************************************************/
3067 static int process(char *base_directory)
3068 {
3069         int rc = 0;
3070
3071         cli = do_connect(desthost, service, cmdline_credentials);
3072         if (!cli) {
3073                 return 1;
3074         }
3075
3076         if (*base_directory) do_cd(base_directory);
3077         
3078         if (cmdstr) {
3079                 rc = process_command_string(cmdstr);
3080         } else {
3081                 process_stdin();
3082         }
3083   
3084         smbcli_shutdown(cli);
3085         return rc;
3086 }
3087
3088 /****************************************************************************
3089 handle a -L query
3090 ****************************************************************************/
3091 static int do_host_query(char *query_host)
3092 {
3093         browse_host(query_host);
3094         list_servers(lp_workgroup());
3095         return(0);
3096 }
3097
3098
3099 /****************************************************************************
3100 handle a message operation
3101 ****************************************************************************/
3102 static int do_message_op(void)
3103 {
3104         struct nbt_name called, calling;
3105         const char *server_name;
3106
3107         calling.name = lp_netbios_name();
3108         calling.type = NBT_NAME_CLIENT;
3109         calling.scope = NULL;
3110
3111         nbt_choose_called_name(NULL, &called, desthost, name_type);
3112
3113         server_name = dest_ip ? dest_ip : desthost;
3114
3115         if (!(cli=smbcli_state_init(NULL)) || !smbcli_socket_connect(cli, server_name)) {
3116                 d_printf("Connection to %s failed\n", server_name);
3117                 return 1;
3118         }
3119
3120         if (!smbcli_transport_establish(cli, &calling, &called)) {
3121                 d_printf("session request failed\n");
3122                 smbcli_shutdown(cli);
3123                 return 1;
3124         }
3125
3126         send_message();
3127         smbcli_shutdown(cli);
3128
3129         return 0;
3130 }
3131
3132
3133 /**
3134  * Process "-L hostname" option.
3135  *
3136  * We don't actually do anything yet -- we just stash the name in a
3137  * global variable and do the query when all options have been read.
3138  **/
3139 static void remember_query_host(const char *arg,
3140                                 pstring query_host)
3141 {
3142         char *slash;
3143         
3144         while (*arg == '\\' || *arg == '/')
3145                 arg++;
3146         pstrcpy(query_host, arg);
3147         if ((slash = strchr(query_host, '/'))
3148             || (slash = strchr(query_host, '\\'))) {
3149                 *slash = 0;
3150         }
3151 }
3152
3153
3154 /****************************************************************************
3155   main program
3156 ****************************************************************************/
3157  int main(int argc,char *argv[])
3158 {
3159         fstring base_directory;
3160         int opt;
3161         pstring query_host;
3162         BOOL message = False;
3163         pstring term_code;
3164         poptContext pc;
3165         char *p;
3166         int rc = 0;
3167         TALLOC_CTX *mem_ctx;
3168         struct poptOption long_options[] = {
3169                 POPT_AUTOHELP
3170
3171                 { "message", 'M', POPT_ARG_STRING, NULL, 'M', "Send message", "HOST" },
3172                 { "ip-address", 'I', POPT_ARG_STRING, NULL, 'I', "Use this IP to connect to", "IP" },
3173                 { "stderr", 'E', POPT_ARG_NONE, NULL, 'E', "Write messages to stderr instead of stdout" },
3174                 { "list", 'L', POPT_ARG_STRING, NULL, 'L', "Get a list of shares available on a host", "HOST" },
3175                 { "terminal", 't', POPT_ARG_STRING, NULL, 't', "Terminal I/O code {sjis|euc|jis7|jis8|junet|hex}", "CODE" },
3176                 { "directory", 'D', POPT_ARG_STRING, NULL, 'D', "Start from directory", "DIR" },
3177                 { "command", 'c', POPT_ARG_STRING, &cmdstr, 'c', "Execute semicolon separated commands" }, 
3178                 { "send-buffer", 'b', POPT_ARG_INT, NULL, 'b', "Changes the transmit/send buffer", "BYTES" },
3179                 { "port", 'p', POPT_ARG_INT, &port, 'p', "Port to connect to", "PORT" },
3180                 POPT_COMMON_SAMBA
3181                 POPT_COMMON_CONNECTION
3182                 POPT_COMMON_CREDENTIALS
3183                 POPT_COMMON_VERSION
3184                 POPT_TABLEEND
3185         };
3186         
3187 #ifdef KANJI
3188         pstrcpy(term_code, KANJI);
3189 #else /* KANJI */