5f8181fde0464b7c0db4e2fecca6c80dc2ba9561
[tprouty/samba.git] / source / 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
7    Copyright (C) Gerald (Jerry) Carter    2004
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25 #include "client/client_proto.h"
26 #include "include/rpc_client.h"
27 #ifndef REGISTER
28 #define REGISTER 0
29 #endif
30
31 extern BOOL AllowDebugChange;
32 extern BOOL override_logfile;
33 extern char tar_type;
34 extern BOOL in_client;
35 static int port = 0;
36 pstring cur_dir = "\\";
37 static pstring cd_path = "";
38 static pstring service;
39 static pstring desthost;
40 static pstring username;
41 static pstring calling_name;
42 static BOOL grepable=False;
43 static char *cmdstr = NULL;
44
45 static int io_bufsize = 64512;
46
47 static int name_type = 0x20;
48 extern int max_protocol;
49
50 static int process_tok(pstring tok);
51 static int cmd_help(void);
52
53 static TALLOC_CTX *ctx;
54 #define CREATE_ACCESS_READ READ_CONTROL_ACCESS
55 static pstring cwd;
56
57 /* 30 second timeout on most commands */
58 #define CLIENT_TIMEOUT (30*1000)
59 #define SHORT_TIMEOUT (5*1000)
60
61 /* value for unused fid field in trans2 secondary request */
62 #define FID_UNUSED (0xFFFF)
63
64 time_t newer_than = 0;
65 static int archive_level = 0;
66
67 static BOOL translation = False;
68 static BOOL have_ip;
69
70 /* clitar bits insert */
71 extern int blocksize;
72 extern BOOL tar_inc;
73 extern BOOL tar_reset;
74 /* clitar bits end */
75  
76
77 static BOOL prompt = True;
78
79 static BOOL recurse = False;
80 static BOOL showacls = False;
81 BOOL lowercase = False;
82
83 static struct in_addr dest_ip;
84
85 #define SEPARATORS " \t\n\r"
86
87 static BOOL abort_mget = True;
88
89 static pstring fileselection = "";
90
91 extern file_info def_finfo;
92
93 /* timing globals */
94 SMB_BIG_UINT get_total_size = 0;
95 unsigned int get_total_time_ms = 0;
96 static SMB_BIG_UINT put_total_size = 0;
97 static unsigned int put_total_time_ms = 0;
98
99 /* totals globals */
100 static double dir_total;
101
102 /* root cli_state connection */
103
104 struct cli_state *cli;
105
106 static char CLI_DIRSEP_CHAR = '\\';
107 static char CLI_DIRSEP_STR[] = { '\\', '\0' };
108
109 /****************************************************************************
110  Write to a local file with CR/LF->LF translation if appropriate. Return the 
111  number taken from the buffer. This may not equal the number written.
112 ****************************************************************************/
113
114 static int writefile(int f, char *b, int n)
115 {
116         int i;
117
118         if (!translation) {
119                 return write(f,b,n);
120         }
121
122         i = 0;
123         while (i < n) {
124                 if (*b == '\r' && (i<(n-1)) && *(b+1) == '\n') {
125                         b++;i++;
126                 }
127                 if (write(f, b, 1) != 1) {
128                         break;
129                 }
130                 b++;
131                 i++;
132         }
133   
134         return(i);
135 }
136
137 /****************************************************************************
138  Read from a file with LF->CR/LF translation if appropriate. Return the 
139  number read. read approx n bytes.
140 ****************************************************************************/
141
142 static int readfile(char *b, int n, XFILE *f)
143 {
144         int i;
145         int c;
146
147         if (!translation)
148                 return x_fread(b,1,n,f);
149   
150         i = 0;
151         while (i < (n - 1) && (i < BUFFER_SIZE)) {
152                 if ((c = x_getc(f)) == EOF) {
153                         break;
154                 }
155       
156                 if (c == '\n') { /* change all LFs to CR/LF */
157                         b[i++] = '\r';
158                 }
159       
160                 b[i++] = c;
161         }
162   
163         return(i);
164 }
165  
166 /****************************************************************************
167  Send a message.
168 ****************************************************************************/
169
170 static void send_message(void)
171 {
172         int total_len = 0;
173         int grp_id;
174
175         if (!cli_message_start(cli, desthost, username, &grp_id)) {
176                 d_printf("message start: %s\n", cli_errstr(cli));
177                 return;
178         }
179
180
181         d_printf("Connected. Type your message, ending it with a Control-D\n");
182
183         while (!feof(stdin) && total_len < 1600) {
184                 int maxlen = MIN(1600 - total_len,127);
185                 pstring msg;
186                 int l=0;
187                 int c;
188
189                 ZERO_ARRAY(msg);
190
191                 for (l=0;l<maxlen && (c=fgetc(stdin))!=EOF;l++) {
192                         if (c == '\n')
193                                 msg[l++] = '\r';
194                         msg[l] = c;   
195                 }
196
197                 if (!cli_message_text(cli, msg, l, grp_id)) {
198                         d_printf("SMBsendtxt failed (%s)\n",cli_errstr(cli));
199                         return;
200                 }      
201                 
202                 total_len += l;
203         }
204
205         if (total_len >= 1600)
206                 d_printf("the message was truncated to 1600 bytes\n");
207         else
208                 d_printf("sent %d bytes\n",total_len);
209
210         if (!cli_message_end(cli, grp_id)) {
211                 d_printf("SMBsendend failed (%s)\n",cli_errstr(cli));
212                 return;
213         }      
214 }
215
216 /****************************************************************************
217  Check the space on a device.
218 ****************************************************************************/
219
220 static int do_dskattr(void)
221 {
222         int total, bsize, avail;
223         struct cli_state *targetcli;
224         pstring targetpath;
225
226         if ( !cli_resolve_path( "", cli, cur_dir, &targetcli, targetpath ) ) {
227                 d_printf("Error in dskattr: %s\n", cli_errstr(cli));
228                 return 1;
229         }
230
231         if (!cli_dskattr(targetcli, &bsize, &total, &avail)) {
232                 d_printf("Error in dskattr: %s\n",cli_errstr(targetcli)); 
233                 return 1;
234         }
235
236         d_printf("\n\t\t%d blocks of size %d. %d blocks available\n",
237                  total, bsize, avail);
238
239         return 0;
240 }
241
242 /****************************************************************************
243  Show cd/pwd.
244 ****************************************************************************/
245
246 static int cmd_pwd(void)
247 {
248         d_printf("Current directory is %s",service);
249         d_printf("%s\n",cur_dir);
250         return 0;
251 }
252
253 /****************************************************************************
254  Change directory - inner section.
255 ****************************************************************************/
256
257 static int do_cd(char *newdir)
258 {
259         char *p = newdir;
260         pstring saved_dir;
261         pstring dname;
262         pstring targetpath;
263         struct cli_state *targetcli;
264         SMB_STRUCT_STAT sbuf;
265         uint32 attributes;
266         int ret = 1;
267       
268         dos_format(newdir);
269
270         /* Save the current directory in case the new directory is invalid */
271
272         pstrcpy(saved_dir, cur_dir);
273
274         if (*p == CLI_DIRSEP_CHAR) {
275                 pstrcpy(cur_dir,p);
276         } else {
277                 pstrcat(cur_dir,p);
278                 if ((cur_dir[0] != '\0') && (*(cur_dir+strlen(cur_dir)-1) != CLI_DIRSEP_CHAR)) {
279                         pstrcat(cur_dir, CLI_DIRSEP_STR);
280                 }
281         }
282         
283         clean_name(cur_dir);
284         pstrcpy( dname, cur_dir );
285         
286         if ( !cli_resolve_path( "", cli, dname, &targetcli, targetpath ) ) {
287                 d_printf("cd %s: %s\n", dname, cli_errstr(cli));
288                 pstrcpy(cur_dir,saved_dir);
289                 goto out;
290         }
291
292         if (strequal(targetpath,CLI_DIRSEP_STR )) {
293                 return 0;
294         }
295                 
296         /* Use a trans2_qpathinfo to test directories for modern servers.
297            Except Win9x doesn't support the qpathinfo_basic() call..... */ 
298         
299         if ( targetcli->protocol >  PROTOCOL_LANMAN2 && !targetcli->win95 ) {
300                 if ( !cli_qpathinfo_basic( targetcli, targetpath, &sbuf, &attributes ) ) {
301                         d_printf("cd %s: %s\n", dname, cli_errstr(targetcli));
302                         pstrcpy(cur_dir,saved_dir);
303                         goto out;
304                 }
305                 
306                 if ( !(attributes&FILE_ATTRIBUTE_DIRECTORY) ) {
307                         d_printf("cd %s: not a directory\n", dname);
308                         pstrcpy(cur_dir,saved_dir);
309                         goto out;
310                 }               
311         } else {
312                 pstrcat( targetpath, CLI_DIRSEP_STR );
313                 clean_name( targetpath );
314                 
315                 if ( !cli_chkpath(targetcli, targetpath) ) {
316                         d_printf("cd %s: %s\n", dname, cli_errstr(targetcli));
317                         pstrcpy(cur_dir,saved_dir);
318                         goto out;
319                 }
320         }
321
322         ret = 0;
323
324 out:
325         
326         pstrcpy(cd_path,cur_dir);
327         return ret;
328 }
329
330 /****************************************************************************
331  Change directory.
332 ****************************************************************************/
333
334 static int cmd_cd(void)
335 {
336         pstring buf;
337         int rc = 0;
338                 
339         if (next_token_nr(NULL,buf,NULL,sizeof(buf)))
340                 rc = do_cd(buf);
341         else
342                 d_printf("Current directory is %s\n",cur_dir);
343
344         return rc;
345 }
346
347 /*******************************************************************
348  Decide if a file should be operated on.
349 ********************************************************************/
350
351 static BOOL do_this_one(file_info *finfo)
352 {
353         if (finfo->mode & aDIR)
354                 return(True);
355
356         if (*fileselection && 
357             !mask_match(finfo->name,fileselection,False)) {
358                 DEBUG(3,("mask_match %s failed\n", finfo->name));
359                 return False;
360         }
361
362         if (newer_than && finfo->mtime_ts.tv_sec < newer_than) {
363                 DEBUG(3,("newer_than %s failed\n", finfo->name));
364                 return(False);
365         }
366
367         if ((archive_level==1 || archive_level==2) && !(finfo->mode & aARCH)) {
368                 DEBUG(3,("archive %s failed\n", finfo->name));
369                 return(False);
370         }
371         
372         return(True);
373 }
374
375 /****************************************************************************
376  Display info about a file.
377 ****************************************************************************/
378
379 static void display_finfo(file_info *finfo)
380 {
381         if (do_this_one(finfo)) {
382                 time_t t = finfo->mtime_ts.tv_sec; /* the time is assumed to be passed as GMT */
383                 if (!showacls) {
384                         d_printf("  %-30s%7.7s %8.0f  %s",
385                                  finfo->name,
386                                  attrib_string(finfo->mode),
387                                 (double)finfo->size,
388                                 time_to_asc(t));
389                         dir_total += finfo->size;
390                 } else {
391                         pstring afname;
392                         int fnum;
393
394                         /* skip if this is . or .. */
395                         if ( strequal(finfo->name,"..") || strequal(finfo->name,".") )
396                                 return;
397                         /* create absolute filename for cli_nt_create() FIXME */
398                         pstrcpy( afname, cwd);
399                         pstrcat( afname, CLI_DIRSEP_STR);
400                         pstrcat( afname, finfo->name);
401                         /* print file meta date header */
402                         d_printf( "FILENAME:%s\n", afname);
403                         d_printf( "MODE:%s\n", attrib_string(finfo->mode));
404                         d_printf( "SIZE:%.0f\n", (double)finfo->size);
405                         d_printf( "MTIME:%s", time_to_asc(t));
406                         fnum = cli_nt_create(finfo->cli, afname, CREATE_ACCESS_READ);
407                         if (fnum == -1) {
408                                 DEBUG( 0, ("display_finfo() Failed to open %s: %s\n",
409                                         afname,
410                                         cli_errstr( finfo->cli)));
411                         } else {
412                                 SEC_DESC *sd = NULL;
413                                 sd = cli_query_secdesc(finfo->cli, fnum, ctx);
414                                 if (!sd) {
415                                         DEBUG( 0, ("display_finfo() failed to "
416                                                 "get security descriptor: %s",
417                                                 cli_errstr( finfo->cli)));
418                                 } else {
419                                         display_sec_desc(sd);
420                                 }
421                         }
422                 }
423         }
424 }
425
426 /****************************************************************************
427  Accumulate size of a file.
428 ****************************************************************************/
429
430 static void do_du(file_info *finfo)
431 {
432         if (do_this_one(finfo)) {
433                 dir_total += finfo->size;
434         }
435 }
436
437 static BOOL do_list_recurse;
438 static BOOL do_list_dirs;
439 static char *do_list_queue = 0;
440 static long do_list_queue_size = 0;
441 static long do_list_queue_start = 0;
442 static long do_list_queue_end = 0;
443 static void (*do_list_fn)(file_info *);
444
445 /****************************************************************************
446  Functions for do_list_queue.
447 ****************************************************************************/
448
449 /*
450  * The do_list_queue is a NUL-separated list of strings stored in a
451  * char*.  Since this is a FIFO, we keep track of the beginning and
452  * ending locations of the data in the queue.  When we overflow, we
453  * double the size of the char*.  When the start of the data passes
454  * the midpoint, we move everything back.  This is logically more
455  * complex than a linked list, but easier from a memory management
456  * angle.  In any memory error condition, do_list_queue is reset.
457  * Functions check to ensure that do_list_queue is non-NULL before
458  * accessing it.
459  */
460
461 static void reset_do_list_queue(void)
462 {
463         SAFE_FREE(do_list_queue);
464         do_list_queue_size = 0;
465         do_list_queue_start = 0;
466         do_list_queue_end = 0;
467 }
468
469 static void init_do_list_queue(void)
470 {
471         reset_do_list_queue();
472         do_list_queue_size = 1024;
473         do_list_queue = (char *)SMB_MALLOC(do_list_queue_size);
474         if (do_list_queue == 0) { 
475                 d_printf("malloc fail for size %d\n",
476                          (int)do_list_queue_size);
477                 reset_do_list_queue();
478         } else {
479                 memset(do_list_queue, 0, do_list_queue_size);
480         }
481 }
482
483 static void adjust_do_list_queue(void)
484 {
485         /*
486          * If the starting point of the queue is more than half way through,
487          * move everything toward the beginning.
488          */
489
490         if (do_list_queue == NULL) {
491                 DEBUG(4,("do_list_queue is empty\n"));
492                 do_list_queue_start = do_list_queue_end = 0;
493                 return;
494         }
495                 
496         if (do_list_queue_start == do_list_queue_end) {
497                 DEBUG(4,("do_list_queue is empty\n"));
498                 do_list_queue_start = do_list_queue_end = 0;
499                 *do_list_queue = '\0';
500         } else if (do_list_queue_start > (do_list_queue_size / 2)) {
501                 DEBUG(4,("sliding do_list_queue backward\n"));
502                 memmove(do_list_queue,
503                         do_list_queue + do_list_queue_start,
504                         do_list_queue_end - do_list_queue_start);
505                 do_list_queue_end -= do_list_queue_start;
506                 do_list_queue_start = 0;
507         }
508 }
509
510 static void add_to_do_list_queue(const char* entry)
511 {
512         long new_end = do_list_queue_end + ((long)strlen(entry)) + 1;
513         while (new_end > do_list_queue_size) {
514                 do_list_queue_size *= 2;
515                 DEBUG(4,("enlarging do_list_queue to %d\n",
516                          (int)do_list_queue_size));
517                 do_list_queue = (char *)SMB_REALLOC(do_list_queue, do_list_queue_size);
518                 if (! do_list_queue) {
519                         d_printf("failure enlarging do_list_queue to %d bytes\n",
520                                  (int)do_list_queue_size);
521                         reset_do_list_queue();
522                 } else {
523                         memset(do_list_queue + do_list_queue_size / 2,
524                                0, do_list_queue_size / 2);
525                 }
526         }
527         if (do_list_queue) {
528                 safe_strcpy_base(do_list_queue + do_list_queue_end, 
529                                  entry, do_list_queue, do_list_queue_size);
530                 do_list_queue_end = new_end;
531                 DEBUG(4,("added %s to do_list_queue (start=%d, end=%d)\n",
532                          entry, (int)do_list_queue_start, (int)do_list_queue_end));
533         }
534 }
535
536 static char *do_list_queue_head(void)
537 {
538         return do_list_queue + do_list_queue_start;
539 }
540
541 static void remove_do_list_queue_head(void)
542 {
543         if (do_list_queue_end > do_list_queue_start) {
544                 do_list_queue_start += strlen(do_list_queue_head()) + 1;
545                 adjust_do_list_queue();
546                 DEBUG(4,("removed head of do_list_queue (start=%d, end=%d)\n",
547                          (int)do_list_queue_start, (int)do_list_queue_end));
548         }
549 }
550
551 static int do_list_queue_empty(void)
552 {
553         return (! (do_list_queue && *do_list_queue));
554 }
555
556 /****************************************************************************
557  A helper for do_list.
558 ****************************************************************************/
559
560 static void do_list_helper(const char *mntpoint, file_info *f, const char *mask, void *state)
561 {
562         char *dir_end;
563
564         /* save the directory */
565         pstrcpy( f->dir, mask );
566         if ( (dir_end = strrchr( f->dir, CLI_DIRSEP_CHAR )) != NULL ) {
567                 *dir_end = '\0';
568         }
569
570         if (f->mode & aDIR) {
571                 if (do_list_dirs && do_this_one(f)) {
572                         do_list_fn(f);
573                 }
574                 if (do_list_recurse && 
575                     !strequal(f->name,".") && 
576                     !strequal(f->name,"..")) {
577                         pstring mask2;
578                         char *p;
579
580                         if (!f->name[0]) {
581                                 d_printf("Empty dir name returned. Possible server misconfiguration.\n");
582                                 return;
583                         }
584
585                         pstrcpy(mask2, mntpoint);
586                         pstrcat(mask2, mask);
587                         p = strrchr_m(mask2,CLI_DIRSEP_CHAR);
588                         if (!p)
589                                 return;
590                         p[1] = 0;
591                         pstrcat(mask2, f->name);
592                         pstrcat(mask2,CLI_DIRSEP_STR);
593                         pstrcat(mask2,"*");
594                         add_to_do_list_queue(mask2);
595                 }
596                 return;
597         }
598
599         if (do_this_one(f)) {
600                 do_list_fn(f);
601         }
602 }
603
604 /****************************************************************************
605  A wrapper around cli_list that adds recursion.
606 ****************************************************************************/
607
608 void do_list(const char *mask,uint16 attribute,void (*fn)(file_info *),BOOL rec, BOOL dirs)
609 {
610         static int in_do_list = 0;
611         struct cli_state *targetcli;
612         pstring targetpath;
613
614         if (in_do_list && rec) {
615                 fprintf(stderr, "INTERNAL ERROR: do_list called recursively when the recursive flag is true\n");
616                 exit(1);
617         }
618
619         in_do_list = 1;
620
621         do_list_recurse = rec;
622         do_list_dirs = dirs;
623         do_list_fn = fn;
624
625         if (rec) {
626                 init_do_list_queue();
627                 add_to_do_list_queue(mask);
628                 
629                 while (! do_list_queue_empty()) {
630                         /*
631                          * Need to copy head so that it doesn't become
632                          * invalid inside the call to cli_list.  This
633                          * would happen if the list were expanded
634                          * during the call.
635                          * Fix from E. Jay Berkenbilt (ejb@ql.org)
636                          */
637                         pstring head;
638                         pstrcpy(head, do_list_queue_head());
639                         
640                         /* check for dfs */
641                         
642                         if ( !cli_resolve_path( "", cli, head, &targetcli, targetpath ) ) {
643                                 d_printf("do_list: [%s] %s\n", head, cli_errstr(cli));
644                                 remove_do_list_queue_head();
645                                 continue;
646                         }
647                         
648                         cli_list(targetcli, targetpath, attribute, do_list_helper, NULL);
649                         remove_do_list_queue_head();
650                         if ((! do_list_queue_empty()) && (fn == display_finfo)) {
651                                 char* next_file = do_list_queue_head();
652                                 char* save_ch = 0;
653                                 if ((strlen(next_file) >= 2) &&
654                                     (next_file[strlen(next_file) - 1] == '*') &&
655                                     (next_file[strlen(next_file) - 2] == CLI_DIRSEP_CHAR)) {
656                                         save_ch = next_file +
657                                                 strlen(next_file) - 2;
658                                         *save_ch = '\0';
659                                         if (showacls) /* cwd is only used if showacls is on */
660                                                 pstrcpy( cwd, next_file);
661                                 }
662                                 if (!showacls) /* don't disturbe the showacls output */
663                                         d_printf("\n%s\n",next_file);
664                                 if (save_ch) {
665                                         *save_ch = CLI_DIRSEP_CHAR;
666                                 }
667                         }
668                 }
669         } else {
670                 /* check for dfs */
671                         
672                 if ( cli_resolve_path( "", cli, mask, &targetcli, targetpath ) ) {
673                         if (cli_list(targetcli, targetpath, attribute, do_list_helper, NULL) == -1) 
674                                 d_printf("%s listing %s\n", cli_errstr(targetcli), targetpath);
675                 }
676                 else
677                         d_printf("do_list: [%s] %s\n", mask, cli_errstr(cli));
678                 
679         }
680
681         in_do_list = 0;
682         reset_do_list_queue();
683 }
684
685 /****************************************************************************
686  Get a directory listing.
687 ****************************************************************************/
688
689 static int cmd_dir(void)
690 {
691         uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
692         pstring mask;
693         pstring buf;
694         char *p=buf;
695         int rc;
696         
697         dir_total = 0;
698         if (strcmp(cur_dir, CLI_DIRSEP_STR) != 0) {
699                 pstrcpy(mask,cur_dir);
700                 if ((mask[0] != '\0') && (mask[strlen(mask)-1]!=CLI_DIRSEP_CHAR))
701                         pstrcat(mask,CLI_DIRSEP_STR);
702         } else {
703                 pstrcpy(mask, CLI_DIRSEP_STR);
704         }
705         
706         if (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
707                 dos_format(p);
708                 if (*p == CLI_DIRSEP_CHAR)
709                         pstrcpy(mask,p + 1);
710                 else
711                         pstrcat(mask,p);
712         } else {
713                 pstrcat(mask,"*");
714         }
715
716         if (showacls) {
717                 /* cwd is only used if showacls is on */
718                 pstrcpy(cwd, cur_dir);
719         }
720
721         do_list(mask, attribute, display_finfo, recurse, True);
722
723         rc = do_dskattr();
724
725         DEBUG(3, ("Total bytes listed: %.0f\n", dir_total));
726
727         return rc;
728 }
729
730 /****************************************************************************
731  Get a directory listing.
732 ****************************************************************************/
733
734 static int cmd_du(void)
735 {
736         uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
737         pstring mask;
738         pstring buf;
739         char *p=buf;
740         int rc;
741         
742         dir_total = 0;
743         pstrcpy(mask,cur_dir);
744         if ((mask[0] != '\0') && (mask[strlen(mask)-1]!=CLI_DIRSEP_CHAR))
745                 pstrcat(mask,CLI_DIRSEP_STR);
746         
747         if (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
748                 dos_format(p);
749                 if (*p == CLI_DIRSEP_CHAR)
750                         pstrcpy(mask,p);
751                 else
752                         pstrcat(mask,p);
753         } else {
754                 pstrcat(mask,"*");
755         }
756
757         do_list(mask, attribute, do_du, recurse, True);
758
759         rc = do_dskattr();
760
761         d_printf("Total number of bytes: %.0f\n", dir_total);
762
763         return rc;
764 }
765
766 /****************************************************************************
767  Get a file from rname to lname
768 ****************************************************************************/
769
770 static int do_get(char *rname, char *lname, BOOL reget)
771 {  
772         int handle = 0, fnum;
773         BOOL newhandle = False;
774         char *data;
775         struct timeval tp_start;
776         int read_size = io_bufsize;
777         uint16 attr;
778         SMB_OFF_T size;
779         off_t start = 0;
780         off_t nread = 0;
781         int rc = 0;
782         struct cli_state *targetcli;
783         pstring targetname;
784
785
786         if (lowercase) {
787                 strlower_m(lname);
788         }
789
790         if ( !cli_resolve_path( "", cli, rname, &targetcli, targetname ) ) {
791                 d_printf("Failed to open %s: %s\n", rname, cli_errstr(cli));
792                 return 1;
793         }
794
795         GetTimeOfDay(&tp_start);
796         
797         fnum = cli_open(targetcli, targetname, O_RDONLY, DENY_NONE);
798
799         if (fnum == -1) {
800                 d_printf("%s opening remote file %s\n",cli_errstr(cli),rname);
801                 return 1;
802         }
803
804         if(!strcmp(lname,"-")) {
805                 handle = fileno(stdout);
806         } else {
807                 if (reget) {
808                         handle = sys_open(lname, O_WRONLY|O_CREAT, 0644);
809                         if (handle >= 0) {
810                                 start = sys_lseek(handle, 0, SEEK_END);
811                                 if (start == -1) {
812                                         d_printf("Error seeking local file\n");
813                                         return 1;
814                                 }
815                         }
816                 } else {
817                         handle = sys_open(lname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
818                 }
819                 newhandle = True;
820         }
821         if (handle < 0) {
822                 d_printf("Error opening local file %s\n",lname);
823                 return 1;
824         }
825
826
827         if (!cli_qfileinfo(targetcli, fnum, 
828                            &attr, &size, NULL, NULL, NULL, NULL, NULL) &&
829             !cli_getattrE(targetcli, fnum, 
830                           &attr, &size, NULL, NULL, NULL)) {
831                 d_printf("getattrib: %s\n",cli_errstr(targetcli));
832                 return 1;
833         }
834
835         DEBUG(1,("getting file %s of size %.0f as %s ", 
836                  rname, (double)size, lname));
837
838         if(!(data = (char *)SMB_MALLOC(read_size))) { 
839                 d_printf("malloc fail for size %d\n", read_size);
840                 cli_close(targetcli, fnum);
841                 return 1;
842         }
843
844         while (1) {
845                 int n = cli_read(targetcli, fnum, data, nread + start, read_size);
846
847                 if (n <= 0)
848                         break;
849  
850                 if (writefile(handle,data, n) != n) {
851                         d_printf("Error writing local file\n");
852                         rc = 1;
853                         break;
854                 }
855       
856                 nread += n;
857         }
858
859         if (nread + start < size) {
860                 DEBUG (0, ("Short read when getting file %s. Only got %ld bytes.\n",
861                             rname, (long)nread));
862
863                 rc = 1;
864         }
865
866         SAFE_FREE(data);
867         
868         if (!cli_close(targetcli, fnum)) {
869                 d_printf("Error %s closing remote file\n",cli_errstr(cli));
870                 rc = 1;
871         }
872
873         if (newhandle) {
874                 close(handle);
875         }
876
877         if (archive_level >= 2 && (attr & aARCH)) {
878                 cli_setatr(cli, rname, attr & ~(uint16)aARCH, 0);
879         }
880
881         {
882                 struct timeval tp_end;
883                 int this_time;
884                 
885                 GetTimeOfDay(&tp_end);
886                 this_time = 
887                         (tp_end.tv_sec - tp_start.tv_sec)*1000 +
888                         (tp_end.tv_usec - tp_start.tv_usec)/1000;
889                 get_total_time_ms += this_time;
890                 get_total_size += nread;
891                 
892                 DEBUG(1,("(%3.1f kb/s) (average %3.1f kb/s)\n",
893                          nread / (1.024*this_time + 1.0e-4),
894                          get_total_size / (1.024*get_total_time_ms)));
895         }
896         
897         return rc;
898 }
899
900 /****************************************************************************
901  Get a file.
902 ****************************************************************************/
903
904 static int cmd_get(void)
905 {
906         pstring lname;
907         pstring rname;
908         char *p;
909
910         pstrcpy(rname,cur_dir);
911         pstrcat(rname,CLI_DIRSEP_STR);
912         
913         p = rname + strlen(rname);
914         
915         if (!next_token_nr(NULL,p,NULL,sizeof(rname)-strlen(rname))) {
916                 d_printf("get <filename>\n");
917                 return 1;
918         }
919         pstrcpy(lname,p);
920         clean_name(rname);
921         
922         next_token_nr(NULL,lname,NULL,sizeof(lname));
923         
924         return do_get(rname, lname, False);
925 }
926
927 /****************************************************************************
928  Do an mget operation on one file.
929 ****************************************************************************/
930
931 static void do_mget(file_info *finfo)
932 {
933         pstring rname;
934         pstring quest;
935         pstring saved_curdir;
936         pstring mget_mask;
937
938         if (strequal(finfo->name,".") || strequal(finfo->name,".."))
939                 return;
940
941         if (abort_mget) {
942                 d_printf("mget aborted\n");
943                 return;
944         }
945
946         if (finfo->mode & aDIR)
947                 slprintf(quest,sizeof(pstring)-1,
948                          "Get directory %s? ",finfo->name);
949         else
950                 slprintf(quest,sizeof(pstring)-1,
951                          "Get file %s? ",finfo->name);
952
953         if (prompt && !yesno(quest))
954                 return;
955
956         if (!(finfo->mode & aDIR)) {
957                 pstrcpy(rname,cur_dir);
958                 pstrcat(rname,finfo->name);
959                 do_get(rname, finfo->name, False);
960                 return;
961         }
962
963         /* handle directories */
964         pstrcpy(saved_curdir,cur_dir);
965
966         pstrcat(cur_dir,finfo->name);
967         pstrcat(cur_dir,CLI_DIRSEP_STR);
968
969         unix_format(finfo->name);
970         if (lowercase)
971                 strlower_m(finfo->name);
972         
973         if (!directory_exist(finfo->name,NULL) && 
974             mkdir(finfo->name,0777) != 0) {
975                 d_printf("failed to create directory %s\n",finfo->name);
976                 pstrcpy(cur_dir,saved_curdir);
977                 return;
978         }
979         
980         if (chdir(finfo->name) != 0) {
981                 d_printf("failed to chdir to directory %s\n",finfo->name);
982                 pstrcpy(cur_dir,saved_curdir);
983                 return;
984         }
985
986         pstrcpy(mget_mask,cur_dir);
987         pstrcat(mget_mask,"*");
988         
989         do_list(mget_mask, aSYSTEM | aHIDDEN | aDIR,do_mget,False, True);
990         chdir("..");
991         pstrcpy(cur_dir,saved_curdir);
992 }
993
994 /****************************************************************************
995  View the file using the pager.
996 ****************************************************************************/
997
998 static int cmd_more(void)
999 {
1000         pstring rname,lname,pager_cmd;
1001         char *pager;
1002         int fd;
1003         int rc = 0;
1004
1005         pstrcpy(rname,cur_dir);
1006         pstrcat(rname,CLI_DIRSEP_STR);
1007         
1008         slprintf(lname,sizeof(lname)-1, "%s/smbmore.XXXXXX",tmpdir());
1009         fd = smb_mkstemp(lname);
1010         if (fd == -1) {
1011                 d_printf("failed to create temporary file for more\n");
1012                 return 1;
1013         }
1014         close(fd);
1015
1016         if (!next_token_nr(NULL,rname+strlen(rname),NULL,sizeof(rname)-strlen(rname))) {
1017                 d_printf("more <filename>\n");
1018                 unlink(lname);
1019                 return 1;
1020         }
1021         clean_name(rname);
1022
1023         rc = do_get(rname, lname, False);
1024
1025         pager=getenv("PAGER");
1026
1027         slprintf(pager_cmd,sizeof(pager_cmd)-1,
1028                  "%s %s",(pager? pager:PAGER), lname);
1029         system(pager_cmd);
1030         unlink(lname);
1031         
1032         return rc;
1033 }
1034
1035 /****************************************************************************
1036  Do a mget command.
1037 ****************************************************************************/
1038
1039 static int cmd_mget(void)
1040 {
1041         uint16 attribute = aSYSTEM | aHIDDEN;
1042         pstring mget_mask;
1043         pstring buf;
1044         char *p=buf;
1045
1046         *mget_mask = 0;
1047
1048         if (recurse)
1049                 attribute |= aDIR;
1050         
1051         abort_mget = False;
1052
1053         while (next_token_nr(NULL,p,NULL,sizeof(buf))) {
1054                 pstrcpy(mget_mask,cur_dir);
1055                 if ((mget_mask[0] != '\0') && (mget_mask[strlen(mget_mask)-1]!=CLI_DIRSEP_CHAR))
1056                         pstrcat(mget_mask,CLI_DIRSEP_STR);
1057                 
1058                 if (*p == CLI_DIRSEP_CHAR)
1059                         pstrcpy(mget_mask,p);
1060                 else
1061                         pstrcat(mget_mask,p);
1062                 do_list(mget_mask, attribute,do_mget,False,True);
1063         }
1064
1065         if (!*mget_mask) {
1066                 pstrcpy(mget_mask,cur_dir);
1067                 if(mget_mask[strlen(mget_mask)-1]!=CLI_DIRSEP_CHAR)
1068                         pstrcat(mget_mask,CLI_DIRSEP_STR);
1069                 pstrcat(mget_mask,"*");
1070                 do_list(mget_mask, attribute,do_mget,False,True);
1071         }
1072         
1073         return 0;
1074 }
1075
1076 /****************************************************************************
1077  Make a directory of name "name".
1078 ****************************************************************************/
1079
1080 static BOOL do_mkdir(char *name)
1081 {
1082         struct cli_state *targetcli;
1083         pstring targetname;
1084         
1085         if ( !cli_resolve_path( "", cli, name, &targetcli, targetname ) ) {
1086                 d_printf("mkdir %s: %s\n", name, cli_errstr(cli));
1087                 return False;
1088         }
1089
1090         if (!cli_mkdir(targetcli, targetname)) {
1091                 d_printf("%s making remote directory %s\n",
1092                          cli_errstr(targetcli),name);
1093                 return(False);
1094         }
1095
1096         return(True);
1097 }
1098
1099 /****************************************************************************
1100  Show 8.3 name of a file.
1101 ****************************************************************************/
1102
1103 static BOOL do_altname(char *name)
1104 {
1105         pstring altname;
1106         if (!NT_STATUS_IS_OK(cli_qpathinfo_alt_name(cli, name, altname))) {
1107                 d_printf("%s getting alt name for %s\n",
1108                          cli_errstr(cli),name);
1109                 return(False);
1110         }
1111         d_printf("%s\n", altname);
1112
1113         return(True);
1114 }
1115
1116 /****************************************************************************
1117  Exit client.
1118 ****************************************************************************/
1119
1120 static int cmd_quit(void)
1121 {
1122         cli_cm_shutdown();
1123         talloc_destroy( ctx);
1124         exit(0);
1125         /* NOTREACHED */
1126         return 0;
1127 }
1128
1129 /****************************************************************************
1130  Make a directory.
1131 ****************************************************************************/
1132
1133 static int cmd_mkdir(void)
1134 {
1135         pstring mask;
1136         pstring buf;
1137         char *p=buf;
1138   
1139         pstrcpy(mask,cur_dir);
1140
1141         if (!next_token_nr(NULL,p,NULL,sizeof(buf))) {
1142                 if (!recurse)
1143                         d_printf("mkdir <dirname>\n");
1144                 return 1;
1145         }
1146         pstrcat(mask,p);
1147
1148         if (recurse) {
1149                 pstring ddir;
1150                 pstring ddir2;
1151                 struct cli_state *targetcli;
1152                 pstring targetname;
1153                 *ddir2 = 0;
1154                 
1155                 if ( !cli_resolve_path( "", cli, mask, &targetcli, targetname ) ) {
1156                         return 1;
1157                 }
1158
1159                 pstrcpy(ddir,targetname);
1160                 trim_char(ddir,'.','\0');
1161                 p = strtok(ddir,"/\\");
1162                 while (p) {
1163                         pstrcat(ddir2,p);
1164                         if (!cli_chkpath(targetcli, ddir2)) { 
1165                                 do_mkdir(ddir2);
1166                         }
1167                         pstrcat(ddir2,CLI_DIRSEP_STR);
1168                         p = strtok(NULL,"/\\");
1169                 }        
1170         } else {
1171                 do_mkdir(mask);
1172         }
1173         
1174         return 0;
1175 }
1176
1177 /****************************************************************************
1178  Show alt name.
1179 ****************************************************************************/
1180
1181 static int cmd_altname(void)
1182 {
1183         pstring name;
1184         pstring buf;
1185         char *p=buf;
1186   
1187         pstrcpy(name,cur_dir);
1188
1189         if (!next_token_nr(NULL,p,NULL,sizeof(buf))) {
1190                 d_printf("altname <file>\n");
1191                 return 1;
1192         }
1193         pstrcat(name,p);
1194
1195         do_altname(name);
1196
1197         return 0;
1198 }
1199
1200 /****************************************************************************
1201  Put a single file.
1202 ****************************************************************************/
1203
1204 static int do_put(char *rname, char *lname, BOOL reput)
1205 {
1206         int fnum;
1207         XFILE *f;
1208         SMB_OFF_T start = 0;
1209         off_t nread = 0;
1210         char *buf = NULL;
1211         int maxwrite = io_bufsize;
1212         int rc = 0;
1213         struct timeval tp_start;
1214         struct cli_state *targetcli;
1215         pstring targetname;
1216         
1217         if ( !cli_resolve_path( "", cli, rname, &targetcli, targetname ) ) {
1218                 d_printf("Failed to open %s: %s\n", rname, cli_errstr(cli));
1219                 return 1;
1220         }
1221         
1222         GetTimeOfDay(&tp_start);
1223
1224         if (reput) {
1225                 fnum = cli_open(targetcli, targetname, O_RDWR|O_CREAT, DENY_NONE);
1226                 if (fnum >= 0) {
1227                         if (!cli_qfileinfo(targetcli, fnum, NULL, &start, NULL, NULL, NULL, NULL, NULL) &&
1228                             !cli_getattrE(targetcli, fnum, NULL, &start, NULL, NULL, NULL)) {
1229                                 d_printf("getattrib: %s\n",cli_errstr(cli));
1230                                 return 1;
1231                         }
1232                 }
1233         } else {
1234                 fnum = cli_open(targetcli, targetname, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE);
1235         }
1236   
1237         if (fnum == -1) {
1238                 d_printf("%s opening remote file %s\n",cli_errstr(targetcli),rname);
1239                 return 1;
1240         }
1241
1242         /* allow files to be piped into smbclient
1243            jdblair 24.jun.98
1244
1245            Note that in this case this function will exit(0) rather
1246            than returning. */
1247         if (!strcmp(lname, "-")) {
1248                 f = x_stdin;
1249                 /* size of file is not known */
1250         } else {
1251                 f = x_fopen(lname,O_RDONLY, 0);
1252                 if (f && reput) {
1253                         if (x_tseek(f, start, SEEK_SET) == -1) {
1254                                 d_printf("Error seeking local file\n");
1255                                 return 1;
1256                         }
1257                 }
1258         }
1259
1260         if (!f) {
1261                 d_printf("Error opening local file %s\n",lname);
1262                 return 1;
1263         }
1264   
1265         DEBUG(1,("putting file %s as %s ",lname,
1266                  rname));
1267   
1268         buf = (char *)SMB_MALLOC(maxwrite);
1269         if (!buf) {
1270                 d_printf("ERROR: Not enough memory!\n");
1271                 return 1;
1272         }
1273         while (!x_feof(f)) {
1274                 int n = maxwrite;
1275                 int ret;
1276
1277                 if ((n = readfile(buf,n,f)) < 1) {
1278                         if((n == 0) && x_feof(f))
1279                                 break; /* Empty local file. */
1280
1281                         d_printf("Error reading local file: %s\n", strerror(errno));
1282                         rc = 1;
1283                         break;
1284                 }
1285
1286                 ret = cli_write(targetcli, fnum, 0, buf, nread + start, n);
1287
1288                 if (n != ret) {
1289                         d_printf("Error writing file: %s\n", cli_errstr(cli));
1290                         rc = 1;
1291                         break;
1292                 } 
1293
1294                 nread += n;
1295         }
1296
1297         if (!cli_close(targetcli, fnum)) {
1298                 d_printf("%s closing remote file %s\n",cli_errstr(cli),rname);
1299                 x_fclose(f);
1300                 SAFE_FREE(buf);
1301                 return 1;
1302         }
1303
1304         
1305         if (f != x_stdin) {
1306                 x_fclose(f);
1307         }
1308
1309         SAFE_FREE(buf);
1310
1311         {
1312                 struct timeval tp_end;
1313                 int this_time;
1314                 
1315                 GetTimeOfDay(&tp_end);
1316                 this_time = 
1317                         (tp_end.tv_sec - tp_start.tv_sec)*1000 +
1318                         (tp_end.tv_usec - tp_start.tv_usec)/1000;
1319                 put_total_time_ms += this_time;
1320                 put_total_size += nread;
1321                 
1322                 DEBUG(1,("(%3.1f kb/s) (average %3.1f kb/s)\n",
1323                          nread / (1.024*this_time + 1.0e-4),
1324                          put_total_size / (1.024*put_total_time_ms)));
1325         }
1326
1327         if (f == x_stdin) {
1328                 cli_cm_shutdown();
1329                 exit(0);
1330         }
1331         
1332         return rc;
1333 }
1334
1335 /****************************************************************************
1336  Put a file.
1337 ****************************************************************************/
1338
1339 static int cmd_put(void)
1340 {
1341         pstring lname;
1342         pstring rname;
1343         pstring buf;
1344         char *p=buf;
1345         
1346         pstrcpy(rname,cur_dir);
1347         pstrcat(rname,CLI_DIRSEP_STR);
1348   
1349         if (!next_token_nr(NULL,p,NULL,sizeof(buf))) {
1350                 d_printf("put <filename>\n");
1351                 return 1;
1352         }
1353         pstrcpy(lname,p);
1354   
1355         if (next_token_nr(NULL,p,NULL,sizeof(buf)))
1356                 pstrcat(rname,p);      
1357         else
1358                 pstrcat(rname,lname);
1359         
1360         clean_name(rname);
1361
1362         {
1363                 SMB_STRUCT_STAT st;
1364                 /* allow '-' to represent stdin
1365                    jdblair, 24.jun.98 */
1366                 if (!file_exist(lname,&st) &&
1367                     (strcmp(lname,"-"))) {
1368                         d_printf("%s does not exist\n",lname);
1369                         return 1;
1370                 }
1371         }
1372
1373         return do_put(rname, lname, False);
1374 }
1375
1376 /*************************************
1377  File list structure.
1378 *************************************/
1379
1380 static struct file_list {
1381         struct file_list *prev, *next;
1382         char *file_path;
1383         BOOL isdir;
1384 } *file_list;
1385
1386 /****************************************************************************
1387  Free a file_list structure.
1388 ****************************************************************************/
1389
1390 static void free_file_list (struct file_list *list_head)
1391 {
1392         struct file_list *list, *next;
1393         
1394         for (list = list_head; list; list = next) {
1395                 next = list->next;
1396                 DLIST_REMOVE(list_head, list);
1397                 SAFE_FREE(list->file_path);
1398                 SAFE_FREE(list);
1399         }
1400 }
1401
1402 /****************************************************************************
1403  Seek in a directory/file list until you get something that doesn't start with
1404  the specified name.
1405 ****************************************************************************/
1406
1407 static BOOL seek_list(struct file_list *list, char *name)
1408 {
1409         while (list) {
1410                 trim_string(list->file_path,"./","\n");
1411                 if (strncmp(list->file_path, name, strlen(name)) != 0) {
1412                         return(True);
1413                 }
1414                 list = list->next;
1415         }
1416       
1417         return(False);
1418 }
1419
1420 /****************************************************************************
1421  Set the file selection mask.
1422 ****************************************************************************/
1423
1424 static int cmd_select(void)
1425 {
1426         pstrcpy(fileselection,"");
1427         next_token_nr(NULL,fileselection,NULL,sizeof(fileselection));
1428
1429         return 0;
1430 }
1431
1432 /****************************************************************************
1433   Recursive file matching function act as find
1434   match must be always set to True when calling this function
1435 ****************************************************************************/
1436
1437 static int file_find(struct file_list **list, const char *directory, 
1438                       const char *expression, BOOL match)
1439 {
1440         SMB_STRUCT_DIR *dir;
1441         struct file_list *entry;
1442         struct stat statbuf;
1443         int ret;
1444         char *path;
1445         BOOL isdir;
1446         const char *dname;
1447
1448         dir = sys_opendir(directory);
1449         if (!dir)
1450                 return -1;
1451         
1452         while ((dname = readdirname(dir))) {
1453                 if (!strcmp("..", dname))
1454                         continue;
1455                 if (!strcmp(".", dname))
1456                         continue;
1457                 
1458                 if (asprintf(&path, "%s/%s", directory, dname) <= 0) {
1459                         continue;
1460                 }
1461
1462                 isdir = False;
1463                 if (!match || !gen_fnmatch(expression, dname)) {
1464                         if (recurse) {
1465                                 ret = stat(path, &statbuf);
1466                                 if (ret == 0) {
1467                                         if (S_ISDIR(statbuf.st_mode)) {
1468                                                 isdir = True;
1469                                                 ret = file_find(list, path, expression, False);
1470                                         }
1471                                 } else {
1472                                         d_printf("file_find: cannot stat file %s\n", path);
1473                                 }
1474                                 
1475                                 if (ret == -1) {
1476                                         SAFE_FREE(path);
1477                                         sys_closedir(dir);
1478                                         return -1;
1479                                 }
1480                         }
1481                         entry = SMB_MALLOC_P(struct file_list);
1482                         if (!entry) {
1483                                 d_printf("Out of memory in file_find\n");
1484                                 sys_closedir(dir);
1485                                 return -1;
1486                         }
1487                         entry->file_path = path;
1488                         entry->isdir = isdir;
1489                         DLIST_ADD(*list, entry);
1490                 } else {
1491                         SAFE_FREE(path);
1492                 }
1493         }
1494
1495         sys_closedir(dir);
1496         return 0;
1497 }
1498
1499 /****************************************************************************
1500  mput some files.
1501 ****************************************************************************/
1502
1503 static int cmd_mput(void)
1504 {
1505         pstring buf;
1506         char *p=buf;
1507         
1508         while (next_token_nr(NULL,p,NULL,sizeof(buf))) {
1509                 int ret;
1510                 struct file_list *temp_list;
1511                 char *quest, *lname, *rname;
1512         
1513                 file_list = NULL;
1514
1515                 ret = file_find(&file_list, ".", p, True);
1516                 if (ret) {
1517                         free_file_list(file_list);
1518                         continue;
1519                 }
1520                 
1521                 quest = NULL;
1522                 lname = NULL;
1523                 rname = NULL;
1524                                 
1525                 for (temp_list = file_list; temp_list; 
1526                      temp_list = temp_list->next) {
1527
1528                         SAFE_FREE(lname);
1529                         if (asprintf(&lname, "%s/", temp_list->file_path) <= 0)
1530                                 continue;
1531                         trim_string(lname, "./", "/");
1532                         
1533                         /* check if it's a directory */
1534                         if (temp_list->isdir) {
1535                                 /* if (!recurse) continue; */
1536                                 
1537                                 SAFE_FREE(quest);
1538                                 if (asprintf(&quest, "Put directory %s? ", lname) < 0) break;
1539                                 if (prompt && !yesno(quest)) { /* No */
1540                                         /* Skip the directory */
1541                                         lname[strlen(lname)-1] = '/';
1542                                         if (!seek_list(temp_list, lname))
1543                                                 break;              
1544                                 } else { /* Yes */
1545                                         SAFE_FREE(rname);
1546                                         if(asprintf(&rname, "%s%s", cur_dir, lname) < 0) break;
1547                                         dos_format(rname);
1548                                         if (!cli_chkpath(cli, rname) && 
1549                                             !do_mkdir(rname)) {
1550                                                 DEBUG (0, ("Unable to make dir, skipping..."));
1551                                                 /* Skip the directory */
1552                                                 lname[strlen(lname)-1] = '/';
1553                                                 if (!seek_list(temp_list, lname))
1554                                                         break;
1555                                         }
1556                                 }
1557                                 continue;
1558                         } else {
1559                                 SAFE_FREE(quest);
1560                                 if (asprintf(&quest,"Put file %s? ", lname) < 0) break;
1561                                 if (prompt && !yesno(quest)) /* No */
1562                                         continue;
1563                                 
1564                                 /* Yes */
1565                                 SAFE_FREE(rname);
1566                                 if (asprintf(&rname, "%s%s", cur_dir, lname) < 0) break;
1567                         }
1568
1569                         dos_format(rname);
1570
1571                         do_put(rname, lname, False);
1572                 }
1573                 free_file_list(file_list);
1574                 SAFE_FREE(quest);
1575                 SAFE_FREE(lname);
1576                 SAFE_FREE(rname);
1577         }
1578
1579         return 0;
1580 }
1581
1582 /****************************************************************************
1583  Cancel a print job.
1584 ****************************************************************************/
1585
1586 static int do_cancel(int job)
1587 {
1588         if (cli_printjob_del(cli, job)) {
1589                 d_printf("Job %d cancelled\n",job);
1590                 return 0;
1591         } else {
1592                 d_printf("Error cancelling job %d : %s\n",job,cli_errstr(cli));
1593                 return 1;
1594         }
1595 }
1596
1597 /****************************************************************************
1598  Cancel a print job.
1599 ****************************************************************************/
1600
1601 static int cmd_cancel(void)
1602 {
1603         pstring buf;
1604         int job; 
1605
1606         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1607                 d_printf("cancel <jobid> ...\n");
1608                 return 1;
1609         }
1610         do {
1611                 job = atoi(buf);
1612                 do_cancel(job);
1613         } while (next_token_nr(NULL,buf,NULL,sizeof(buf)));
1614         
1615         return 0;
1616 }
1617
1618 /****************************************************************************
1619  Print a file.
1620 ****************************************************************************/
1621
1622 static int cmd_print(void)
1623 {
1624         pstring lname;
1625         pstring rname;
1626         char *p;
1627
1628         if (!next_token_nr(NULL,lname,NULL, sizeof(lname))) {
1629                 d_printf("print <filename>\n");
1630                 return 1;
1631         }
1632
1633         pstrcpy(rname,lname);
1634         p = strrchr_m(rname,'/');
1635         if (p) {
1636                 slprintf(rname, sizeof(rname)-1, "%s-%d", p+1, (int)sys_getpid());
1637         }
1638
1639         if (strequal(lname,"-")) {
1640                 slprintf(rname, sizeof(rname)-1, "stdin-%d", (int)sys_getpid());
1641         }
1642
1643         return do_put(rname, lname, False);
1644 }
1645
1646 /****************************************************************************
1647  Show a print queue entry.
1648 ****************************************************************************/
1649
1650 static void queue_fn(struct print_job_info *p)
1651 {
1652         d_printf("%-6d   %-9d    %s\n", (int)p->id, (int)p->size, p->name);
1653 }
1654
1655 /****************************************************************************
1656  Show a print queue.
1657 ****************************************************************************/
1658
1659 static int cmd_queue(void)
1660 {
1661         cli_print_queue(cli, queue_fn);
1662         
1663         return 0;
1664 }
1665
1666 /****************************************************************************
1667  Delete some files.
1668 ****************************************************************************/
1669
1670 static void do_del(file_info *finfo)
1671 {
1672         pstring mask;
1673
1674         pstr_sprintf( mask, "%s%c%s", finfo->dir, CLI_DIRSEP_CHAR, finfo->name );
1675
1676         if (finfo->mode & aDIR) 
1677                 return;
1678
1679         if (!cli_unlink(finfo->cli, mask)) {
1680                 d_printf("%s deleting remote file %s\n",cli_errstr(finfo->cli),mask);
1681         }
1682 }
1683
1684 /****************************************************************************
1685  Delete some files.
1686 ****************************************************************************/
1687
1688 static int cmd_del(void)
1689 {
1690         pstring mask;
1691         pstring buf;
1692         uint16 attribute = aSYSTEM | aHIDDEN;
1693
1694         if (recurse)
1695                 attribute |= aDIR;
1696         
1697         pstrcpy(mask,cur_dir);
1698         
1699         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1700                 d_printf("del <filename>\n");
1701                 return 1;
1702         }
1703         pstrcat(mask,buf);
1704
1705         do_list(mask, attribute,do_del,False,False);
1706         
1707         return 0;
1708 }
1709
1710 /****************************************************************************
1711  Wildcard delete some files.
1712 ****************************************************************************/
1713
1714 static int cmd_wdel(void)
1715 {
1716         pstring mask;
1717         pstring buf;
1718         uint16 attribute;
1719         struct cli_state *targetcli;
1720         pstring targetname;
1721
1722         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1723                 d_printf("wdel 0x<attrib> <wcard>\n");
1724                 return 1;
1725         }
1726
1727         attribute = (uint16)strtol(buf, (char **)NULL, 16);
1728
1729         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1730                 d_printf("wdel 0x<attrib> <wcard>\n");
1731                 return 1;
1732         }
1733
1734         pstrcpy(mask,cur_dir);
1735         pstrcat(mask,buf);
1736
1737         if ( !cli_resolve_path( "", cli, mask, &targetcli, targetname ) ) {
1738                 d_printf("cmd_wdel %s: %s\n", mask, cli_errstr(cli));
1739                 return 1;
1740         }
1741         
1742         if (!cli_unlink_full(targetcli, targetname, attribute)) {
1743                 d_printf("%s deleting remote files %s\n",cli_errstr(targetcli),targetname);
1744         }
1745         return 0;
1746 }
1747
1748 /****************************************************************************
1749 ****************************************************************************/
1750
1751 static int cmd_open(void)
1752 {
1753         pstring mask;
1754         pstring buf;
1755         struct cli_state *targetcli;
1756         pstring targetname;
1757         int fnum;
1758
1759         pstrcpy(mask,cur_dir);
1760         
1761         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1762                 d_printf("open <filename>\n");
1763                 return 1;
1764         }
1765         pstrcat(mask,buf);
1766
1767         if ( !cli_resolve_path( "", cli, mask, &targetcli, targetname ) ) {
1768                 d_printf("open %s: %s\n", mask, cli_errstr(cli));
1769                 return 1;
1770         }
1771         
1772         fnum = cli_nt_create(targetcli, targetname, FILE_READ_DATA|FILE_WRITE_DATA);
1773         if (fnum == -1) {
1774                 fnum = cli_nt_create(targetcli, targetname, FILE_READ_DATA);
1775                 if (fnum != -1) {
1776                         d_printf("open file %s: for read/write fnum %d\n", targetname, fnum);
1777                 } else {
1778                         d_printf("Failed to open file %s. %s\n", targetname, cli_errstr(cli));
1779                 }
1780         } else {
1781                 d_printf("open file %s: for read/write fnum %d\n", targetname, fnum);
1782         }
1783
1784         return 0;
1785 }
1786
1787 /****************************************************************************
1788 ****************************************************************************/
1789
1790 static int cmd_posix_encrypt(void)
1791 {
1792         NTSTATUS status;
1793
1794         if (cli->use_kerberos) {
1795                 status = cli_gss_smb_encryption_start(cli);
1796         } else {        
1797                 fstring buf;
1798                 fstring domain;
1799                 fstring user;
1800                 fstring password;
1801
1802                 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1803                         d_printf("posix_encrypt domain user password\n");
1804                         return 1;
1805                 }
1806                 fstrcpy(domain,buf);
1807
1808                 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1809                         d_printf("posix_encrypt domain user password\n");
1810                         return 1;
1811                 }
1812                 fstrcpy(user,buf);
1813
1814                 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1815                         d_printf("posix_encrypt domain user password\n");
1816                         return 1;
1817                 }
1818                 fstrcpy(password,buf);
1819
1820                 status = cli_raw_ntlm_smb_encryption_start(cli,
1821                                                         user,
1822                                                         password,
1823                                                         domain);
1824         }
1825         
1826         if (!NT_STATUS_IS_OK(status)) {
1827                 d_printf("posix_encrypt failed with error %s\n", nt_errstr(status));
1828         } else {
1829                 d_printf("encryption on\n");
1830         }
1831
1832         return 0;
1833 }
1834
1835 /****************************************************************************
1836 ****************************************************************************/
1837
1838 static int cmd_posix_open(void)
1839 {
1840         pstring mask;
1841         pstring buf;
1842         struct cli_state *targetcli;
1843         pstring targetname;
1844         mode_t mode;
1845         int fnum;
1846
1847         pstrcpy(mask,cur_dir);
1848         
1849         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1850                 d_printf("posix_open <filename> 0<mode>\n");
1851                 return 1;
1852         }
1853         pstrcat(mask,buf);
1854         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1855                 d_printf("posix_open <filename> 0<mode>\n");
1856                 return 1;
1857         }
1858         mode = (mode_t)strtol(buf, (char **)NULL, 8);
1859
1860         if (!cli_resolve_path( "", cli, mask, &targetcli, targetname )) {
1861                 d_printf("posix_open %s: %s\n", mask, cli_errstr(cli));
1862                 return 1;
1863         }
1864         
1865         fnum = cli_posix_open(targetcli, targetname, O_CREAT|O_RDWR, mode);
1866         if (fnum == -1) {
1867                 fnum = cli_posix_open(targetcli, targetname, O_CREAT|O_RDONLY, mode);
1868                 if (fnum != -1) {
1869                         d_printf("posix_open file %s: for read/write fnum %d\n", targetname, fnum);
1870                 } else {
1871                         d_printf("Failed to open file %s. %s\n", targetname, cli_errstr(cli));
1872                 }
1873         } else {
1874                 d_printf("posix_open file %s: for read/write fnum %d\n", targetname, fnum);
1875         }
1876
1877         return 0;
1878 }
1879
1880 static int cmd_posix_mkdir(void)
1881 {
1882         pstring mask;
1883         pstring buf;
1884         struct cli_state *targetcli;
1885         pstring targetname;
1886         mode_t mode;
1887         int fnum;
1888
1889         pstrcpy(mask,cur_dir);
1890         
1891         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1892                 d_printf("posix_mkdir <filename> 0<mode>\n");
1893                 return 1;
1894         }
1895         pstrcat(mask,buf);
1896         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1897                 d_printf("posix_mkdir <filename> 0<mode>\n");
1898                 return 1;
1899         }
1900         mode = (mode_t)strtol(buf, (char **)NULL, 8);
1901
1902         if (!cli_resolve_path( "", cli, mask, &targetcli, targetname )) {
1903                 d_printf("posix_mkdir %s: %s\n", mask, cli_errstr(cli));
1904                 return 1;
1905         }
1906
1907         fnum = cli_posix_mkdir(targetcli, targetname, mode);
1908         if (fnum == -1) {
1909                 d_printf("Failed to open file %s. %s\n", targetname, cli_errstr(cli));
1910         } else {
1911                 d_printf("posix_mkdir created directory %s\n", targetname);
1912         }
1913
1914         return 0;
1915 }
1916
1917 static int cmd_posix_unlink(void)
1918 {
1919         pstring mask;
1920         pstring buf;
1921         struct cli_state *targetcli;
1922         pstring targetname;
1923
1924         pstrcpy(mask,cur_dir);
1925         
1926         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1927                 d_printf("posix_unlink <filename>\n");
1928                 return 1;
1929         }
1930         pstrcat(mask,buf);
1931
1932         if (!cli_resolve_path( "", cli, mask, &targetcli, targetname )) {
1933                 d_printf("posix_unlink %s: %s\n", mask, cli_errstr(cli));
1934                 return 1;
1935         }
1936         
1937         if (!cli_posix_unlink(targetcli, targetname)) {
1938                 d_printf("Failed to unlink file %s. %s\n", targetname, cli_errstr(cli));
1939         } else {
1940                 d_printf("posix_unlink deleted file %s\n", targetname);
1941         }
1942
1943         return 0;
1944 }
1945
1946 static int cmd_posix_rmdir(void)
1947 {
1948         pstring mask;
1949         pstring buf;
1950         struct cli_state *targetcli;
1951         pstring targetname;
1952
1953         pstrcpy(mask,cur_dir);
1954         
1955         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1956                 d_printf("posix_rmdir <filename>\n");
1957                 return 1;
1958         }
1959         pstrcat(mask,buf);
1960
1961         if (!cli_resolve_path( "", cli, mask, &targetcli, targetname)) {
1962                 d_printf("posix_rmdir %s: %s\n", mask, cli_errstr(cli));
1963                 return 1;
1964         }
1965         
1966         if (!cli_posix_rmdir(targetcli, targetname)) {
1967                 d_printf("Failed to unlink directory %s. %s\n", targetname, cli_errstr(cli));
1968         } else {
1969                 d_printf("posix_rmdir deleted directory %s\n", targetname);
1970         }
1971
1972         return 0;
1973 }
1974
1975 static int cmd_close(void)
1976 {
1977         fstring buf;
1978         int fnum;
1979
1980         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1981                 d_printf("close <fnum>\n");
1982                 return 1;
1983         }
1984
1985         fnum = atoi(buf);
1986         /* We really should use the targetcli here.... */
1987         if (!cli_close(cli, fnum)) {
1988                 d_printf("close %d: %s\n", fnum, cli_errstr(cli));
1989                 return 1;
1990         }
1991         return 0;
1992 }
1993
1994 static int cmd_posix(void)
1995 {
1996         uint16 major, minor;
1997         uint32 caplow, caphigh;
1998         pstring caps;
1999
2000         if (!SERVER_HAS_UNIX_CIFS(cli)) {
2001                 d_printf("Server doesn't support UNIX CIFS extensions.\n");
2002                 return 1;
2003         }
2004
2005         if (!cli_unix_extensions_version(cli, &major, &minor, &caplow, &caphigh)) {
2006                 d_printf("Can't get UNIX CIFS extensions version from server.\n");
2007                 return 1;
2008         }
2009
2010         d_printf("Server supports CIFS extensions %u.%u\n", (unsigned int)major, (unsigned int)minor);
2011
2012         *caps = '\0';
2013         if (caplow & CIFS_UNIX_FCNTL_LOCKS_CAP) {
2014                 pstrcat(caps, "locks ");
2015         }
2016         if (caplow & CIFS_UNIX_POSIX_ACLS_CAP) {
2017                 pstrcat(caps, "acls ");
2018         }
2019         if (caplow & CIFS_UNIX_XATTTR_CAP) {
2020                 pstrcat(caps, "eas ");
2021         }
2022         if (caplow & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
2023                 pstrcat(caps, "pathnames ");
2024         }
2025         if (caplow & CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP) {
2026                 pstrcat(caps, "posix_path_operations ");
2027         }
2028
2029         if (strlen(caps) > 0 && caps[strlen(caps)-1] == ' ') {
2030                 caps[strlen(caps)-1] = '\0';
2031         }
2032
2033         if (!cli_set_unix_extensions_capabilities(cli, major, minor, caplow, caphigh)) {
2034                 d_printf("Can't set UNIX CIFS extensions capabilities. %s.\n", cli_errstr(cli));
2035                 return 1;
2036         }
2037
2038         d_printf("Selecting server supported CIFS capabilities %s\n", caps);
2039
2040         if (caplow & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
2041                 CLI_DIRSEP_CHAR = '/';
2042                 *CLI_DIRSEP_STR = '/';
2043                 pstrcpy(cur_dir, CLI_DIRSEP_STR);
2044         }
2045
2046         return 0;
2047 }
2048
2049 static int cmd_lock(void)
2050 {
2051         fstring buf;
2052         SMB_BIG_UINT start, len;
2053         enum brl_type lock_type;
2054         int fnum;
2055
2056         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
2057                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
2058                 return 1;
2059         }
2060         fnum = atoi(buf);
2061
2062         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
2063                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
2064                 return 1;
2065         }
2066
2067         if (*buf == 'r' || *buf == 'R') {
2068                 lock_type = READ_LOCK;
2069         } else if (*buf == 'w' || *buf == 'W') {
2070                 lock_type = WRITE_LOCK;
2071         } else {
2072                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
2073                 return 1;
2074         }
2075
2076         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
2077                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
2078                 return 1;
2079         }
2080
2081         start = (SMB_BIG_UINT)strtol(buf, (char **)NULL, 16);
2082
2083         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
2084                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
2085                 return 1;
2086         }
2087
2088         len = (SMB_BIG_UINT)strtol(buf, (char **)NULL, 16);
2089
2090         if (!cli_posix_lock(cli, fnum, start, len, True, lock_type)) {
2091                 d_printf("lock failed %d: %s\n", fnum, cli_errstr(cli));
2092         }
2093
2094         return 0;
2095 }
2096
2097 static int cmd_unlock(void)
2098 {
2099         fstring buf;
2100         SMB_BIG_UINT start, len;
2101         int fnum;
2102
2103         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
2104                 d_printf("unlock <fnum> <hex-start> <hex-len>\n");
2105                 return 1;
2106         }
2107         fnum = atoi(buf);
2108
2109         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
2110                 d_printf("unlock <fnum> <hex-start> <hex-len>\n");
2111                 return 1;
2112         }
2113
2114         start = (SMB_BIG_UINT)strtol(buf, (char **)NULL, 16);
2115
2116         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
2117                 d_printf("unlock <fnum> <hex-start> <hex-len>\n");
2118                 return 1;
2119         }
2120
2121         len = (SMB_BIG_UINT)strtol(buf, (char **)NULL, 16);
2122
2123         if (!cli_posix_unlock(cli, fnum, start, len)) {
2124                 d_printf("unlock failed %d: %s\n", fnum, cli_errstr(cli));
2125         }
2126
2127         return 0;
2128 }
2129
2130
2131 /****************************************************************************
2132  Remove a directory.
2133 ****************************************************************************/
2134
2135 static int cmd_rmdir(void)
2136 {
2137         pstring mask;
2138         pstring buf;
2139         struct cli_state *targetcli;
2140         pstring targetname;
2141   
2142         pstrcpy(mask,cur_dir);
2143         
2144         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
2145                 d_printf("rmdir <dirname>\n");
2146                 return 1;
2147         }
2148         pstrcat(mask,buf);
2149
2150         if ( !cli_resolve_path( "", cli, mask, &targetcli, targetname ) ) {
2151                 d_printf("rmdir %s: %s\n", mask, cli_errstr(cli));
2152                 return 1;
2153         }
2154         
2155         if (!cli_rmdir(targetcli, targetname)) {
2156                 d_printf("%s removing remote directory file %s\n",
2157                          cli_errstr(targetcli),mask);
2158         }
2159         
2160         return 0;
2161 }
2162
2163 /****************************************************************************
2164  UNIX hardlink.
2165 ****************************************************************************/
2166
2167 static int cmd_link(void)
2168 {
2169         pstring oldname,newname;
2170         pstring buf,buf2;
2171         struct cli_state *targetcli;
2172         pstring targetname;
2173   
2174         pstrcpy(oldname,cur_dir);
2175         pstrcpy(newname,cur_dir);
2176   
2177         if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) || 
2178             !next_token_nr(NULL,buf2,NULL, sizeof(buf2))) {
2179                 d_printf("link <oldname> <newname>\n");
2180                 return 1;
2181         }
2182
2183         pstrcat(oldname,buf);
2184         pstrcat(newname,buf2);
2185
2186         if ( !cli_resolve_path( "", cli, oldname, &targetcli, targetname ) ) {
2187                 d_printf("link %s: %s\n", oldname, cli_errstr(cli));
2188                 return 1;
2189         }
2190         
2191         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
2192                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2193                 return 1;
2194         }
2195         
2196         if (!cli_unix_hardlink(targetcli, targetname, newname)) {
2197                 d_printf("%s linking files (%s -> %s)\n", cli_errstr(targetcli), newname, oldname);
2198                 return 1;
2199         }  
2200
2201         return 0;
2202 }
2203
2204 /****************************************************************************
2205  UNIX symlink.
2206 ****************************************************************************/
2207
2208 static int cmd_symlink(void)
2209 {
2210         pstring oldname,newname;
2211         pstring buf,buf2;
2212         struct cli_state *targetcli;
2213         pstring targetname;
2214   
2215         if (!SERVER_HAS_UNIX_CIFS(cli)) {
2216                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2217                 return 1;
2218         }
2219
2220         pstrcpy(newname,cur_dir);
2221         
2222         if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) || 
2223             !next_token_nr(NULL,buf2,NULL, sizeof(buf2))) {
2224                 d_printf("symlink <oldname> <newname>\n");
2225                 return 1;
2226         }
2227
2228         pstrcpy(oldname,buf);
2229         pstrcat(newname,buf2);
2230
2231         if ( !cli_resolve_path( "", cli, oldname, &targetcli, targetname ) ) {
2232                 d_printf("link %s: %s\n", oldname, cli_errstr(cli));
2233                 return 1;
2234         }
2235
2236         if (!cli_unix_symlink(targetcli, targetname, newname)) {
2237                 d_printf("%s symlinking files (%s -> %s)\n",
2238                         cli_errstr(targetcli), newname, targetname);
2239                 return 1;
2240         } 
2241
2242         return 0;
2243 }
2244
2245 /****************************************************************************
2246  UNIX chmod.
2247 ****************************************************************************/
2248
2249 static int cmd_chmod(void)
2250 {
2251         pstring src;
2252         mode_t mode;
2253         pstring buf, buf2;
2254         struct cli_state *targetcli;
2255         pstring targetname;
2256   
2257         pstrcpy(src,cur_dir);
2258         
2259         if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) || 
2260             !next_token_nr(NULL,buf2,NULL, sizeof(buf2))) {
2261                 d_printf("chmod mode file\n");
2262                 return 1;
2263         }
2264
2265         mode = (mode_t)strtol(buf, NULL, 8);
2266         pstrcat(src,buf2);
2267
2268         if ( !cli_resolve_path( "", cli, src, &targetcli, targetname ) ) {
2269                 d_printf("chmod %s: %s\n", src, cli_errstr(cli));
2270                 return 1;
2271         }
2272         
2273         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
2274                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2275                 return 1;
2276         }
2277         
2278         if (!cli_unix_chmod(targetcli, targetname, mode)) {
2279                 d_printf("%s chmod file %s 0%o\n",
2280                         cli_errstr(targetcli), src, (unsigned int)mode);
2281                 return 1;
2282         } 
2283
2284         return 0;
2285 }
2286
2287 static const char *filetype_to_str(mode_t mode)
2288 {
2289         if (S_ISREG(mode)) {
2290                 return "regular file";
2291         } else if (S_ISDIR(mode)) {
2292                 return "directory";
2293         } else 
2294 #ifdef S_ISCHR
2295         if (S_ISCHR(mode)) {
2296                 return "character device";
2297         } else
2298 #endif
2299 #ifdef S_ISBLK
2300         if (S_ISBLK(mode)) {
2301                 return "block device";
2302         } else
2303 #endif
2304 #ifdef S_ISFIFO
2305         if (S_ISFIFO(mode)) {
2306                 return "fifo";
2307         } else
2308 #endif
2309 #ifdef S_ISLNK
2310         if (S_ISLNK(mode)) {
2311                 return "symbolic link";
2312         } else
2313 #endif
2314 #ifdef S_ISSOCK
2315         if (S_ISSOCK(mode)) {
2316                 return "socket";
2317         } else
2318 #endif
2319         return "";
2320 }
2321
2322 static char rwx_to_str(mode_t m, mode_t bt, char ret)
2323 {
2324         if (m & bt) {
2325                 return ret;
2326         } else {
2327                 return '-';
2328         }
2329 }
2330
2331 static char *unix_mode_to_str(char *s, mode_t m)
2332 {
2333         char *p = s;
2334         const char *str = filetype_to_str(m);
2335
2336         switch(str[0]) {
2337                 case 'd':
2338                         *p++ = 'd';
2339                         break;
2340                 case 'c':
2341                         *p++ = 'c';
2342                         break;
2343                 case 'b':
2344                         *p++ = 'b';
2345                         break;
2346                 case 'f':
2347                         *p++ = 'p';
2348                         break;
2349                 case 's':
2350                         *p++ = str[1] == 'y' ? 'l' : 's';
2351                         break;
2352                 case 'r':
2353                 default:
2354                         *p++ = '-';
2355                         break;
2356         }
2357         *p++ = rwx_to_str(m, S_IRUSR, 'r');
2358         *p++ = rwx_to_str(m, S_IWUSR, 'w');
2359         *p++ = rwx_to_str(m, S_IXUSR, 'x');
2360         *p++ = rwx_to_str(m, S_IRGRP, 'r');
2361         *p++ = rwx_to_str(m, S_IWGRP, 'w');
2362         *p++ = rwx_to_str(m, S_IXGRP, 'x');
2363         *p++ = rwx_to_str(m, S_IROTH, 'r');
2364         *p++ = rwx_to_str(m, S_IWOTH, 'w');
2365         *p++ = rwx_to_str(m, S_IXOTH, 'x');
2366         *p++ = '\0';
2367         return s;
2368 }
2369
2370 /****************************************************************************
2371  Utility function for UNIX getfacl.
2372 ****************************************************************************/
2373
2374 static char *perms_to_string(fstring permstr, unsigned char perms)
2375 {
2376         fstrcpy(permstr, "---");
2377         if (perms & SMB_POSIX_ACL_READ) {
2378                 permstr[0] = 'r';
2379         }
2380         if (perms & SMB_POSIX_ACL_WRITE) {
2381                 permstr[1] = 'w';
2382         }
2383         if (perms & SMB_POSIX_ACL_EXECUTE) {
2384                 permstr[2] = 'x';
2385         }
2386         return permstr;
2387 }
2388
2389 /****************************************************************************
2390  UNIX getfacl.
2391 ****************************************************************************/
2392
2393 static int cmd_getfacl(void)
2394 {
2395         pstring src, name;
2396         uint16 major, minor;
2397         uint32 caplow, caphigh;
2398         char *retbuf = NULL;
2399         size_t rb_size = 0;
2400         SMB_STRUCT_STAT sbuf;
2401         uint16 num_file_acls = 0;
2402         uint16 num_dir_acls = 0;
2403         uint16 i;
2404         struct cli_state *targetcli;
2405         pstring targetname;
2406  
2407         pstrcpy(src,cur_dir);
2408         
2409         if (!next_token_nr(NULL,name,NULL,sizeof(name))) {
2410                 d_printf("stat file\n");
2411                 return 1;
2412         }
2413
2414         pstrcat(src,name);
2415         
2416         if ( !cli_resolve_path( "", cli, src, &targetcli, targetname ) ) {
2417                 d_printf("stat %s: %s\n", src, cli_errstr(cli));
2418                 return 1;
2419         }
2420         
2421         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
2422                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2423                 return 1;
2424         }
2425         
2426         if (!cli_unix_extensions_version(targetcli, &major, &minor, &caplow, &caphigh)) {
2427                 d_printf("Can't get UNIX CIFS version from server.\n");
2428                 return 1;
2429         }
2430
2431         if (!(caplow & CIFS_UNIX_POSIX_ACLS_CAP)) {
2432                 d_printf("This server supports UNIX extensions but doesn't support POSIX ACLs.\n");
2433                 return 1;
2434         }
2435
2436         if (!cli_unix_stat(targetcli, targetname, &sbuf)) {
2437                 d_printf("%s getfacl doing a stat on file %s\n",
2438                         cli_errstr(targetcli), src);
2439                 return 1;
2440         } 
2441
2442         if (!cli_unix_getfacl(targetcli, targetname, &rb_size, &retbuf)) {
2443                 d_printf("%s getfacl file %s\n",
2444                         cli_errstr(targetcli), src);
2445                 return 1;
2446         } 
2447
2448         /* ToDo : Print out the ACL values. */
2449         if (SVAL(retbuf,0) != SMB_POSIX_ACL_VERSION || rb_size < 6) {
2450                 d_printf("getfacl file %s, unknown POSIX acl version %u.\n",
2451                         src, (unsigned int)CVAL(retbuf,0) );
2452                 SAFE_FREE(retbuf);
2453                 return 1;
2454         }
2455
2456         num_file_acls = SVAL(retbuf,2);
2457         num_dir_acls = SVAL(retbuf,4);
2458         if (rb_size != SMB_POSIX_ACL_HEADER_SIZE + SMB_POSIX_ACL_ENTRY_SIZE*(num_file_acls+num_dir_acls)) {
2459                 d_printf("getfacl file %s, incorrect POSIX acl buffer size (should be %u, was %u).\n",
2460                         src,
2461                         (unsigned int)(SMB_POSIX_ACL_HEADER_SIZE + SMB_POSIX_ACL_ENTRY_SIZE*(num_file_acls+num_dir_acls)),
2462                         (unsigned int)rb_size);
2463
2464                 SAFE_FREE(retbuf);
2465                 return 1;
2466         }
2467
2468         d_printf("# file: %s\n", src);
2469         d_printf("# owner: %u\n# group: %u\n", (unsigned int)sbuf.st_uid, (unsigned int)sbuf.st_gid);
2470
2471         if (num_file_acls == 0 && num_dir_acls == 0) {
2472                 d_printf("No acls found.\n");
2473         }
2474
2475         for (i = 0; i < num_file_acls; i++) {
2476                 uint32 uorg;
2477                 fstring permstring;
2478                 unsigned char tagtype = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE));
2479                 unsigned char perms = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+1);
2480
2481                 switch(tagtype) {
2482                         case SMB_POSIX_ACL_USER_OBJ:
2483                                 d_printf("user::");
2484                                 break;
2485                         case SMB_POSIX_ACL_USER:
2486                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
2487                                 d_printf("user:%u:", uorg);
2488                                 break;
2489                         case SMB_POSIX_ACL_GROUP_OBJ:
2490                                 d_printf("group::");
2491                                 break;
2492                         case SMB_POSIX_ACL_GROUP:
2493                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
2494                                 d_printf("group:%u", uorg);
2495                                 break;
2496                         case SMB_POSIX_ACL_MASK:
2497                                 d_printf("mask::");
2498                                 break;
2499                         case SMB_POSIX_ACL_OTHER:
2500                                 d_printf("other::");
2501                                 break;
2502                         default:
2503                                 d_printf("getfacl file %s, incorrect POSIX acl tagtype (%u).\n",
2504                                         src, (unsigned int)tagtype );
2505                                 SAFE_FREE(retbuf);
2506                                 return 1;
2507                 }
2508
2509                 d_printf("%s\n", perms_to_string(permstring, perms));
2510         }
2511
2512         for (i = 0; i < num_dir_acls; i++) {
2513                 uint32 uorg;
2514                 fstring permstring;
2515                 unsigned char tagtype = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE));
2516                 unsigned char perms = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+1);
2517
2518                 switch(tagtype) {
2519                         case SMB_POSIX_ACL_USER_OBJ:
2520                                 d_printf("default:user::");
2521                                 break;
2522                         case SMB_POSIX_ACL_USER:
2523                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+2);
2524                                 d_printf("default:user:%u:", uorg);
2525                                 break;
2526                         case SMB_POSIX_ACL_GROUP_OBJ:
2527                                 d_printf("default:group::");
2528                                 break;
2529                         case SMB_POSIX_ACL_GROUP:
2530                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+2);
2531                                 d_printf("default:group:%u", uorg);
2532                                 break;
2533                         case SMB_POSIX_ACL_MASK:
2534                                 d_printf("default:mask::");
2535                                 break;
2536                         case SMB_POSIX_ACL_OTHER:
2537                                 d_printf("default:other::");
2538                                 break;
2539                         default:
2540                                 d_printf("getfacl file %s, incorrect POSIX acl tagtype (%u).\n",
2541                                         src, (unsigned int)tagtype );
2542                                 SAFE_FREE(retbuf);
2543                                 return 1;
2544                 }
2545
2546                 d_printf("%s\n", perms_to_string(permstring, perms));
2547         }
2548
2549         SAFE_FREE(retbuf);
2550         return 0;
2551 }
2552
2553 /****************************************************************************
2554  UNIX stat.
2555 ****************************************************************************/
2556
2557 static int cmd_stat(void)
2558 {
2559         pstring src, name;
2560         fstring mode_str;
2561         SMB_STRUCT_STAT sbuf;
2562         struct cli_state *targetcli;
2563         struct tm *lt;
2564         pstring targetname;
2565  
2566         if (!SERVER_HAS_UNIX_CIFS(cli)) {
2567                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2568                 return 1;
2569         }
2570
2571         pstrcpy(src,cur_dir);
2572         
2573         if (!next_token_nr(NULL,name,NULL,sizeof(name))) {
2574                 d_printf("stat file\n");
2575                 return 1;
2576         }
2577
2578         pstrcat(src,name);
2579
2580         
2581         if ( !cli_resolve_path( "", cli, src, &targetcli, targetname ) ) {
2582                 d_printf("stat %s: %s\n", src, cli_errstr(cli));
2583                 return 1;
2584         }
2585         
2586         if (!cli_unix_stat(targetcli, targetname, &sbuf)) {
2587                 d_printf("%s stat file %s\n",
2588                         cli_errstr(targetcli), src);
2589                 return 1;
2590         } 
2591
2592         /* Print out the stat values. */
2593         d_printf("File: %s\n", src);
2594         d_printf("Size: %-12.0f\tBlocks: %u\t%s\n",
2595                 (double)sbuf.st_size,
2596                 (unsigned int)sbuf.st_blocks,
2597                 filetype_to_str(sbuf.st_mode));
2598
2599 #if defined(S_ISCHR) && defined(S_ISBLK)
2600         if (S_ISCHR(sbuf.st_mode) || S_ISBLK(sbuf.st_mode)) {
2601                 d_printf("Inode: %.0f\tLinks: %u\tDevice type: %u,%u\n",
2602                         (double)sbuf.st_ino,
2603                         (unsigned int)sbuf.st_nlink,
2604                         unix_dev_major(sbuf.st_rdev),
2605                         unix_dev_minor(sbuf.st_rdev));
2606         } else 
2607 #endif
2608                 d_printf("Inode: %.0f\tLinks: %u\n",
2609                         (double)sbuf.st_ino,
2610                         (unsigned int)sbuf.st_nlink);
2611
2612         d_printf("Access: (0%03o/%s)\tUid: %u\tGid: %u\n",
2613                 ((int)sbuf.st_mode & 0777),
2614                 unix_mode_to_str(mode_str, sbuf.st_mode),
2615                 (unsigned int)sbuf.st_uid, 
2616                 (unsigned int)sbuf.st_gid);
2617
2618         lt = localtime(&sbuf.st_atime);
2619         if (lt) {
2620                 strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
2621         } else {
2622                 fstrcpy(mode_str, "unknown");
2623         }
2624         d_printf("Access: %s\n", mode_str);
2625
2626         lt = localtime(&sbuf.st_mtime);
2627         if (lt) {
2628                 strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
2629         } else {
2630                 fstrcpy(mode_str, "unknown");
2631         }
2632         d_printf("Modify: %s\n", mode_str);
2633
2634         lt = localtime(&sbuf.st_ctime);
2635         if (lt) {
2636                 strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
2637         } else {
2638                 fstrcpy(mode_str, "unknown");
2639         }
2640         d_printf("Change: %s\n", mode_str);
2641         
2642         return 0;
2643 }
2644
2645
2646 /****************************************************************************
2647  UNIX chown.
2648 ****************************************************************************/
2649
2650 static int cmd_chown(void)
2651 {
2652         pstring src;
2653         uid_t uid;
2654         gid_t gid;
2655         pstring buf, buf2, buf3;
2656         struct cli_state *targetcli;
2657         pstring targetname;
2658   
2659         pstrcpy(src,cur_dir);
2660         
2661         if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) || 
2662             !next_token_nr(NULL,buf2,NULL, sizeof(buf2)) ||
2663             !next_token_nr(NULL,buf3,NULL, sizeof(buf3))) {
2664                 d_printf("chown uid gid file\n");
2665                 return 1;
2666         }
2667
2668         uid = (uid_t)atoi(buf);
2669         gid = (gid_t)atoi(buf2);
2670         pstrcat(src,buf3);
2671
2672         if ( !cli_resolve_path( "", cli, src, &targetcli, targetname ) ) {
2673                 d_printf("chown %s: %s\n", src, cli_errstr(cli));
2674                 return 1;
2675         }
2676
2677         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
2678                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2679                 return 1;
2680         }
2681         
2682         if (!cli_unix_chown(targetcli, targetname, uid, gid)) {
2683                 d_printf("%s chown file %s uid=%d, gid=%d\n",
2684                         cli_errstr(targetcli), src, (int)uid, (int)gid);
2685                 return 1;
2686         } 
2687
2688         return 0;
2689 }
2690
2691 /****************************************************************************
2692  Rename some file.
2693 ****************************************************************************/
2694
2695 static int cmd_rename(void)
2696 {
2697         pstring src,dest;
2698         pstring buf,buf2;
2699         struct cli_state *targetcli;
2700         pstring targetname;
2701   
2702         pstrcpy(src,cur_dir);
2703         pstrcpy(dest,cur_dir);
2704         
2705         if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) || 
2706             !next_token_nr(NULL,buf2,NULL, sizeof(buf2))) {
2707                 d_printf("rename <src> <dest>\n");
2708                 return 1;
2709         }
2710
2711         pstrcat(src,buf);
2712         pstrcat(dest,buf2);
2713
2714         if ( !cli_resolve_path( "", cli, src, &targetcli, targetname ) ) {
2715                 d_printf("chown %s: %s\n", src, cli_errstr(cli));
2716                 return 1;
2717         }
2718
2719         if (!cli_rename(targetcli, targetname, dest)) {
2720                 d_printf("%s renaming files\n",cli_errstr(targetcli));
2721                 return 1;
2722         }
2723         
2724         return 0;
2725 }
2726
2727 /****************************************************************************
2728  Print the volume name.
2729 ****************************************************************************/
2730
2731 static int cmd_volume(void)
2732 {
2733         fstring volname;
2734         uint32 serial_num;
2735         time_t create_date;
2736   
2737         if (!cli_get_fs_volume_info(cli, volname, &serial_num, &create_date)) {
2738                 d_printf("Errr %s getting volume info\n",cli_errstr(cli));
2739                 return 1;
2740         }
2741         
2742         d_printf("Volume: |%s| serial number 0x%x\n", volname, (unsigned int)serial_num);
2743         return 0;
2744 }
2745
2746 /****************************************************************************
2747  Hard link files using the NT call.
2748 ****************************************************************************/
2749
2750 static int cmd_hardlink(void)
2751 {
2752         pstring src,dest;
2753         pstring buf,buf2;
2754         struct cli_state *targetcli;
2755         pstring targetname;
2756   
2757         pstrcpy(src,cur_dir);
2758         pstrcpy(dest,cur_dir);
2759         
2760         if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) || 
2761             !next_token_nr(NULL,buf2,NULL, sizeof(buf2))) {
2762                 d_printf("hardlink <src> <dest>\n");
2763                 return 1;
2764         }
2765
2766         pstrcat(src,buf);
2767         pstrcat(dest,buf2);
2768
2769         if ( !cli_resolve_path( "", cli, src, &targetcli, targetname ) ) {
2770                 d_printf("hardlink %s: %s\n", src, cli_errstr(cli));
2771                 return 1;
2772         }
2773         
2774         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
2775                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2776                 return 1;
2777         }
2778         
2779         if (!cli_nt_hardlink(targetcli, targetname, dest)) {
2780                 d_printf("%s doing an NT hard link of files\n",cli_errstr(targetcli));
2781                 return 1;
2782         }
2783         
2784         return 0;
2785 }
2786
2787 /****************************************************************************
2788  Toggle the prompt flag.
2789 ****************************************************************************/
2790
2791 static int cmd_prompt(void)
2792 {
2793         prompt = !prompt;
2794         DEBUG(2,("prompting is now %s\n",prompt?"on":"off"));
2795         
2796         return 1;
2797 }
2798
2799 /****************************************************************************
2800  Set the newer than time.
2801 ****************************************************************************/
2802
2803 static int cmd_newer(void)
2804 {
2805         pstring buf;
2806         BOOL ok;
2807         SMB_STRUCT_STAT sbuf;
2808
2809         ok = next_token_nr(NULL,buf,NULL,sizeof(buf));
2810         if (ok && (sys_stat(buf,&sbuf) == 0)) {
2811                 newer_than = sbuf.st_mtime;
2812                 DEBUG(1,("Getting files newer than %s",
2813                          time_to_asc(newer_than)));
2814         } else {
2815                 newer_than = 0;
2816         }
2817
2818         if (ok && newer_than == 0) {
2819                 d_printf("Error setting newer-than time\n");
2820                 return 1;
2821         }
2822
2823         return 0;
2824 }
2825
2826 /****************************************************************************
2827  Set the archive level.
2828 ****************************************************************************/
2829
2830 static int cmd_archive(void)
2831 {
2832         pstring buf;
2833
2834         if (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
2835                 archive_level = atoi(buf);
2836         } else
2837                 d_printf("Archive level is %d\n",archive_level);
2838
2839         return 0;
2840 }
2841
2842 /****************************************************************************
2843  Toggle the lowercaseflag.
2844 ****************************************************************************/
2845
2846 static int cmd_lowercase(void)
2847 {
2848         lowercase = !lowercase;
2849         DEBUG(2,("filename lowercasing is now %s\n",lowercase?"on":"off"));
2850
2851         return 0;
2852 }
2853
2854 /****************************************************************************
2855  Toggle the case sensitive flag.
2856 ****************************************************************************/
2857
2858 static int cmd_setcase(void)
2859 {
2860         BOOL orig_case_sensitive = cli_set_case_sensitive(cli, False);
2861
2862         cli_set_case_sensitive(cli, !orig_case_sensitive);
2863         DEBUG(2,("filename case sensitivity is now %s\n",!orig_case_sensitive ?
2864                 "on":"off"));
2865
2866         return 0;
2867 }
2868
2869 /****************************************************************************
2870  Toggle the showacls flag.
2871 ****************************************************************************/
2872
2873 static int cmd_showacls(void)
2874 {
2875         showacls = !showacls;
2876         DEBUG(2,("showacls is now %s\n",showacls?"on":"off"));
2877
2878         if (!ctx && showacls)
2879                 ctx = talloc_init("smbclient:showacls");
2880                 if (!ctx) {
2881                         DEBUG( 0, ("cmd_showacls() out of memory.  talloc_init() failed.\n"));
2882         }
2883
2884         return 0;
2885 }
2886
2887
2888 /****************************************************************************
2889  Toggle the recurse flag.
2890 ****************************************************************************/
2891
2892 static int cmd_recurse(void)
2893 {
2894         recurse = !recurse;
2895         DEBUG(2,("directory recursion is now %s\n",recurse?"on":"off"));
2896
2897         return 0;
2898 }
2899
2900 /****************************************************************************
2901  Toggle the translate flag.
2902 ****************************************************************************/
2903
2904 static int cmd_translate(void)
2905 {
2906         translation = !translation;
2907         DEBUG(2,("CR/LF<->LF and print text translation now %s\n",
2908                  translation?"on":"off"));
2909
2910         return 0;
2911 }
2912
2913 /****************************************************************************
2914  Do the lcd command.
2915  ****************************************************************************/
2916
2917 static int cmd_lcd(void)
2918 {
2919         pstring buf;
2920         pstring d;
2921         
2922         if (next_token_nr(NULL,buf,NULL,sizeof(buf)))
2923                 chdir(buf);
2924         DEBUG(2,("the local directory is now %s\n",sys_getwd(d)));
2925
2926         return 0;
2927 }
2928
2929 /****************************************************************************
2930  Get a file restarting at end of local file.
2931  ****************************************************************************/
2932
2933 static int cmd_reget(void)
2934 {
2935         pstring local_name;
2936         pstring remote_name;
2937         char *p;
2938
2939         pstrcpy(remote_name, cur_dir);
2940         pstrcat(remote_name, CLI_DIRSEP_STR);
2941         
2942         p = remote_name + strlen(remote_name);
2943         
2944         if (!next_token_nr(NULL, p, NULL, sizeof(remote_name) - strlen(remote_name))) {
2945                 d_printf("reget <filename>\n");
2946                 return 1;
2947         }
2948         pstrcpy(local_name, p);
2949         clean_name(remote_name);
2950         
2951         next_token_nr(NULL, local_name, NULL, sizeof(local_name));
2952         
2953         return do_get(remote_name, local_name, True);
2954 }
2955
2956 /****************************************************************************
2957  Put a file restarting at end of local file.
2958  ****************************************************************************/
2959
2960 static int cmd_reput(void)
2961 {
2962         pstring local_name;
2963         pstring remote_name;
2964         pstring buf;
2965         char *p = buf;
2966         SMB_STRUCT_STAT st;
2967         
2968         pstrcpy(remote_name, cur_dir);
2969         pstrcat(remote_name, CLI_DIRSEP_STR);
2970   
2971         if (!next_token_nr(NULL, p, NULL, sizeof(buf))) {
2972                 d_printf("reput <filename>\n");
2973                 return 1;
2974         }
2975         pstrcpy(local_name, p);
2976   
2977         if (!file_exist(local_name, &st)) {
2978                 d_printf("%s does not exist\n", local_name);
2979                 return 1;
2980         }
2981
2982         if (next_token_nr(NULL, p, NULL, sizeof(buf)))
2983                 pstrcat(remote_name, p);
2984         else
2985                 pstrcat(remote_name, local_name);
2986         
2987         clean_name(remote_name);
2988
2989         return do_put(remote_name, local_name, True);
2990 }
2991
2992 /****************************************************************************
2993  List a share name.
2994  ****************************************************************************/
2995
2996 static void browse_fn(const char *name, uint32 m, 
2997                       const char *comment, void *state)
2998 {
2999         fstring typestr;
3000
3001         *typestr=0;
3002
3003         switch (m & 7)
3004         {
3005           case STYPE_DISKTREE:
3006             fstrcpy(typestr,"Disk"); break;
3007           case STYPE_PRINTQ:
3008             fstrcpy(typestr,"Printer"); break;
3009           case STYPE_DEVICE:
3010             fstrcpy(typestr,"Device"); break;
3011           case STYPE_IPC:
3012             fstrcpy(typestr,"IPC"); break;
3013         }
3014         /* FIXME: If the remote machine returns non-ascii characters
3015            in any of these fields, they can corrupt the output.  We
3016            should remove them. */
3017         if (!grepable) {
3018                 d_printf("\t%-15s %-10.10s%s\n",
3019                         name,typestr,comment);
3020         } else {
3021                 d_printf ("%s|%s|%s\n",typestr,name,comment);
3022         }
3023 }
3024
3025 static BOOL browse_host_rpc(BOOL sort)
3026 {
3027         NTSTATUS status;
3028         struct rpc_pipe_client *pipe_hnd;
3029         TALLOC_CTX *mem_ctx;
3030         uint32 enum_hnd = 0;
3031         struct srvsvc_NetShareCtr1 ctr1;
3032         union srvsvc_NetShareCtr ctr;
3033         int i;
3034         uint32 level;
3035         uint32 numentries;
3036
3037         mem_ctx = talloc_new(NULL);
3038         if (mem_ctx == NULL) {
3039                 DEBUG(0, ("talloc_new failed\n"));
3040                 return False;
3041         }
3042
3043         pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SRVSVC, &status);
3044
3045         if (pipe_hnd == NULL) {
3046                 DEBUG(10, ("Could not connect to srvsvc pipe: %s\n",
3047                            nt_errstr(status)));
3048                 TALLOC_FREE(mem_ctx);
3049                 return False;
3050         }
3051
3052         ZERO_STRUCT(ctr1);
3053         level = 1;
3054         ctr.ctr1 = &ctr1;
3055
3056         status = rpccli_srvsvc_NetShareEnum(pipe_hnd, mem_ctx, "", &level,
3057                                             &ctr, 0xffffffff, &numentries,
3058                                             &enum_hnd);
3059
3060         if (!NT_STATUS_IS_OK(status)) {
3061                 TALLOC_FREE(mem_ctx);
3062                 cli_rpc_pipe_close(pipe_hnd);
3063                 return False;
3064         }
3065
3066         for (i=0; i<numentries; i++) {
3067                 struct srvsvc_NetShareInfo1 *info = &ctr.ctr1->array[i];
3068                 browse_fn(info->name, info->type, info->comment, NULL);
3069         }
3070
3071         TALLOC_FREE(mem_ctx);
3072         cli_rpc_pipe_close(pipe_hnd);
3073         return True;
3074 }
3075
3076 /****************************************************************************
3077  Try and browse available connections on a host.
3078 ****************************************************************************/
3079
3080 static BOOL browse_host(BOOL sort)
3081 {
3082         int ret;
3083         if (!grepable) {
3084                 d_printf("\n\tSharename       Type      Comment\n");
3085                 d_printf("\t---------       ----      -------\n");
3086         }
3087
3088         if (browse_host_rpc(sort)) {
3089                 return True;
3090         }
3091
3092         if((ret = cli_RNetShareEnum(cli, browse_fn, NULL)) == -1)
3093                 d_printf("Error returning browse list: %s\n", cli_errstr(cli));
3094
3095         return (ret != -1);
3096 }
3097
3098 /****************************************************************************
3099  List a server name.
3100 ****************************************************************************/
3101
3102 static void server_fn(const char *name, uint32 m, 
3103                       const char *comment, void *state)
3104 {
3105         
3106         if (!grepable){
3107                 d_printf("\t%-16s     %s\n", name, comment);
3108         } else {
3109                 d_printf("%s|%s|%s\n",(char *)state, name, comment);
3110         }
3111 }
3112
3113 /****************************************************************************
3114  Try and browse available connections on a host.
3115 ****************************************************************************/
3116
3117 static BOOL list_servers(const char *wk_grp)
3118 {
3119         fstring state;
3120
3121         if (!cli->server_domain)
3122                 return False;
3123
3124         if (!grepable) {
3125                 d_printf("\n\tServer               Comment\n");
3126                 d_printf("\t---------            -------\n");
3127         };
3128         fstrcpy( state, "Server" );
3129         cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_ALL, server_fn,
3130                           state);
3131
3132         if (!grepable) {
3133                 d_printf("\n\tWorkgroup            Master\n");
3134                 d_printf("\t---------            -------\n");
3135         }; 
3136
3137         fstrcpy( state, "Workgroup" );
3138         cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_DOMAIN_ENUM,
3139                           server_fn, state);
3140         return True;
3141 }
3142
3143 /****************************************************************************
3144  Print or set current VUID
3145 ****************************************************************************/
3146
3147 static int cmd_vuid(void)
3148 {
3149         fstring buf;
3150         
3151         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
3152                 d_printf("Current VUID is %d\n", cli->vuid);
3153                 return 0;
3154         }
3155
3156         cli->vuid = atoi(buf);
3157         return 0;
3158 }
3159
3160 /****************************************************************************
3161  Setup a new VUID, by issuing a session setup
3162 ****************************************************************************/
3163
3164 static int cmd_logon(void)
3165 {
3166         pstring l_username, l_password;
3167         pstring buf,buf2;
3168   
3169         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
3170                 d_printf("logon <username> [<password>]\n");
3171                 return 0;
3172         }
3173
3174         pstrcpy(l_username, buf);
3175
3176         if (!next_token_nr(NULL,buf2,NULL,sizeof(buf))) 
3177         {
3178                 char *pass = getpass("Password: ");
3179                 if (pass) 
3180                         pstrcpy(l_password, pass);
3181         } 
3182         else
3183                 pstrcpy(l_password, buf2);
3184
3185         if (!NT_STATUS_IS_OK(cli_session_setup(cli, l_username, 
3186                                                l_password, strlen(l_password),
3187                                                l_password, strlen(l_password),
3188                                                lp_workgroup()))) {
3189                 d_printf("session setup failed: %s\n", cli_errstr(cli));
3190                 return -1;
3191         }
3192
3193         d_printf("Current VUID is %d\n", cli->vuid);
3194         return 0;
3195 }
3196
3197
3198 /****************************************************************************
3199  list active connections
3200 ****************************************************************************/
3201
3202 static int cmd_list_connect(void)
3203 {
3204         cli_cm_display();
3205
3206         return 0;
3207 }
3208
3209 /****************************************************************************
3210  display the current active client connection
3211 ****************************************************************************/
3212
3213 static int cmd_show_connect( void )
3214 {
3215         struct cli_state *targetcli;
3216         pstring targetpath;
3217         
3218         if ( !cli_resolve_path( "", cli, cur_dir, &targetcli, targetpath ) ) {
3219                 d_printf("showconnect %s: %s\n", cur_dir, cli_errstr(cli));
3220                 return 1;
3221         }
3222         
3223         d_printf("//%s/%s\n", targetcli->desthost, targetcli->share);
3224         return 0;
3225 }
3226
3227 /* Some constants for completing filename arguments */
3228
3229 #define COMPL_NONE        0          /* No completions */
3230 #define COMPL_REMOTE      1          /* Complete remote filename */
3231 #define COMPL_LOCAL       2          /* Complete local filename */
3232
3233 /* This defines the commands supported by this client.
3234  * NOTE: The "!" must be the last one in the list because it's fn pointer
3235  *       field is NULL, and NULL in that field is used in process_tok()
3236  *       (below) to indicate the end of the list.  crh
3237  */
3238 static struct
3239 {
3240   const char *name;
3241   int (*fn)(void);
3242   const char *description;
3243   char compl_args[2];      /* Completion argument info */
3244 } commands[] = {
3245   {"?",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
3246   {"altname",cmd_altname,"<file> show alt name",{COMPL_NONE,COMPL_NONE}},
3247   {"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}},
3248   {"blocksize",cmd_block,"blocksize <number> (default 20)",{COMPL_NONE,COMPL_NONE}},
3249   {"cancel",cmd_cancel,"<jobid> cancel a print queue entry",{COMPL_NONE,COMPL_NONE}},
3250   {"case_sensitive",cmd_setcase,"toggle the case sensitive flag to server",{COMPL_NONE,COMPL_NONE}},
3251   {"cd",cmd_cd,"[directory] change/report the remote directory",{COMPL_REMOTE,COMPL_NONE}},
3252   {"chmod",cmd_chmod,"<src> <mode> chmod a file using UNIX permission",{COMPL_REMOTE,COMPL_REMOTE}},
3253   {"chown",cmd_chown,"<src> <uid> <gid> chown a file using UNIX uids and gids",{COMPL_REMOTE,COMPL_REMOTE}},
3254   {"close",cmd_close,"<fid> close a file given a fid",{COMPL_REMOTE,COMPL_REMOTE}},
3255   {"del",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
3256   {"dir",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
3257   {"du",cmd_du,"<mask> computes the total size of the current directory",{COMPL_REMOTE,COMPL_NONE}},
3258   {"exit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
3259   {"get",cmd_get,"<remote name> [local name] get a file",{COMPL_REMOTE,COMPL_LOCAL}},
3260   {"getfacl",cmd_getfacl,"<file name> get the POSIX ACL on a file (UNIX extensions only)",{COMPL_REMOTE,COMPL_LOCAL}},
3261   {"hardlink",cmd_hardlink,"<src> <dest> create a Windows hard link",{COMPL_REMOTE,COMPL_REMOTE}},
3262   {"help",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
3263   {"history",cmd_history,"displays the command history",{COMPL_NONE,COMPL_NONE}},
3264   {"lcd",cmd_lcd,"[directory] change/report the local current working directory",{COMPL_LOCAL,COMPL_NONE}},
3265   {"link",cmd_link,"<oldname> <newname> create a UNIX hard link",{COMPL_REMOTE,COMPL_REMOTE}},
3266   {"lock",cmd_lock,"lock <fnum> [r|w] <hex-start> <hex-len> : set a POSIX lock",{COMPL_REMOTE,COMPL_REMOTE}},
3267   {"lowercase",cmd_lowercase,"toggle lowercasing of filenames for get",{COMPL_NONE,COMPL_NONE}},  
3268   {"ls",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
3269   {"mask",cmd_select,"<mask> mask all filenames against this",{COMPL_REMOTE,COMPL_NONE}},
3270   {"md",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
3271   {"mget",cmd_mget,"<mask> get all the matching files",{COMPL_REMOTE,COMPL_NONE}},
3272   {"mkdir",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
3273   {"more",cmd_more,"<remote name> view a remote file with your pager",{COMPL_REMOTE,COMPL_NONE}},  
3274   {"mput",cmd_mput,"<mask> put all matching files",{COMPL_REMOTE,COMPL_NONE}},
3275   {"newer",cmd_newer,"<file> only mget files newer than the specified local file",{COMPL_LOCAL,COMPL_NONE}},
3276   {"open",cmd_open,"<mask> open a file",{COMPL_REMOTE,COMPL_NONE}},
3277   {"posix", cmd_posix, "turn on all POSIX capabilities", {COMPL_REMOTE,COMPL_NONE}},
3278   {"posix_encrypt",cmd_posix_encrypt,"<domain> <user> <password> start up transport encryption",{COMPL_REMOTE,COMPL_NONE}},
3279   {"posix_open",cmd_posix_open,"<name> 0<mode> open_flags mode open a file using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
3280   {"posix_mkdir",cmd_posix_mkdir,"<name> 0<mode> creates a directory using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
3281   {"posix_rmdir",cmd_posix_rmdir,"<name> removes a directory using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
3282   {"posix_unlink",cmd_posix_unlink,"<name> removes a file using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
3283   {"print",cmd_print,"<file name> print a file",{COMPL_NONE,COMPL_NONE}},
3284   {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput",{COMPL_NONE,COMPL_NONE}},  
3285   {"put",cmd_put,"<local name> [remote name] put a file",{COMPL_LOCAL,COMPL_REMOTE}},
3286   {"pwd",cmd_pwd,"show current remote directory (same as 'cd' with no args)",{COMPL_NONE,COMPL_NONE}},
3287   {"q",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
3288   {"queue",cmd_queue,"show the print queue",{COMPL_NONE,COMPL_NONE}},
3289   {"quit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
3290   {"rd",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
3291   {"recurse",cmd_recurse,"toggle directory recursion for mget and mput",{COMPL_NONE,COMPL_NONE}},  
3292   {"reget",cmd_reget,"<remote name> [local name] get a file restarting at end of local file",{COMPL_REMOTE,COMPL_LOCAL}},
3293   {"rename",cmd_rename,"<src> <dest> rename some files",{COMPL_REMOTE,COMPL_REMOTE}},
3294   {"reput",cmd_reput,"<local name> [remote name] put a file restarting at end of remote file",{COMPL_LOCAL,COMPL_REMOTE}},
3295   {"rm",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
3296   {"rmdir",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
3297   {"showacls",cmd_showacls,"toggle if ACLs are shown or not",{COMPL_NONE,COMPL_NONE}},  
3298   {"setmode",cmd_setmode,"filename <setmode string> change modes of file",{COMPL_REMOTE,COMPL_NONE}},
3299   {"stat",cmd_stat,"filename Do a UNIX extensions stat call on a file",{COMPL_REMOTE,COMPL_REMOTE}},
3300   {"symlink",cmd_symlink,"<oldname> <newname> create a UNIX symlink",{COMPL_REMOTE,COMPL_REMOTE}},
3301   {"tar",cmd_tar,"tar <c|x>[IXFqbgNan] current directory to/from <file name>",{COMPL_NONE,COMPL_NONE}},
3302   {"tarmode",cmd_tarmode,"<full|inc|reset|noreset> tar's behaviour towards archive bits",{COMPL_NONE,COMPL_NONE}},
3303   {"translate",cmd_translate,"toggle text translation for printing",{COMPL_NONE,COMPL_NONE}},
3304   {"unlock",cmd_unlock,"unlock <fnum> <hex-start> <hex-len> : remove a POSIX lock",{COMPL_REMOTE,COMPL_REMOTE}},
3305   {"volume",cmd_volume,"print the volume name",{COMPL_NONE,COMPL_NONE}},
3306   {"vuid",cmd_vuid,"change current vuid",{COMPL_NONE,COMPL_NONE}},
3307   {"wdel",cmd_wdel,"<attrib> <mask> wildcard delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
3308   {"logon",cmd_logon,"establish new logon",{COMPL_NONE,COMPL_NONE}},
3309   {"listconnect",cmd_list_connect,"list open connections",{COMPL_NONE,COMPL_NONE}},
3310   {"showconnect",cmd_show_connect,"display the current active connection",{COMPL_NONE,COMPL_NONE}},
3311   
3312   /* Yes, this must be here, see crh's comment above. */
3313   {"!",NULL,"run a shell command on the local system",{COMPL_NONE,COMPL_NONE}},
3314   {NULL,NULL,NULL,{COMPL_NONE,COMPL_NONE}}
3315 };
3316
3317 /*******************************************************************
3318  Lookup a command string in the list of commands, including 
3319  abbreviations.
3320 ******************************************************************/
3321
3322 static int process_tok(pstring tok)
3323 {
3324         int i = 0, matches = 0;
3325         int cmd=0;
3326         int tok_len = strlen(tok);
3327         
3328         while (commands[i].fn != NULL) {
3329                 if (strequal(commands[i].name,tok)) {
3330                         matches = 1;
3331                         cmd = i;
3332                         break;
3333                 } else if (strnequal(commands[i].name, tok, tok_len)) {
3334                         matches++;
3335                         cmd = i;
3336                 }
3337                 i++;
3338         }
3339   
3340         if (matches == 0)
3341                 return(-1);
3342         else if (matches == 1)
3343                 return(cmd);
3344         else
3345                 return(-2);
3346 }
3347
3348 /****************************************************************************
3349  Help.
3350 ****************************************************************************/
3351
3352 static int cmd_help(void)
3353 {
3354         int i=0,j;
3355         pstring buf;
3356         
3357         if (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
3358                 if ((i = process_tok(buf)) >= 0)
3359                         d_printf("HELP %s:\n\t%s\n\n",commands[i].name,commands[i].description);
3360         } else {
3361                 while (commands[i].description) {
3362                         for (j=0; commands[i].description && (j<5); j++) {
3363                                 d_printf("%-15s",commands[i].name);
3364                                 i++;
3365                         }
3366                         d_printf("\n");
3367                 }
3368         }
3369         return 0;
3370 }
3371
3372 /****************************************************************************
3373  Process a -c command string.
3374 ****************************************************************************/
3375
3376 static int process_command_string(char *cmd)
3377 {
3378         pstring line;
3379         const char *ptr;
3380         int rc = 0;
3381
3382         /* establish the connection if not already */
3383         
3384         if (!cli) {
3385                 cli = cli_cm_open(desthost, service, True);
3386                 if (!cli)
3387                         return 0;
3388         }
3389         
3390         while (cmd[0] != '\0')    {
3391                 char *p;
3392                 pstring tok;
3393                 int i;
3394                 
3395                 if ((p = strchr_m(cmd, ';')) == 0) {
3396                         strncpy(line, cmd, 999);
3397                         line[1000] = '\0';
3398                         cmd += strlen(cmd);
3399                 } else {
3400                         if (p - cmd > 999)
3401                                 p = cmd + 999;
3402                         strncpy(line, cmd, p - cmd);
3403                         line[p - cmd] = '\0';
3404                         cmd = p + 1;
3405                 }
3406                 
3407                 /* and get the first part of the command */
3408                 ptr = line;
3409                 if (!next_token_nr(&ptr,tok,NULL,sizeof(tok))) continue;
3410                 
3411                 if ((i = process_tok(tok)) >= 0) {
3412                         rc = commands[i].fn();
3413                 } else if (i == -2) {
3414                         d_printf("%s: command abbreviation ambiguous\n",tok);
3415                 } else {
3416                         d_printf("%s: command not found\n",tok);
3417                 }
3418         }
3419         
3420         return rc;
3421 }       
3422
3423 #define MAX_COMPLETIONS 100
3424
3425 typedef struct {
3426         pstring dirmask;
3427         char **matches;
3428         int count, samelen;
3429         const char *text;
3430         int len;
3431 } completion_remote_t;
3432
3433 static void completion_remote_filter(const char *mnt, file_info *f, const char *mask, void *state)
3434 {
3435         completion_remote_t *info = (completion_remote_t *)state;
3436
3437         if ((info->count < MAX_COMPLETIONS - 1) && (strncmp(info->text, f->name, info->len) == 0) && (strcmp(f->name, ".") != 0) && (strcmp(f->name, "..") != 0)) {
3438                 if ((info->dirmask[0] == 0) && !(f->mode & aDIR))
3439                         info->matches[info->count] = SMB_STRDUP(f->name);
3440                 else {
3441                         pstring tmp;
3442
3443                         if (info->dirmask[0] != 0)
3444                                 pstrcpy(tmp, info->dirmask);
3445                         else
3446                                 tmp[0] = 0;
3447                         pstrcat(tmp, f->name);
3448                         if (f->mode & aDIR)
3449                                 pstrcat(tmp, "/");
3450                         info->matches[info->count] = SMB_STRDUP(tmp);
3451                 }
3452                 if (info->matches[info->count] == NULL)
3453                         return;
3454                 if (f->mode & aDIR)
3455                         smb_readline_ca_char(0);
3456
3457                 if (info->count == 1)
3458                         info->samelen = strlen(info->matches[info->count]);
3459                 else
3460                         while (strncmp(info->matches[info->count], info->matches[info->count-1], info->samelen) != 0)
3461                                 info->samelen--;
3462                 info->count++;
3463         }
3464 }
3465
3466 static char **remote_completion(const char *text, int len)
3467 {
3468         pstring dirmask;
3469         int i;
3470         completion_remote_t info = { "", NULL, 1, 0, NULL, 0 };
3471
3472         /* can't have non-static intialisation on Sun CC, so do it
3473            at run time here */
3474         info.samelen = len;
3475         info.text = text;
3476         info.len = len;
3477                 
3478         if (len >= MIN(PATH_MAX,sizeof(pstring))) {
3479                 return(NULL);
3480         }
3481
3482         info.matches = SMB_MALLOC_ARRAY(char *,MAX_COMPLETIONS);
3483         if (!info.matches) {
3484                 return NULL;
3485         }
3486
3487         /*
3488          * We're leaving matches[0] free to fill it later with the text to
3489          * display: Either the one single match or the longest common subset
3490          * of the matches.
3491          */
3492         info.matches[0] = NULL;
3493         info.count = 1;
3494
3495         for (i = len-1; i >= 0; i--) {
3496                 if ((text[i] == '/') || (text[i] == CLI_DIRSEP_CHAR)) {
3497                         break;
3498                 }
3499         }
3500
3501         info.text = text+i+1;
3502         info.samelen = info.len = len-i-1;
3503
3504         if (i > 0) {
3505                 strncpy(info.dirmask, text, i+1);
3506                 info.dirmask[i+1] = 0;
3507                 pstr_sprintf(dirmask, "%s%*s*", cur_dir, i-1, text);
3508         } else {
3509                 pstr_sprintf(dirmask, "%s*", cur_dir);
3510         }
3511
3512         if (cli_list(cli, dirmask, aDIR | aSYSTEM | aHIDDEN, completion_remote_filter, &info) < 0)
3513                 goto cleanup;
3514
3515         if (info.count == 1) {
3516
3517                 /*
3518                  * No matches at all, NULL indicates there is nothing
3519                  */
3520
3521                 SAFE_FREE(info.matches[0]);
3522                 SAFE_FREE(info.matches);
3523                 return NULL;
3524         }
3525
3526         if (info.count == 2) {
3527
3528                 /*
3529                  * Exactly one match in matches[1], indicate this is the one
3530                  * in matches[0].
3531                  */
3532
3533                 info.matches[0] = info.matches[1];
3534                 info.matches[1] = NULL;
3535                 info.count -= 1;
3536                 return info.matches;
3537         }
3538
3539         /*
3540          * We got more than one possible match, set the result to the maximum
3541          * common subset
3542          */
3543
3544         info.matches[0] = SMB_STRNDUP(info.matches[1], info.samelen);
3545         info.matches[info.count] = NULL;
3546         return info.matches;
3547
3548 cleanup:
3549         for (i = 0; i < info.count; i++)
3550                 free(info.matches[i]);
3551         free(info.matches);
3552         return NULL;
3553 }
3554
3555 static char **completion_fn(const char *text, int start, int end)
3556 {
3557         smb_readline_ca_char(' ');
3558
3559         if (start) {
3560                 const char *buf, *sp;
3561                 int i;
3562                 char compl_type;
3563
3564                 buf = smb_readline_get_line_buffer();
3565                 if (buf == NULL)
3566                         return NULL;
3567                 
3568                 sp = strchr(buf, ' ');
3569                 if (sp == NULL)
3570                         return NULL;
3571
3572                 for (i = 0; commands[i].name; i++) {
3573                         if ((strncmp(commands[i].name, buf, sp - buf) == 0) &&
3574                             (commands[i].name[sp - buf] == 0)) {
3575                                 break;
3576                         }
3577                 }
3578                 if (commands[i].name == NULL)
3579                         return NULL;
3580
3581                 while (*sp == ' ')
3582                         sp++;
3583
3584                 if (sp == (buf + start))
3585                         compl_type = commands[i].compl_args[0];
3586                 else
3587                         compl_type = commands[i].compl_args[1];
3588
3589                 if (compl_type == COMPL_REMOTE)
3590                         return remote_completion(text, end - start);
3591                 else /* fall back to local filename completion */
3592                         return NULL;
3593         } else {
3594                 char **matches;
3595                 int i, len, samelen = 0, count=1;
3596
3597                 matches = SMB_MALLOC_ARRAY(char *, MAX_COMPLETIONS);
3598                 if (!matches) {
3599                         return NULL;
3600                 }
3601                 matches[0] = NULL;
3602
3603                 len = strlen(text);
3604                 for (i=0;commands[i].fn && count < MAX_COMPLETIONS-1;i++) {
3605                         if (strncmp(text, commands[i].name, len) == 0) {
3606                                 matches[count] = SMB_STRDUP(commands[i].name);
3607                                 if (!matches[count])
3608                                         goto cleanup;
3609                                 if (count == 1)
3610                                         samelen = strlen(matches[count]);
3611                                 else
3612                                         while (strncmp(matches[count], matches[count-1], samelen) != 0)
3613                                                 samelen--;
3614                                 count++;
3615                         }
3616                 }
3617
3618                 switch (count) {
3619                 case 0: /* should never happen */
3620                 case 1:
3621                         goto cleanup;
3622                 case 2:
3623                         matches[0] = SMB_STRDUP(matches[1]);
3624                         break;
3625                 default:
3626                         matches[0] = (char *)SMB_MALLOC(samelen+1);
3627                         if (!matches[0])
3628                                 goto cleanup;
3629                         strncpy(matches[0], matches[1], samelen);
3630                         matches[0][samelen] = 0;
3631                 }
3632                 matches[count] = NULL;
3633                 return matches;
3634
3635 cleanup:
3636                 for (i = 0; i < count; i++)
3637                         free(matches[i]);
3638
3639                 free(matches);
3640                 return NULL;
3641         }
3642 }
3643
3644 /****************************************************************************
3645  Make sure we swallow keepalives during idle time.
3646 ****************************************************************************/
3647
3648 static void readline_callback(void)
3649 {
3650         fd_set fds;
3651         struct timeval timeout;
3652         static time_t last_t;
3653         time_t t;
3654
3655         t = time(NULL);
3656
3657         if (t - last_t < 5)
3658                 return;
3659
3660         last_t = t;
3661
3662  again:
3663
3664         if (cli->fd == -1)
3665                 return;
3666
3667         FD_ZERO(&fds);
3668         FD_SET(cli->fd,&fds);
3669
3670         timeout.tv_sec = 0;
3671         timeout.tv_usec = 0;
3672         sys_select_intr(cli->fd+1,&fds,NULL,NULL,&timeout);
3673                 
3674         /* We deliberately use cli_receive_smb_return_keepalive instead of
3675            client_receive_smb as we want to receive
3676            session keepalives and then drop them here.
3677         */
3678         if (FD_ISSET(cli->fd,&fds)) {
3679                 if (!cli_receive_smb_return_keepalive(cli)) {
3680                         DEBUG(0, ("Read from server failed, maybe it closed the "
3681                                 "connection\n"));
3682                         return;
3683                 }
3684                 goto again;
3685         }
3686       
3687         /* Ping the server to keep the connection alive using SMBecho. */
3688         {
3689                 unsigned char garbage[16];
3690                 memset(garbage, 0xf0, sizeof(garbage));
3691                 cli_echo(cli, garbage, sizeof(garbage));
3692         }
3693 }
3694
3695 /****************************************************************************
3696  Process commands on stdin.
3697 ****************************************************************************/
3698
3699 static int process_stdin(void)
3700 {
3701         const char *ptr;
3702         int rc = 0;
3703
3704         while (1) {
3705                 pstring tok;
3706                 pstring the_prompt;
3707                 char *cline;
3708                 pstring line;
3709                 int i;
3710                 
3711                 /* display a prompt */
3712                 slprintf(the_prompt, sizeof(the_prompt)-1, "smb: %s> ", cur_dir);
3713                 cline = smb_readline(the_prompt, readline_callback, completion_fn);
3714                         
3715                 if (!cline) break;
3716                 
3717                 pstrcpy(line, cline);
3718
3719                 /* special case - first char is ! */
3720                 if (*line == '!') {
3721                         system(line + 1);
3722                         continue;
3723                 }
3724       
3725                 /* and get the first part of the command */
3726                 ptr = line;
3727                 if (!next_token_nr(&ptr,tok,NULL,sizeof(tok))) continue;
3728
3729                 if ((i = process_tok(tok)) >= 0) {
3730                         rc = commands[i].fn();
3731                 } else if (i == -2) {
3732                         d_printf("%s: command abbreviation ambiguous\n",tok);
3733                 } else {
3734                         d_printf("%s: command not found\n",tok);
3735                 }
3736         }
3737         return rc;
3738 }
3739
3740 /****************************************************************************
3741  Process commands from the client.
3742 ****************************************************************************/
3743
3744 static int process(char *base_directory)
3745 {
3746         int rc = 0;
3747
3748         cli = cli_cm_open(desthost, service, True);
3749         if (!cli) {
3750                 return 1;
3751         }
3752
3753         if (*base_directory) {
3754                 rc = do_cd(base_directory);
3755                 if (rc) {
3756                         cli_cm_shutdown();
3757                         return rc;
3758                 }
3759         }
3760         
3761         if (cmdstr) {
3762                 rc = process_command_string(cmdstr);
3763         } else {
3764                 process_stdin();
3765         }
3766   
3767         cli_cm_shutdown();
3768         return rc;
3769 }
3770
3771 /****************************************************************************
3772  Handle a -L query.
3773 ****************************************************************************/
3774
3775 static int do_host_query(char *query_host)
3776 {
3777         cli = cli_cm_open(query_host, "IPC$", True);
3778         if (!cli)
3779                 return 1;
3780
3781         browse_host(True);
3782
3783         if (port != 139) {
3784
3785                 /* Workgroups simply don't make sense over anything
3786                    else but port 139... */
3787
3788                 cli_cm_shutdown();
3789                 cli_cm_set_port( 139 );
3790                 cli = cli_cm_open(query_host, "IPC$", True);
3791         }
3792
3793         if (cli == NULL) {
3794                 d_printf("NetBIOS over TCP disabled -- no workgroup available\n");
3795                 return 1;
3796         }
3797
3798         list_servers(lp_workgroup());
3799
3800         cli_cm_shutdown();
3801         
3802         return(0);
3803 }
3804
3805 /****************************************************************************
3806  Handle a tar operation.
3807 ****************************************************************************/
3808
3809 static int do_tar_op(char *base_directory)
3810 {
3811         int ret;
3812
3813         /* do we already have a connection? */
3814         if (!cli) {
3815                 cli = cli_cm_open(desthost, service, True);
3816                 if (!cli)
3817                         return 1;
3818         }
3819
3820         recurse=True;
3821
3822         if (*base_directory)  {
3823                 ret = do_cd(base_directory);
3824                 if (ret) {
3825                         cli_cm_shutdown();
3826                         return ret;
3827                 }
3828         }
3829         
3830         ret=process_tar();
3831
3832         cli_cm_shutdown();
3833
3834         return(ret);
3835 }
3836
3837 /****************************************************************************
3838  Handle a message operation.
3839 ****************************************************************************/
3840
3841 static int do_message_op(void)
3842 {
3843         struct in_addr ip;
3844         struct nmb_name called, calling;
3845         fstring server_name;
3846         char name_type_hex[10];
3847         int msg_port;
3848         NTSTATUS status;
3849
3850         make_nmb_name(&calling, calling_name, 0x0);
3851         make_nmb_name(&called , desthost, name_type);
3852
3853         fstrcpy(server_name, desthost);
3854         snprintf(name_type_hex, sizeof(name_type_hex), "#%X", name_type);
3855         fstrcat(server_name, name_type_hex);
3856
3857         zero_ip(&ip);
3858         if (have_ip) 
3859                 ip = dest_ip;
3860
3861         /* we can only