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