r22002: Fix bug #3974, there are still open issues with -N behavior (doc fix next)
[ira/wip.git] / source3 / 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 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25 #include "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         fstring buf;
1793         fstring domain;
1794         fstring user;
1795         fstring password;
1796         NTSTATUS status;
1797
1798         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1799                 d_printf("posix_encrypt domain user password\n");
1800                 return 1;
1801         }
1802         fstrcpy(domain,buf);
1803
1804         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1805                 d_printf("posix_encrypt domain user password\n");
1806                 return 1;
1807         }
1808         fstrcpy(user,buf);
1809
1810         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1811                 d_printf("posix_encrypt domain user password\n");
1812                 return 1;
1813         }
1814         fstrcpy(password,buf);
1815
1816         status = cli_raw_ntlm_smb_encryption_start(cli,
1817                                                 user,
1818                                                 password,
1819                                                 domain);
1820         
1821         if (!NT_STATUS_IS_OK(status)) {
1822                 d_printf("posix_encrypt failed with error %s\n", nt_errstr(status));
1823         } else {
1824                 d_printf("encryption on\n");
1825         }
1826
1827         return 0;
1828 }
1829
1830 /****************************************************************************
1831 ****************************************************************************/
1832
1833 static int cmd_posix_open(void)
1834 {
1835         pstring mask;
1836         pstring buf;
1837         struct cli_state *targetcli;
1838         pstring targetname;
1839         mode_t mode;
1840         int fnum;
1841
1842         pstrcpy(mask,cur_dir);
1843         
1844         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1845                 d_printf("posix_open <filename> 0<mode>\n");
1846                 return 1;
1847         }
1848         pstrcat(mask,buf);
1849         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1850                 d_printf("posix_open <filename> 0<mode>\n");
1851                 return 1;
1852         }
1853         mode = (mode_t)strtol(buf, (char **)NULL, 8);
1854
1855         if (!cli_resolve_path( "", cli, mask, &targetcli, targetname )) {
1856                 d_printf("posix_open %s: %s\n", mask, cli_errstr(cli));
1857                 return 1;
1858         }
1859         
1860         fnum = cli_posix_open(targetcli, targetname, O_CREAT|O_RDWR, mode);
1861         if (fnum == -1) {
1862                 fnum = cli_posix_open(targetcli, targetname, O_CREAT|O_RDONLY, mode);
1863                 if (fnum != -1) {
1864                         d_printf("posix_open file %s: for read/write fnum %d\n", targetname, fnum);
1865                 } else {
1866                         d_printf("Failed to open file %s. %s\n", targetname, cli_errstr(cli));
1867                 }
1868         } else {
1869                 d_printf("posix_open file %s: for read/write fnum %d\n", targetname, fnum);
1870         }
1871
1872         return 0;
1873 }
1874
1875 static int cmd_posix_mkdir(void)
1876 {
1877         pstring mask;
1878         pstring buf;
1879         struct cli_state *targetcli;
1880         pstring targetname;
1881         mode_t mode;
1882         int fnum;
1883
1884         pstrcpy(mask,cur_dir);
1885         
1886         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1887                 d_printf("posix_mkdir <filename> 0<mode>\n");
1888                 return 1;
1889         }
1890         pstrcat(mask,buf);
1891         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1892                 d_printf("posix_mkdir <filename> 0<mode>\n");
1893                 return 1;
1894         }
1895         mode = (mode_t)strtol(buf, (char **)NULL, 8);
1896
1897         if (!cli_resolve_path( "", cli, mask, &targetcli, targetname )) {
1898                 d_printf("posix_mkdir %s: %s\n", mask, cli_errstr(cli));
1899                 return 1;
1900         }
1901
1902         fnum = cli_posix_mkdir(targetcli, targetname, mode);
1903         if (fnum == -1) {
1904                 d_printf("Failed to open file %s. %s\n", targetname, cli_errstr(cli));
1905         } else {
1906                 d_printf("posix_mkdir created directory %s\n", targetname);
1907         }
1908
1909         return 0;
1910 }
1911
1912 static int cmd_posix_unlink(void)
1913 {
1914         pstring mask;
1915         pstring buf;
1916         struct cli_state *targetcli;
1917         pstring targetname;
1918
1919         pstrcpy(mask,cur_dir);
1920         
1921         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1922                 d_printf("posix_unlink <filename>\n");
1923                 return 1;
1924         }
1925         pstrcat(mask,buf);
1926
1927         if (!cli_resolve_path( "", cli, mask, &targetcli, targetname )) {
1928                 d_printf("posix_unlink %s: %s\n", mask, cli_errstr(cli));
1929                 return 1;
1930         }
1931         
1932         if (!cli_posix_unlink(targetcli, targetname)) {
1933                 d_printf("Failed to unlink file %s. %s\n", targetname, cli_errstr(cli));
1934         } else {
1935                 d_printf("posix_unlink deleted file %s\n", targetname);
1936         }
1937
1938         return 0;
1939 }
1940
1941 static int cmd_posix_rmdir(void)
1942 {
1943         pstring mask;
1944         pstring buf;
1945         struct cli_state *targetcli;
1946         pstring targetname;
1947
1948         pstrcpy(mask,cur_dir);
1949         
1950         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1951                 d_printf("posix_rmdir <filename>\n");
1952                 return 1;
1953         }
1954         pstrcat(mask,buf);
1955
1956         if (!cli_resolve_path( "", cli, mask, &targetcli, targetname)) {
1957                 d_printf("posix_rmdir %s: %s\n", mask, cli_errstr(cli));
1958                 return 1;
1959         }
1960         
1961         if (!cli_posix_rmdir(targetcli, targetname)) {
1962                 d_printf("Failed to unlink directory %s. %s\n", targetname, cli_errstr(cli));
1963         } else {
1964                 d_printf("posix_rmdir deleted directory %s\n", targetname);
1965         }
1966
1967         return 0;
1968 }
1969
1970 static int cmd_close(void)
1971 {
1972         fstring buf;
1973         int fnum;
1974
1975         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1976                 d_printf("close <fnum>\n");
1977                 return 1;
1978         }
1979
1980         fnum = atoi(buf);
1981         /* We really should use the targetcli here.... */
1982         if (!cli_close(cli, fnum)) {
1983                 d_printf("close %d: %s\n", fnum, cli_errstr(cli));
1984                 return 1;
1985         }
1986         return 0;
1987 }
1988
1989 static int cmd_posix(void)
1990 {
1991         uint16 major, minor;
1992         uint32 caplow, caphigh;
1993         pstring caps;
1994
1995         if (!SERVER_HAS_UNIX_CIFS(cli)) {
1996                 d_printf("Server doesn't support UNIX CIFS extensions.\n");
1997                 return 1;
1998         }
1999
2000         if (!cli_unix_extensions_version(cli, &major, &minor, &caplow, &caphigh)) {
2001                 d_printf("Can't get UNIX CIFS extensions version from server.\n");
2002                 return 1;
2003         }
2004
2005         d_printf("Server supports CIFS extensions %u.%u\n", (unsigned int)major, (unsigned int)minor);
2006
2007         *caps = '\0';
2008         if (caplow & CIFS_UNIX_FCNTL_LOCKS_CAP) {
2009                 pstrcat(caps, "locks ");
2010         }
2011         if (caplow & CIFS_UNIX_POSIX_ACLS_CAP) {
2012                 pstrcat(caps, "acls ");
2013         }
2014         if (caplow & CIFS_UNIX_XATTTR_CAP) {
2015                 pstrcat(caps, "eas ");
2016         }
2017         if (caplow & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
2018                 pstrcat(caps, "pathnames ");
2019         }
2020         if (caplow & CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP) {
2021                 pstrcat(caps, "posix_path_operations ");
2022         }
2023
2024         if (strlen(caps) > 0 && caps[strlen(caps)-1] == ' ') {
2025                 caps[strlen(caps)-1] = '\0';
2026         }
2027
2028         if (!cli_set_unix_extensions_capabilities(cli, major, minor, caplow, caphigh)) {
2029                 d_printf("Can't set UNIX CIFS extensions capabilities. %s.\n", cli_errstr(cli));
2030                 return 1;
2031         }
2032
2033         d_printf("Selecting server supported CIFS capabilities %s\n", caps);
2034
2035         if (caplow & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
2036                 CLI_DIRSEP_CHAR = '/';
2037                 *CLI_DIRSEP_STR = '/';
2038                 pstrcpy(cur_dir, CLI_DIRSEP_STR);
2039         }
2040
2041         return 0;
2042 }
2043
2044 static int cmd_lock(void)
2045 {
2046         fstring buf;
2047         SMB_BIG_UINT start, len;
2048         enum brl_type lock_type;
2049         int fnum;
2050
2051         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
2052                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
2053                 return 1;
2054         }
2055         fnum = atoi(buf);
2056
2057         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
2058                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
2059                 return 1;
2060         }
2061
2062         if (*buf == 'r' || *buf == 'R') {
2063                 lock_type = READ_LOCK;
2064         } else if (*buf == 'w' || *buf == 'W') {
2065                 lock_type = WRITE_LOCK;
2066         } else {
2067                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
2068                 return 1;
2069         }
2070
2071         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
2072                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
2073                 return 1;
2074         }
2075
2076         start = (SMB_BIG_UINT)strtol(buf, (char **)NULL, 16);
2077
2078         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
2079                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
2080                 return 1;
2081         }
2082
2083         len = (SMB_BIG_UINT)strtol(buf, (char **)NULL, 16);
2084
2085         if (!cli_posix_lock(cli, fnum, start, len, True, lock_type)) {
2086                 d_printf("lock failed %d: %s\n", fnum, cli_errstr(cli));
2087         }
2088
2089         return 0;
2090 }
2091
2092 static int cmd_unlock(void)
2093 {
2094         fstring buf;
2095         SMB_BIG_UINT start, len;
2096         int fnum;
2097
2098         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
2099                 d_printf("unlock <fnum> <hex-start> <hex-len>\n");
2100                 return 1;
2101         }
2102         fnum = atoi(buf);
2103
2104         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
2105                 d_printf("unlock <fnum> <hex-start> <hex-len>\n");
2106                 return 1;
2107         }
2108
2109         start = (SMB_BIG_UINT)strtol(buf, (char **)NULL, 16);
2110
2111         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
2112                 d_printf("unlock <fnum> <hex-start> <hex-len>\n");
2113                 return 1;
2114         }
2115
2116         len = (SMB_BIG_UINT)strtol(buf, (char **)NULL, 16);
2117
2118         if (!cli_posix_unlock(cli, fnum, start, len)) {
2119                 d_printf("unlock failed %d: %s\n", fnum, cli_errstr(cli));
2120         }
2121
2122         return 0;
2123 }
2124
2125
2126 /****************************************************************************
2127  Remove a directory.
2128 ****************************************************************************/
2129
2130 static int cmd_rmdir(void)
2131 {
2132         pstring mask;
2133         pstring buf;
2134         struct cli_state *targetcli;
2135         pstring targetname;
2136   
2137         pstrcpy(mask,cur_dir);
2138         
2139         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
2140                 d_printf("rmdir <dirname>\n");
2141                 return 1;
2142         }
2143         pstrcat(mask,buf);
2144
2145         if ( !cli_resolve_path( "", cli, mask, &targetcli, targetname ) ) {
2146                 d_printf("rmdir %s: %s\n", mask, cli_errstr(cli));
2147                 return 1;
2148         }
2149         
2150         if (!cli_rmdir(targetcli, targetname)) {
2151                 d_printf("%s removing remote directory file %s\n",
2152                          cli_errstr(targetcli),mask);
2153         }
2154         
2155         return 0;
2156 }
2157
2158 /****************************************************************************
2159  UNIX hardlink.
2160 ****************************************************************************/
2161
2162 static int cmd_link(void)
2163 {
2164         pstring oldname,newname;
2165         pstring buf,buf2;
2166         struct cli_state *targetcli;
2167         pstring targetname;
2168   
2169         pstrcpy(oldname,cur_dir);
2170         pstrcpy(newname,cur_dir);
2171   
2172         if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) || 
2173             !next_token_nr(NULL,buf2,NULL, sizeof(buf2))) {
2174                 d_printf("link <oldname> <newname>\n");
2175                 return 1;
2176         }
2177
2178         pstrcat(oldname,buf);
2179         pstrcat(newname,buf2);
2180
2181         if ( !cli_resolve_path( "", cli, oldname, &targetcli, targetname ) ) {
2182                 d_printf("link %s: %s\n", oldname, cli_errstr(cli));
2183                 return 1;
2184         }
2185         
2186         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
2187                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2188                 return 1;
2189         }
2190         
2191         if (!cli_unix_hardlink(targetcli, targetname, newname)) {
2192                 d_printf("%s linking files (%s -> %s)\n", cli_errstr(targetcli), newname, oldname);
2193                 return 1;
2194         }  
2195
2196         return 0;
2197 }
2198
2199 /****************************************************************************
2200  UNIX symlink.
2201 ****************************************************************************/
2202
2203 static int cmd_symlink(void)
2204 {
2205         pstring oldname,newname;
2206         pstring buf,buf2;
2207         struct cli_state *targetcli;
2208         pstring targetname;
2209   
2210         if (!SERVER_HAS_UNIX_CIFS(cli)) {
2211                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2212                 return 1;
2213         }
2214
2215         pstrcpy(newname,cur_dir);
2216         
2217         if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) || 
2218             !next_token_nr(NULL,buf2,NULL, sizeof(buf2))) {
2219                 d_printf("symlink <oldname> <newname>\n");
2220                 return 1;
2221         }
2222
2223         pstrcpy(oldname,buf);
2224         pstrcat(newname,buf2);
2225
2226         if ( !cli_resolve_path( "", cli, oldname, &targetcli, targetname ) ) {
2227                 d_printf("link %s: %s\n", oldname, cli_errstr(cli));
2228                 return 1;
2229         }
2230
2231         if (!cli_unix_symlink(targetcli, targetname, newname)) {
2232                 d_printf("%s symlinking files (%s -> %s)\n",
2233                         cli_errstr(targetcli), newname, targetname);
2234                 return 1;
2235         } 
2236
2237         return 0;
2238 }
2239
2240 /****************************************************************************
2241  UNIX chmod.
2242 ****************************************************************************/
2243
2244 static int cmd_chmod(void)
2245 {
2246         pstring src;
2247         mode_t mode;
2248         pstring buf, buf2;
2249         struct cli_state *targetcli;
2250         pstring targetname;
2251   
2252         pstrcpy(src,cur_dir);
2253         
2254         if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) || 
2255             !next_token_nr(NULL,buf2,NULL, sizeof(buf2))) {
2256                 d_printf("chmod mode file\n");
2257                 return 1;
2258         }
2259
2260         mode = (mode_t)strtol(buf, NULL, 8);
2261         pstrcat(src,buf2);
2262
2263         if ( !cli_resolve_path( "", cli, src, &targetcli, targetname ) ) {
2264                 d_printf("chmod %s: %s\n", src, cli_errstr(cli));
2265                 return 1;
2266         }
2267         
2268         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
2269                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2270                 return 1;
2271         }
2272         
2273         if (!cli_unix_chmod(targetcli, targetname, mode)) {
2274                 d_printf("%s chmod file %s 0%o\n",
2275                         cli_errstr(targetcli), src, (unsigned int)mode);
2276                 return 1;
2277         } 
2278
2279         return 0;
2280 }
2281
2282 static const char *filetype_to_str(mode_t mode)
2283 {
2284         if (S_ISREG(mode)) {
2285                 return "regular file";
2286         } else if (S_ISDIR(mode)) {
2287                 return "directory";
2288         } else 
2289 #ifdef S_ISCHR
2290         if (S_ISCHR(mode)) {
2291                 return "character device";
2292         } else
2293 #endif
2294 #ifdef S_ISBLK
2295         if (S_ISBLK(mode)) {
2296                 return "block device";
2297         } else
2298 #endif
2299 #ifdef S_ISFIFO
2300         if (S_ISFIFO(mode)) {
2301                 return "fifo";
2302         } else
2303 #endif
2304 #ifdef S_ISLNK
2305         if (S_ISLNK(mode)) {
2306                 return "symbolic link";
2307         } else
2308 #endif
2309 #ifdef S_ISSOCK
2310         if (S_ISSOCK(mode)) {
2311                 return "socket";
2312         } else
2313 #endif
2314         return "";
2315 }
2316
2317 static char rwx_to_str(mode_t m, mode_t bt, char ret)
2318 {
2319         if (m & bt) {
2320                 return ret;
2321         } else {
2322                 return '-';
2323         }
2324 }
2325
2326 static char *unix_mode_to_str(char *s, mode_t m)
2327 {
2328         char *p = s;
2329         const char *str = filetype_to_str(m);
2330
2331         switch(str[0]) {
2332                 case 'd':
2333                         *p++ = 'd';
2334                         break;
2335                 case 'c':
2336                         *p++ = 'c';
2337                         break;
2338                 case 'b':
2339                         *p++ = 'b';
2340                         break;
2341                 case 'f':
2342                         *p++ = 'p';
2343                         break;
2344                 case 's':
2345                         *p++ = str[1] == 'y' ? 'l' : 's';
2346                         break;
2347                 case 'r':
2348                 default:
2349                         *p++ = '-';
2350                         break;
2351         }
2352         *p++ = rwx_to_str(m, S_IRUSR, 'r');
2353         *p++ = rwx_to_str(m, S_IWUSR, 'w');
2354         *p++ = rwx_to_str(m, S_IXUSR, 'x');
2355         *p++ = rwx_to_str(m, S_IRGRP, 'r');
2356         *p++ = rwx_to_str(m, S_IWGRP, 'w');
2357         *p++ = rwx_to_str(m, S_IXGRP, 'x');
2358         *p++ = rwx_to_str(m, S_IROTH, 'r');
2359         *p++ = rwx_to_str(m, S_IWOTH, 'w');
2360         *p++ = rwx_to_str(m, S_IXOTH, 'x');
2361         *p++ = '\0';
2362         return s;
2363 }
2364
2365 /****************************************************************************
2366  Utility function for UNIX getfacl.
2367 ****************************************************************************/
2368
2369 static char *perms_to_string(fstring permstr, unsigned char perms)
2370 {
2371         fstrcpy(permstr, "---");
2372         if (perms & SMB_POSIX_ACL_READ) {
2373                 permstr[0] = 'r';
2374         }
2375         if (perms & SMB_POSIX_ACL_WRITE) {
2376                 permstr[1] = 'w';
2377         }
2378         if (perms & SMB_POSIX_ACL_EXECUTE) {
2379                 permstr[2] = 'x';
2380         }
2381         return permstr;
2382 }
2383
2384 /****************************************************************************
2385  UNIX getfacl.
2386 ****************************************************************************/
2387
2388 static int cmd_getfacl(void)
2389 {
2390         pstring src, name;
2391         uint16 major, minor;
2392         uint32 caplow, caphigh;
2393         char *retbuf = NULL;
2394         size_t rb_size = 0;
2395         SMB_STRUCT_STAT sbuf;
2396         uint16 num_file_acls = 0;
2397         uint16 num_dir_acls = 0;
2398         uint16 i;
2399         struct cli_state *targetcli;
2400         pstring targetname;
2401  
2402         pstrcpy(src,cur_dir);
2403         
2404         if (!next_token_nr(NULL,name,NULL,sizeof(name))) {
2405                 d_printf("stat file\n");
2406                 return 1;
2407         }
2408
2409         pstrcat(src,name);
2410         
2411         if ( !cli_resolve_path( "", cli, src, &targetcli, targetname ) ) {
2412                 d_printf("stat %s: %s\n", src, cli_errstr(cli));
2413                 return 1;
2414         }
2415         
2416         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
2417                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2418                 return 1;
2419         }
2420         
2421         if (!cli_unix_extensions_version(targetcli, &major, &minor, &caplow, &caphigh)) {
2422                 d_printf("Can't get UNIX CIFS version from server.\n");
2423                 return 1;
2424         }
2425
2426         if (!(caplow & CIFS_UNIX_POSIX_ACLS_CAP)) {
2427                 d_printf("This server supports UNIX extensions but doesn't support POSIX ACLs.\n");
2428                 return 1;
2429         }
2430
2431         if (!cli_unix_stat(targetcli, targetname, &sbuf)) {
2432                 d_printf("%s getfacl doing a stat on file %s\n",
2433                         cli_errstr(targetcli), src);
2434                 return 1;
2435         } 
2436
2437         if (!cli_unix_getfacl(targetcli, targetname, &rb_size, &retbuf)) {
2438                 d_printf("%s getfacl file %s\n",
2439                         cli_errstr(targetcli), src);
2440                 return 1;
2441         } 
2442
2443         /* ToDo : Print out the ACL values. */
2444         if (SVAL(retbuf,0) != SMB_POSIX_ACL_VERSION || rb_size < 6) {
2445                 d_printf("getfacl file %s, unknown POSIX acl version %u.\n",
2446                         src, (unsigned int)CVAL(retbuf,0) );
2447                 SAFE_FREE(retbuf);
2448                 return 1;
2449         }
2450
2451         num_file_acls = SVAL(retbuf,2);
2452         num_dir_acls = SVAL(retbuf,4);
2453         if (rb_size != SMB_POSIX_ACL_HEADER_SIZE + SMB_POSIX_ACL_ENTRY_SIZE*(num_file_acls+num_dir_acls)) {
2454                 d_printf("getfacl file %s, incorrect POSIX acl buffer size (should be %u, was %u).\n",
2455                         src,
2456                         (unsigned int)(SMB_POSIX_ACL_HEADER_SIZE + SMB_POSIX_ACL_ENTRY_SIZE*(num_file_acls+num_dir_acls)),
2457                         (unsigned int)rb_size);
2458
2459                 SAFE_FREE(retbuf);
2460                 return 1;
2461         }
2462
2463         d_printf("# file: %s\n", src);
2464         d_printf("# owner: %u\n# group: %u\n", (unsigned int)sbuf.st_uid, (unsigned int)sbuf.st_gid);
2465
2466         if (num_file_acls == 0 && num_dir_acls == 0) {
2467                 d_printf("No acls found.\n");
2468         }
2469
2470         for (i = 0; i < num_file_acls; i++) {
2471                 uint32 uorg;
2472                 fstring permstring;
2473                 unsigned char tagtype = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE));
2474                 unsigned char perms = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+1);
2475
2476                 switch(tagtype) {
2477                         case SMB_POSIX_ACL_USER_OBJ:
2478                                 d_printf("user::");
2479                                 break;
2480                         case SMB_POSIX_ACL_USER:
2481                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
2482                                 d_printf("user:%u:", uorg);
2483                                 break;
2484                         case SMB_POSIX_ACL_GROUP_OBJ:
2485                                 d_printf("group::");
2486                                 break;
2487                         case SMB_POSIX_ACL_GROUP:
2488                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
2489                                 d_printf("group:%u", uorg);
2490                                 break;
2491                         case SMB_POSIX_ACL_MASK:
2492                                 d_printf("mask::");
2493                                 break;
2494                         case SMB_POSIX_ACL_OTHER:
2495                                 d_printf("other::");
2496                                 break;
2497                         default:
2498                                 d_printf("getfacl file %s, incorrect POSIX acl tagtype (%u).\n",
2499                                         src, (unsigned int)tagtype );
2500                                 SAFE_FREE(retbuf);
2501                                 return 1;
2502                 }
2503
2504                 d_printf("%s\n", perms_to_string(permstring, perms));
2505         }
2506
2507         for (i = 0; i < num_dir_acls; i++) {
2508                 uint32 uorg;
2509                 fstring permstring;
2510                 unsigned char tagtype = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE));
2511                 unsigned char perms = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+1);
2512
2513                 switch(tagtype) {
2514                         case SMB_POSIX_ACL_USER_OBJ:
2515                                 d_printf("default:user::");
2516                                 break;
2517                         case SMB_POSIX_ACL_USER:
2518                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+2);
2519                                 d_printf("default:user:%u:", uorg);
2520                                 break;
2521                         case SMB_POSIX_ACL_GROUP_OBJ:
2522                                 d_printf("default:group::");
2523                                 break;
2524                         case SMB_POSIX_ACL_GROUP:
2525                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+2);
2526                                 d_printf("default:group:%u", uorg);
2527                                 break;
2528                         case SMB_POSIX_ACL_MASK:
2529                                 d_printf("default:mask::");
2530                                 break;
2531                         case SMB_POSIX_ACL_OTHER:
2532                                 d_printf("default:other::");
2533                                 break;
2534                         default:
2535                                 d_printf("getfacl file %s, incorrect POSIX acl tagtype (%u).\n",
2536                                         src, (unsigned int)tagtype );
2537                                 SAFE_FREE(retbuf);
2538                                 return 1;
2539                 }
2540
2541                 d_printf("%s\n", perms_to_string(permstring, perms));
2542         }
2543
2544         SAFE_FREE(retbuf);
2545         return 0;
2546 }
2547
2548 /****************************************************************************
2549  UNIX stat.
2550 ****************************************************************************/
2551
2552 static int cmd_stat(void)
2553 {
2554         pstring src, name;
2555         fstring mode_str;
2556         SMB_STRUCT_STAT sbuf;
2557         struct cli_state *targetcli;
2558         struct tm *lt;
2559         pstring targetname;
2560  
2561         if (!SERVER_HAS_UNIX_CIFS(cli)) {
2562                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2563                 return 1;
2564         }
2565
2566         pstrcpy(src,cur_dir);
2567         
2568         if (!next_token_nr(NULL,name,NULL,sizeof(name))) {
2569                 d_printf("stat file\n");
2570                 return 1;
2571         }
2572
2573         pstrcat(src,name);
2574
2575         
2576         if ( !cli_resolve_path( "", cli, src, &targetcli, targetname ) ) {
2577                 d_printf("stat %s: %s\n", src, cli_errstr(cli));
2578                 return 1;
2579         }
2580         
2581         if (!cli_unix_stat(targetcli, targetname, &sbuf)) {
2582                 d_printf("%s stat file %s\n",
2583                         cli_errstr(targetcli), src);
2584                 return 1;
2585         } 
2586
2587         /* Print out the stat values. */
2588         d_printf("File: %s\n", src);
2589         d_printf("Size: %-12.0f\tBlocks: %u\t%s\n",
2590                 (double)sbuf.st_size,
2591                 (unsigned int)sbuf.st_blocks,
2592                 filetype_to_str(sbuf.st_mode));
2593
2594 #if defined(S_ISCHR) && defined(S_ISBLK)
2595         if (S_ISCHR(sbuf.st_mode) || S_ISBLK(sbuf.st_mode)) {
2596                 d_printf("Inode: %.0f\tLinks: %u\tDevice type: %u,%u\n",
2597                         (double)sbuf.st_ino,
2598                         (unsigned int)sbuf.st_nlink,
2599                         unix_dev_major(sbuf.st_rdev),
2600                         unix_dev_minor(sbuf.st_rdev));
2601         } else 
2602 #endif
2603                 d_printf("Inode: %.0f\tLinks: %u\n",
2604                         (double)sbuf.st_ino,
2605                         (unsigned int)sbuf.st_nlink);
2606
2607         d_printf("Access: (0%03o/%s)\tUid: %u\tGid: %u\n",
2608                 ((int)sbuf.st_mode & 0777),
2609                 unix_mode_to_str(mode_str, sbuf.st_mode),
2610                 (unsigned int)sbuf.st_uid, 
2611                 (unsigned int)sbuf.st_gid);
2612
2613         lt = localtime(&sbuf.st_atime);
2614         if (lt) {
2615                 strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
2616         } else {
2617                 fstrcpy(mode_str, "unknown");
2618         }
2619         d_printf("Access: %s\n", mode_str);
2620
2621         lt = localtime(&sbuf.st_mtime);
2622         if (lt) {
2623                 strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
2624         } else {
2625                 fstrcpy(mode_str, "unknown");
2626         }
2627         d_printf("Modify: %s\n", mode_str);
2628
2629         lt = localtime(&sbuf.st_ctime);
2630         if (lt) {
2631                 strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
2632         } else {
2633                 fstrcpy(mode_str, "unknown");
2634         }
2635         d_printf("Change: %s\n", mode_str);
2636         
2637         return 0;
2638 }
2639
2640
2641 /****************************************************************************
2642  UNIX chown.
2643 ****************************************************************************/
2644
2645 static int cmd_chown(void)
2646 {
2647         pstring src;
2648         uid_t uid;
2649         gid_t gid;
2650         pstring buf, buf2, buf3;
2651         struct cli_state *targetcli;
2652         pstring targetname;
2653   
2654         pstrcpy(src,cur_dir);
2655         
2656         if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) || 
2657             !next_token_nr(NULL,buf2,NULL, sizeof(buf2)) ||
2658             !next_token_nr(NULL,buf3,NULL, sizeof(buf3))) {
2659                 d_printf("chown uid gid file\n");
2660                 return 1;
2661         }
2662
2663         uid = (uid_t)atoi(buf);
2664         gid = (gid_t)atoi(buf2);
2665         pstrcat(src,buf3);
2666
2667         if ( !cli_resolve_path( "", cli, src, &targetcli, targetname ) ) {
2668                 d_printf("chown %s: %s\n", src, cli_errstr(cli));
2669                 return 1;
2670         }
2671
2672         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
2673                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2674                 return 1;
2675         }
2676         
2677         if (!cli_unix_chown(targetcli, targetname, uid, gid)) {
2678                 d_printf("%s chown file %s uid=%d, gid=%d\n",
2679                         cli_errstr(targetcli), src, (int)uid, (int)gid);
2680                 return 1;
2681         } 
2682
2683         return 0;
2684 }
2685
2686 /****************************************************************************
2687  Rename some file.
2688 ****************************************************************************/
2689
2690 static int cmd_rename(void)
2691 {
2692         pstring src,dest;
2693         pstring buf,buf2;
2694         struct cli_state *targetcli;
2695         pstring targetname;
2696   
2697         pstrcpy(src,cur_dir);
2698         pstrcpy(dest,cur_dir);
2699         
2700         if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) || 
2701             !next_token_nr(NULL,buf2,NULL, sizeof(buf2))) {
2702                 d_printf("rename <src> <dest>\n");
2703                 return 1;
2704         }
2705
2706         pstrcat(src,buf);
2707         pstrcat(dest,buf2);
2708
2709         if ( !cli_resolve_path( "", cli, src, &targetcli, targetname ) ) {
2710                 d_printf("chown %s: %s\n", src, cli_errstr(cli));
2711                 return 1;
2712         }
2713
2714         if (!cli_rename(targetcli, targetname, dest)) {
2715                 d_printf("%s renaming files\n",cli_errstr(targetcli));
2716                 return 1;
2717         }
2718         
2719         return 0;
2720 }
2721
2722 /****************************************************************************
2723  Print the volume name.
2724 ****************************************************************************/
2725
2726 static int cmd_volume(void)
2727 {
2728         fstring volname;
2729         uint32 serial_num;
2730         time_t create_date;
2731   
2732         if (!cli_get_fs_volume_info(cli, volname, &serial_num, &create_date)) {
2733                 d_printf("Errr %s getting volume info\n",cli_errstr(cli));
2734                 return 1;
2735         }
2736         
2737         d_printf("Volume: |%s| serial number 0x%x\n", volname, (unsigned int)serial_num);
2738         return 0;
2739 }
2740
2741 /****************************************************************************
2742  Hard link files using the NT call.
2743 ****************************************************************************/
2744
2745 static int cmd_hardlink(void)
2746 {
2747         pstring src,dest;
2748         pstring buf,buf2;
2749         struct cli_state *targetcli;
2750         pstring targetname;
2751   
2752         pstrcpy(src,cur_dir);
2753         pstrcpy(dest,cur_dir);
2754         
2755         if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) || 
2756             !next_token_nr(NULL,buf2,NULL, sizeof(buf2))) {
2757                 d_printf("hardlink <src> <dest>\n");
2758                 return 1;
2759         }
2760
2761         pstrcat(src,buf);
2762         pstrcat(dest,buf2);
2763
2764         if ( !cli_resolve_path( "", cli, src, &targetcli, targetname ) ) {
2765                 d_printf("hardlink %s: %s\n", src, cli_errstr(cli));
2766                 return 1;
2767         }
2768         
2769         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
2770                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2771                 return 1;
2772         }
2773         
2774         if (!cli_nt_hardlink(targetcli, targetname, dest)) {
2775                 d_printf("%s doing an NT hard link of files\n",cli_errstr(targetcli));
2776                 return 1;
2777         }
2778         
2779         return 0;
2780 }
2781
2782 /****************************************************************************
2783  Toggle the prompt flag.
2784 ****************************************************************************/
2785
2786 static int cmd_prompt(void)
2787 {
2788         prompt = !prompt;
2789         DEBUG(2,("prompting is now %s\n",prompt?"on":"off"));
2790         
2791         return 1;
2792 }
2793
2794 /****************************************************************************
2795  Set the newer than time.
2796 ****************************************************************************/
2797
2798 static int cmd_newer(void)
2799 {
2800         pstring buf;
2801         BOOL ok;
2802         SMB_STRUCT_STAT sbuf;
2803
2804         ok = next_token_nr(NULL,buf,NULL,sizeof(buf));
2805         if (ok && (sys_stat(buf,&sbuf) == 0)) {
2806                 newer_than = sbuf.st_mtime;
2807                 DEBUG(1,("Getting files newer than %s",
2808                          time_to_asc(newer_than)));
2809         } else {
2810                 newer_than = 0;
2811         }
2812
2813         if (ok && newer_than == 0) {
2814                 d_printf("Error setting newer-than time\n");
2815                 return 1;
2816         }
2817
2818         return 0;
2819 }
2820
2821 /****************************************************************************
2822  Set the archive level.
2823 ****************************************************************************/
2824
2825 static int cmd_archive(void)
2826 {
2827         pstring buf;
2828
2829         if (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
2830                 archive_level = atoi(buf);
2831         } else
2832                 d_printf("Archive level is %d\n",archive_level);
2833
2834         return 0;
2835 }
2836
2837 /****************************************************************************
2838  Toggle the lowercaseflag.
2839 ****************************************************************************/
2840
2841 static int cmd_lowercase(void)
2842 {
2843         lowercase = !lowercase;
2844         DEBUG(2,("filename lowercasing is now %s\n",lowercase?"on":"off"));
2845
2846         return 0;
2847 }
2848
2849 /****************************************************************************
2850  Toggle the case sensitive flag.
2851 ****************************************************************************/
2852
2853 static int cmd_setcase(void)
2854 {
2855         BOOL orig_case_sensitive = cli_set_case_sensitive(cli, False);
2856
2857         cli_set_case_sensitive(cli, !orig_case_sensitive);
2858         DEBUG(2,("filename case sensitivity is now %s\n",!orig_case_sensitive ?
2859                 "on":"off"));
2860
2861         return 0;
2862 }
2863
2864 /****************************************************************************
2865  Toggle the showacls flag.
2866 ****************************************************************************/
2867
2868 static int cmd_showacls(void)
2869 {
2870         showacls = !showacls;
2871         DEBUG(2,("showacls is now %s\n",showacls?"on":"off"));
2872
2873         if (!ctx && showacls)
2874                 ctx = talloc_init("smbclient:showacls");
2875                 if (!ctx) {
2876                         DEBUG( 0, ("cmd_showacls() out of memory.  talloc_init() failed.\n"));
2877         }
2878
2879         return 0;
2880 }
2881
2882
2883 /****************************************************************************
2884  Toggle the recurse flag.
2885 ****************************************************************************/
2886
2887 static int cmd_recurse(void)
2888 {
2889         recurse = !recurse;
2890         DEBUG(2,("directory recursion is now %s\n",recurse?"on":"off"));
2891
2892         return 0;
2893 }
2894
2895 /****************************************************************************
2896  Toggle the translate flag.
2897 ****************************************************************************/
2898
2899 static int cmd_translate(void)
2900 {
2901         translation = !translation;
2902         DEBUG(2,("CR/LF<->LF and print text translation now %s\n",
2903                  translation?"on":"off"));
2904
2905         return 0;
2906 }
2907
2908 /****************************************************************************
2909  Do the lcd command.
2910  ****************************************************************************/
2911
2912 static int cmd_lcd(void)
2913 {
2914         pstring buf;
2915         pstring d;
2916         
2917         if (next_token_nr(NULL,buf,NULL,sizeof(buf)))
2918                 chdir(buf);
2919         DEBUG(2,("the local directory is now %s\n",sys_getwd(d)));
2920
2921         return 0;
2922 }
2923
2924 /****************************************************************************
2925  Get a file restarting at end of local file.
2926  ****************************************************************************/
2927
2928 static int cmd_reget(void)
2929 {
2930         pstring local_name;
2931         pstring remote_name;
2932         char *p;
2933
2934         pstrcpy(remote_name, cur_dir);
2935         pstrcat(remote_name, CLI_DIRSEP_STR);
2936         
2937         p = remote_name + strlen(remote_name);
2938         
2939         if (!next_token_nr(NULL, p, NULL, sizeof(remote_name) - strlen(remote_name))) {
2940                 d_printf("reget <filename>\n");
2941                 return 1;
2942         }
2943         pstrcpy(local_name, p);
2944         clean_name(remote_name);
2945         
2946         next_token_nr(NULL, local_name, NULL, sizeof(local_name));
2947         
2948         return do_get(remote_name, local_name, True);
2949 }
2950
2951 /****************************************************************************
2952  Put a file restarting at end of local file.
2953  ****************************************************************************/
2954
2955 static int cmd_reput(void)
2956 {
2957         pstring local_name;
2958         pstring remote_name;
2959         pstring buf;
2960         char *p = buf;
2961         SMB_STRUCT_STAT st;
2962         
2963         pstrcpy(remote_name, cur_dir);
2964         pstrcat(remote_name, CLI_DIRSEP_STR);
2965   
2966         if (!next_token_nr(NULL, p, NULL, sizeof(buf))) {
2967                 d_printf("reput <filename>\n");
2968                 return 1;
2969         }
2970         pstrcpy(local_name, p);
2971   
2972         if (!file_exist(local_name, &st)) {
2973                 d_printf("%s does not exist\n", local_name);
2974                 return 1;
2975         }
2976
2977         if (next_token_nr(NULL, p, NULL, sizeof(buf)))
2978                 pstrcat(remote_name, p);
2979         else
2980                 pstrcat(remote_name, local_name);
2981         
2982         clean_name(remote_name);
2983
2984         return do_put(remote_name, local_name, True);
2985 }
2986
2987 /****************************************************************************
2988  List a share name.
2989  ****************************************************************************/
2990
2991 static void browse_fn(const char *name, uint32 m, 
2992                       const char *comment, void *state)
2993 {
2994         fstring typestr;
2995
2996         *typestr=0;
2997
2998         switch (m & 7)
2999         {
3000           case STYPE_DISKTREE:
3001             fstrcpy(typestr,"Disk"); break;
3002           case STYPE_PRINTQ:
3003             fstrcpy(typestr,"Printer"); break;
3004           case STYPE_DEVICE:
3005             fstrcpy(typestr,"Device"); break;
3006           case STYPE_IPC:
3007             fstrcpy(typestr,"IPC"); break;
3008         }
3009         /* FIXME: If the remote machine returns non-ascii characters
3010            in any of these fields, they can corrupt the output.  We
3011            should remove them. */
3012         if (!grepable) {
3013                 d_printf("\t%-15s %-10.10s%s\n",
3014                         name,typestr,comment);
3015         } else {
3016                 d_printf ("%s|%s|%s\n",typestr,name,comment);
3017         }
3018 }
3019
3020 static BOOL browse_host_rpc(BOOL sort)
3021 {
3022         NTSTATUS status;
3023         struct rpc_pipe_client *pipe_hnd;
3024         TALLOC_CTX *mem_ctx;
3025         uint32 enum_hnd = 0;
3026         struct srvsvc_NetShareCtr1 ctr1;
3027         union srvsvc_NetShareCtr ctr;
3028         int i;
3029         uint32 level;
3030         uint32 numentries;
3031
3032         mem_ctx = talloc_new(NULL);
3033         if (mem_ctx == NULL) {
3034                 DEBUG(0, ("talloc_new failed\n"));
3035                 return False;
3036         }
3037
3038         pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SRVSVC, &status);
3039
3040         if (pipe_hnd == NULL) {
3041                 DEBUG(10, ("Could not connect to srvsvc pipe: %s\n",
3042                            nt_errstr(status)));
3043                 TALLOC_FREE(mem_ctx);
3044                 return False;
3045         }
3046
3047         ZERO_STRUCT(ctr1);
3048         level = 1;
3049         ctr.ctr1 = &ctr1;
3050
3051         status = rpccli_srvsvc_NetShareEnum(pipe_hnd, mem_ctx, "", &level,
3052                                             &ctr, 0xffffffff, &numentries,
3053                                             &enum_hnd);
3054
3055         if (!NT_STATUS_IS_OK(status)) {
3056                 TALLOC_FREE(mem_ctx);
3057                 cli_rpc_pipe_close(pipe_hnd);
3058                 return False;
3059         }
3060
3061         for (i=0; i<numentries; i++) {
3062                 struct srvsvc_NetShareInfo1 *info = &ctr.ctr1->array[i];
3063                 browse_fn(info->name, info->type, info->comment, NULL);
3064         }
3065
3066         TALLOC_FREE(mem_ctx);
3067         cli_rpc_pipe_close(pipe_hnd);
3068         return True;
3069 }
3070
3071 /****************************************************************************
3072  Try and browse available connections on a host.
3073 ****************************************************************************/
3074
3075 static BOOL browse_host(BOOL sort)
3076 {
3077         int ret;
3078         if (!grepable) {
3079                 d_printf("\n\tSharename       Type      Comment\n");
3080                 d_printf("\t---------       ----      -------\n");
3081         }
3082
3083         if (browse_host_rpc(sort)) {
3084                 return True;
3085         }
3086
3087         if((ret = cli_RNetShareEnum(cli, browse_fn, NULL)) == -1)
3088                 d_printf("Error returning browse list: %s\n", cli_errstr(cli));
3089
3090         return (ret != -1);
3091 }
3092
3093 /****************************************************************************
3094  List a server name.
3095 ****************************************************************************/
3096
3097 static void server_fn(const char *name, uint32 m, 
3098                       const char *comment, void *state)
3099 {
3100         
3101         if (!grepable){
3102                 d_printf("\t%-16s     %s\n", name, comment);
3103         } else {
3104                 d_printf("%s|%s|%s\n",(char *)state, name, comment);
3105         }
3106 }
3107
3108 /****************************************************************************
3109  Try and browse available connections on a host.
3110 ****************************************************************************/
3111
3112 static BOOL list_servers(const char *wk_grp)
3113 {
3114         fstring state;
3115
3116         if (!cli->server_domain)
3117                 return False;
3118
3119         if (!grepable) {
3120                 d_printf("\n\tServer               Comment\n");
3121                 d_printf("\t---------            -------\n");
3122         };
3123         fstrcpy( state, "Server" );
3124         cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_ALL, server_fn,
3125                           state);
3126
3127         if (!grepable) {
3128                 d_printf("\n\tWorkgroup            Master\n");
3129                 d_printf("\t---------            -------\n");
3130         }; 
3131
3132         fstrcpy( state, "Workgroup" );
3133         cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_DOMAIN_ENUM,
3134                           server_fn, state);
3135         return True;
3136 }
3137
3138 /****************************************************************************
3139  Print or set current VUID
3140 ****************************************************************************/
3141
3142 static int cmd_vuid(void)
3143 {
3144         fstring buf;
3145         
3146         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
3147                 d_printf("Current VUID is %d\n", cli->vuid);
3148                 return 0;
3149         }
3150
3151         cli->vuid = atoi(buf);
3152         return 0;
3153 }
3154
3155 /****************************************************************************
3156  Setup a new VUID, by issuing a session setup
3157 ****************************************************************************/
3158
3159 static int cmd_logon(void)
3160 {
3161         pstring l_username, l_password;
3162         pstring buf,buf2;
3163   
3164         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
3165                 d_printf("logon <username> [<password>]\n");
3166                 return 0;
3167         }
3168
3169         pstrcpy(l_username, buf);
3170
3171         if (!next_token_nr(NULL,buf2,NULL,sizeof(buf))) 
3172         {
3173                 char *pass = getpass("Password: ");
3174                 if (pass) 
3175                         pstrcpy(l_password, pass);
3176         } 
3177         else
3178                 pstrcpy(l_password, buf2);
3179
3180         if (!NT_STATUS_IS_OK(cli_session_setup(cli, l_username, 
3181                                                l_password, strlen(l_password),
3182                                                l_password, strlen(l_password),
3183                                                lp_workgroup()))) {
3184                 d_printf("session setup failed: %s\n", cli_errstr(cli));
3185                 return -1;
3186         }
3187
3188         d_printf("Current VUID is %d\n", cli->vuid);
3189         return 0;
3190 }
3191
3192
3193 /****************************************************************************
3194  list active connections
3195 ****************************************************************************/
3196
3197 static int cmd_list_connect(void)
3198 {
3199         cli_cm_display();
3200
3201         return 0;
3202 }
3203
3204 /****************************************************************************
3205  display the current active client connection
3206 ****************************************************************************/
3207
3208 static int cmd_show_connect( void )
3209 {
3210         struct cli_state *targetcli;
3211         pstring targetpath;
3212         
3213         if ( !cli_resolve_path( "", cli, cur_dir, &targetcli, targetpath ) ) {
3214                 d_printf("showconnect %s: %s\n", cur_dir, cli_errstr(cli));
3215                 return 1;
3216         }
3217         
3218         d_printf("//%s/%s\n", targetcli->desthost, targetcli->share);
3219         return 0;
3220 }
3221
3222 /* Some constants for completing filename arguments */
3223
3224 #define COMPL_NONE        0          /* No completions */
3225 #define COMPL_REMOTE      1          /* Complete remote filename */
3226 #define COMPL_LOCAL       2          /* Complete local filename */
3227
3228 /* This defines the commands supported by this client.
3229  * NOTE: The "!" must be the last one in the list because it's fn pointer
3230  *       field is NULL, and NULL in that field is used in process_tok()
3231  *       (below) to indicate the end of the list.  crh
3232  */
3233 static struct
3234 {
3235   const char *name;
3236   int (*fn)(void);
3237   const char *description;
3238   char compl_args[2];      /* Completion argument info */
3239 } commands[] = {
3240   {"?",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
3241   {"altname",cmd_altname,"<file> show alt name",{COMPL_NONE,COMPL_NONE}},
3242   {"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}},
3243   {"blocksize",cmd_block,"blocksize <number> (default 20)",{COMPL_NONE,COMPL_NONE}},
3244   {"cancel",cmd_cancel,"<jobid> cancel a print queue entry",{COMPL_NONE,COMPL_NONE}},
3245   {"case_sensitive",cmd_setcase,"toggle the case sensitive flag to server",{COMPL_NONE,COMPL_NONE}},
3246   {"cd",cmd_cd,"[directory] change/report the remote directory",{COMPL_REMOTE,COMPL_NONE}},
3247   {"chmod",cmd_chmod,"<src> <mode> chmod a file using UNIX permission",{COMPL_REMOTE,COMPL_REMOTE}},
3248   {"chown",cmd_chown,"<src> <uid> <gid> chown a file using UNIX uids and gids",{COMPL_REMOTE,COMPL_REMOTE}},
3249   {"close",cmd_close,"<fid> close a file given a fid",{COMPL_REMOTE,COMPL_REMOTE}},
3250   {"del",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
3251   {"dir",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
3252   {"du",cmd_du,"<mask> computes the total size of the current directory",{COMPL_REMOTE,COMPL_NONE}},
3253   {"exit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
3254   {"get",cmd_get,"<remote name> [local name] get a file",{COMPL_REMOTE,COMPL_LOCAL}},
3255   {"getfacl",cmd_getfacl,"<file name> get the POSIX ACL on a file (UNIX extensions only)",{COMPL_REMOTE,COMPL_LOCAL}},
3256   {"hardlink",cmd_hardlink,"<src> <dest> create a Windows hard link",{COMPL_REMOTE,COMPL_REMOTE}},
3257   {"help",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
3258   {"history",cmd_history,"displays the command history",{COMPL_NONE,COMPL_NONE}},
3259   {"lcd",cmd_lcd,"[directory] change/report the local current working directory",{COMPL_LOCAL,COMPL_NONE}},
3260   {"link",cmd_link,"<oldname> <newname> create a UNIX hard link",{COMPL_REMOTE,COMPL_REMOTE}},
3261   {"lock",cmd_lock,"lock <fnum> [r|w] <hex-start> <hex-len> : set a POSIX lock",{COMPL_REMOTE,COMPL_REMOTE}},
3262   {"lowercase",cmd_lowercase,"toggle lowercasing of filenames for get",{COMPL_NONE,COMPL_NONE}},  
3263   {"ls",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
3264   {"mask",cmd_select,"<mask> mask all filenames against this",{COMPL_REMOTE,COMPL_NONE}},
3265   {"md",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
3266   {"mget",cmd_mget,"<mask> get all the matching files",{COMPL_REMOTE,COMPL_NONE}},
3267   {"mkdir",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
3268   {"more",cmd_more,"<remote name> view a remote file with your pager",{COMPL_REMOTE,COMPL_NONE}},  
3269   {"mput",cmd_mput,"<mask> put all matching files",{COMPL_REMOTE,COMPL_NONE}},
3270   {"newer",cmd_newer,"<file> only mget files newer than the specified local file",{COMPL_LOCAL,COMPL_NONE}},
3271   {"open",cmd_open,"<mask> open a file",{COMPL_REMOTE,COMPL_NONE}},
3272   {"posix", cmd_posix, "turn on all POSIX capabilities", {COMPL_REMOTE,COMPL_NONE}},
3273   {"posix_encrypt",cmd_posix_encrypt,"<domain> <user> <password> start up transport encryption",{COMPL_REMOTE,COMPL_NONE}},
3274   {"posix_open",cmd_posix_open,"<name> 0<mode> open_flags mode open a file using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
3275   {"posix_mkdir",cmd_posix_mkdir,"<name> 0<mode> creates a directory using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
3276   {"posix_rmdir",cmd_posix_rmdir,"<name> removes a directory using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
3277   {"posix_unlink",cmd_posix_unlink,"<name> removes a file using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
3278   {"print",cmd_print,"<file name> print a file",{COMPL_NONE,COMPL_NONE}},
3279   {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput",{COMPL_NONE,COMPL_NONE}},  
3280   {"put",cmd_put,"<local name> [remote name] put a file",{COMPL_LOCAL,COMPL_REMOTE}},
3281   {"pwd",cmd_pwd,"show current remote directory (same as 'cd' with no args)",{COMPL_NONE,COMPL_NONE}},
3282   {"q",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
3283   {"queue",cmd_queue,"show the print queue",{COMPL_NONE,COMPL_NONE}},
3284   {"quit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
3285   {"rd",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
3286   {"recurse",cmd_recurse,"toggle directory recursion for mget and mput",{COMPL_NONE,COMPL_NONE}},  
3287   {"reget",cmd_reget,"<remote name> [local name] get a file restarting at end of local file",{COMPL_REMOTE,COMPL_LOCAL}},
3288   {"rename",cmd_rename,"<src> <dest> rename some files",{COMPL_REMOTE,COMPL_REMOTE}},
3289   {"reput",cmd_reput,"<local name> [remote name] put a file restarting at end of remote file",{COMPL_LOCAL,COMPL_REMOTE}},
3290   {"rm",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
3291   {"rmdir",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
3292   {"showacls",cmd_showacls,"toggle if ACLs are shown or not",{COMPL_NONE,COMPL_NONE}},  
3293   {"setmode",cmd_setmode,"filename <setmode string> change modes of file",{COMPL_REMOTE,COMPL_NONE}},
3294   {"stat",cmd_stat,"filename Do a UNIX extensions stat call on a file",{COMPL_REMOTE,COMPL_REMOTE}},
3295   {"symlink",cmd_symlink,"<oldname> <newname> create a UNIX symlink",{COMPL_REMOTE,COMPL_REMOTE}},
3296   {"tar",cmd_tar,"tar <c|x>[IXFqbgNan] current directory to/from <file name>",{COMPL_NONE,COMPL_NONE}},
3297   {"tarmode",cmd_tarmode,"<full|inc|reset|noreset> tar's behaviour towards archive bits",{COMPL_NONE,COMPL_NONE}},
3298   {"translate",cmd_translate,"toggle text translation for printing",{COMPL_NONE,COMPL_NONE}},
3299   {"unlock",cmd_unlock,"unlock <fnum> <hex-start> <hex-len> : remove a POSIX lock",{COMPL_REMOTE,COMPL_REMOTE}},
3300   {"volume",cmd_volume,"print the volume name",{COMPL_NONE,COMPL_NONE}},
3301   {"vuid",cmd_vuid,"change current vuid",{COMPL_NONE,COMPL_NONE}},
3302   {"wdel",cmd_wdel,"<attrib> <mask> wildcard delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
3303   {"logon",cmd_logon,"establish new logon",{COMPL_NONE,COMPL_NONE}},
3304   {"listconnect",cmd_list_connect,"list open connections",{COMPL_NONE,COMPL_NONE}},
3305   {"showconnect",cmd_show_connect,"display the current active connection",{COMPL_NONE,COMPL_NONE}},
3306   
3307   /* Yes, this must be here, see crh's comment above. */
3308   {"!",NULL,"run a shell command on the local system",{COMPL_NONE,COMPL_NONE}},
3309   {NULL,NULL,NULL,{COMPL_NONE,COMPL_NONE}}
3310 };
3311
3312 /*******************************************************************
3313  Lookup a command string in the list of commands, including 
3314  abbreviations.
3315 ******************************************************************/
3316
3317 static int process_tok(pstring tok)
3318 {
3319         int i = 0, matches = 0;
3320         int cmd=0;
3321         int tok_len = strlen(tok);
3322         
3323         while (commands[i].fn != NULL) {
3324                 if (strequal(commands[i].name,tok)) {
3325                         matches = 1;
3326                         cmd = i;
3327                         break;
3328                 } else if (strnequal(commands[i].name, tok, tok_len)) {
3329                         matches++;
3330                         cmd = i;
3331                 }
3332                 i++;
3333         }
3334   
3335         if (matches == 0)
3336                 return(-1);
3337         else if (matches == 1)
3338                 return(cmd);
3339         else
3340                 return(-2);
3341 }
3342
3343 /****************************************************************************
3344  Help.
3345 ****************************************************************************/
3346
3347 static int cmd_help(void)
3348 {
3349         int i=0,j;
3350         pstring buf;
3351         
3352         if (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
3353                 if ((i = process_tok(buf)) >= 0)
3354                         d_printf("HELP %s:\n\t%s\n\n",commands[i].name,commands[i].description);
3355         } else {
3356                 while (commands[i].description) {
3357                         for (j=0; commands[i].description && (j<5); j++) {
3358                                 d_printf("%-15s",commands[i].name);
3359                                 i++;
3360                         }
3361                         d_printf("\n");
3362                 }
3363         }
3364         return 0;
3365 }
3366
3367 /****************************************************************************
3368  Process a -c command string.
3369 ****************************************************************************/
3370
3371 static int process_command_string(char *cmd)
3372 {
3373         pstring line;
3374         const char *ptr;
3375         int rc = 0;
3376
3377         /* establish the connection if not already */
3378         
3379         if (!cli) {
3380                 cli = cli_cm_open(desthost, service, True);
3381                 if (!cli)
3382                         return 0;
3383         }
3384         
3385         while (cmd[0] != '\0')    {
3386                 char *p;
3387                 pstring tok;
3388                 int i;
3389                 
3390                 if ((p = strchr_m(cmd, ';')) == 0) {
3391                         strncpy(line, cmd, 999);
3392                         line[1000] = '\0';
3393                         cmd += strlen(cmd);
3394                 } else {
3395                         if (p - cmd > 999)
3396                                 p = cmd + 999;
3397                         strncpy(line, cmd, p - cmd);
3398                         line[p - cmd] = '\0';
3399                         cmd = p + 1;
3400                 }
3401                 
3402                 /* and get the first part of the command */
3403                 ptr = line;
3404                 if (!next_token_nr(&ptr,tok,NULL,sizeof(tok))) continue;
3405                 
3406                 if ((i = process_tok(tok)) >= 0) {
3407                         rc = commands[i].fn();
3408                 } else if (i == -2) {
3409                         d_printf("%s: command abbreviation ambiguous\n",tok);
3410                 } else {
3411                         d_printf("%s: command not found\n",tok);
3412                 }
3413         }
3414         
3415         return rc;
3416 }       
3417
3418 #define MAX_COMPLETIONS 100
3419
3420 typedef struct {
3421         pstring dirmask;
3422         char **matches;
3423         int count, samelen;
3424         const char *text;
3425         int len;
3426 } completion_remote_t;
3427
3428 static void completion_remote_filter(const char *mnt, file_info *f, const char *mask, void *state)
3429 {
3430         completion_remote_t *info = (completion_remote_t *)state;
3431
3432         if ((info->count < MAX_COMPLETIONS - 1) && (strncmp(info->text, f->name, info->len) == 0) && (strcmp(f->name, ".") != 0) && (strcmp(f->name, "..") != 0)) {
3433                 if ((info->dirmask[0] == 0) && !(f->mode & aDIR))
3434                         info->matches[info->count] = SMB_STRDUP(f->name);
3435                 else {
3436                         pstring tmp;
3437
3438                         if (info->dirmask[0] != 0)
3439                                 pstrcpy(tmp, info->dirmask);
3440                         else
3441                                 tmp[0] = 0;
3442                         pstrcat(tmp, f->name);
3443                         if (f->mode & aDIR)
3444                                 pstrcat(tmp, "/");
3445                         info->matches[info->count] = SMB_STRDUP(tmp);
3446                 }
3447                 if (info->matches[info->count] == NULL)
3448                         return;
3449                 if (f->mode & aDIR)
3450                         smb_readline_ca_char(0);
3451
3452                 if (info->count == 1)
3453                         info->samelen = strlen(info->matches[info->count]);
3454                 else
3455                         while (strncmp(info->matches[info->count], info->matches[info->count-1], info->samelen) != 0)
3456                                 info->samelen--;
3457                 info->count++;
3458         }
3459 }
3460
3461 static char **remote_completion(const char *text, int len)
3462 {
3463         pstring dirmask;
3464         int i;
3465         completion_remote_t info = { "", NULL, 1, 0, NULL, 0 };
3466
3467         /* can't have non-static intialisation on Sun CC, so do it
3468            at run time here */
3469         info.samelen = len;
3470         info.text = text;
3471         info.len = len;
3472                 
3473         if (len >= MIN(PATH_MAX,sizeof(pstring))) {
3474                 return(NULL);
3475         }
3476
3477         info.matches = SMB_MALLOC_ARRAY(char *,MAX_COMPLETIONS);
3478         if (!info.matches) {
3479                 return NULL;
3480         }
3481
3482         /*
3483          * We're leaving matches[0] free to fill it later with the text to
3484          * display: Either the one single match or the longest common subset
3485          * of the matches.
3486          */
3487         info.matches[0] = NULL;
3488         info.count = 1;
3489
3490         for (i = len-1; i >= 0; i--) {
3491                 if ((text[i] == '/') || (text[i] == CLI_DIRSEP_CHAR)) {
3492                         break;
3493                 }
3494         }
3495
3496         info.text = text+i+1;
3497         info.samelen = info.len = len-i-1;
3498
3499         if (i > 0) {
3500                 strncpy(info.dirmask, text, i+1);
3501                 info.dirmask[i+1] = 0;
3502                 pstr_sprintf(dirmask, "%s%*s*", cur_dir, i-1, text);
3503         } else {
3504                 pstr_sprintf(dirmask, "%s*", cur_dir);
3505         }
3506
3507         if (cli_list(cli, dirmask, aDIR | aSYSTEM | aHIDDEN, completion_remote_filter, &info) < 0)
3508                 goto cleanup;
3509
3510         if (info.count == 1) {
3511
3512                 /*
3513                  * No matches at all, NULL indicates there is nothing
3514                  */
3515
3516                 SAFE_FREE(info.matches[0]);
3517                 SAFE_FREE(info.matches);
3518                 return NULL;
3519         }
3520
3521         if (info.count == 2) {
3522
3523                 /*
3524                  * Exactly one match in matches[1], indicate this is the one
3525                  * in matches[0].
3526                  */
3527
3528                 info.matches[0] = info.matches[1];
3529                 info.matches[1] = NULL;
3530                 info.count -= 1;
3531                 return info.matches;
3532         }
3533
3534         /*
3535          * We got more than one possible match, set the result to the maximum
3536          * common subset
3537          */
3538
3539         info.matches[0] = SMB_STRNDUP(info.matches[1], info.samelen);
3540         info.matches[info.count] = NULL;
3541         return info.matches;
3542
3543 cleanup:
3544         for (i = 0; i < info.count; i++)
3545                 free(info.matches[i]);
3546         free(info.matches);
3547         return NULL;
3548 }
3549
3550 static char **completion_fn(const char *text, int start, int end)
3551 {
3552         smb_readline_ca_char(' ');
3553
3554         if (start) {
3555                 const char *buf, *sp;
3556                 int i;
3557                 char compl_type;
3558
3559                 buf = smb_readline_get_line_buffer();
3560                 if (buf == NULL)
3561                         return NULL;
3562                 
3563                 sp = strchr(buf, ' ');
3564                 if (sp == NULL)
3565                         return NULL;
3566
3567                 for (i = 0; commands[i].name; i++) {
3568                         if ((strncmp(commands[i].name, buf, sp - buf) == 0) &&
3569                             (commands[i].name[sp - buf] == 0)) {
3570                                 break;
3571                         }
3572                 }
3573                 if (commands[i].name == NULL)
3574                         return NULL;
3575
3576                 while (*sp == ' ')
3577                         sp++;
3578
3579                 if (sp == (buf + start))
3580                         compl_type = commands[i].compl_args[0];
3581                 else
3582                         compl_type = commands[i].compl_args[1];
3583
3584                 if (compl_type == COMPL_REMOTE)
3585                         return remote_completion(text, end - start);
3586                 else /* fall back to local filename completion */
3587                         return NULL;
3588         } else {
3589                 char **matches;
3590                 int i, len, samelen = 0, count=1;
3591
3592                 matches = SMB_MALLOC_ARRAY(char *, MAX_COMPLETIONS);
3593                 if (!matches) {
3594                         return NULL;
3595                 }
3596                 matches[0] = NULL;
3597
3598                 len = strlen(text);
3599                 for (i=0;commands[i].fn && count < MAX_COMPLETIONS-1;i++) {
3600                         if (strncmp(text, commands[i].name, len) == 0) {
3601                                 matches[count] = SMB_STRDUP(commands[i].name);
3602                                 if (!matches[count])
3603                                         goto cleanup;
3604                                 if (count == 1)
3605                                         samelen = strlen(matches[count]);
3606                                 else
3607                                         while (strncmp(matches[count], matches[count-1], samelen) != 0)
3608                                                 samelen--;
3609                                 count++;
3610                         }
3611                 }
3612
3613                 switch (count) {
3614                 case 0: /* should never happen */
3615                 case 1:
3616                         goto cleanup;
3617                 case 2:
3618                         matches[0] = SMB_STRDUP(matches[1]);
3619                         break;
3620                 default:
3621                         matches[0] = (char *)SMB_MALLOC(samelen+1);
3622                         if (!matches[0])
3623                                 goto cleanup;
3624                         strncpy(matches[0], matches[1], samelen);
3625                         matches[0][samelen] = 0;
3626                 }
3627                 matches[count] = NULL;
3628                 return matches;
3629
3630 cleanup:
3631                 for (i = 0; i < count; i++)
3632                         free(matches[i]);
3633
3634                 free(matches);
3635                 return NULL;
3636         }
3637 }
3638
3639 /****************************************************************************
3640  Make sure we swallow keepalives during idle time.
3641 ****************************************************************************/
3642
3643 static void readline_callback(void)
3644 {
3645         fd_set fds;
3646         struct timeval timeout;
3647         static time_t last_t;
3648         time_t t;
3649
3650         t = time(NULL);
3651
3652         if (t - last_t < 5)
3653                 return;
3654
3655         last_t = t;
3656
3657  again:
3658
3659         if (cli->fd == -1)
3660                 return;
3661
3662         FD_ZERO(&fds);
3663         FD_SET(cli->fd,&fds);
3664
3665         timeout.tv_sec = 0;
3666         timeout.tv_usec = 0;
3667         sys_select_intr(cli->fd+1,&fds,NULL,NULL,&timeout);
3668                 
3669         /* We deliberately use cli_receive_smb_return_keepalive instead of
3670            client_receive_smb as we want to receive
3671            session keepalives and then drop them here.
3672         */
3673         if (FD_ISSET(cli->fd,&fds)) {
3674                 if (!cli_receive_smb_return_keepalive(cli)) {
3675                         DEBUG(0, ("Read from server failed, maybe it closed the "
3676                                 "connection\n"));
3677                         return;
3678                 }
3679                 goto again;
3680         }
3681       
3682         /* Ping the server to keep the connection alive using SMBecho. */
3683         {
3684                 unsigned char garbage[16];
3685                 memset(garbage, 0xf0, sizeof(garbage));
3686                 cli_echo(cli, garbage, sizeof(garbage));
3687         }
3688 }
3689
3690 /****************************************************************************
3691  Process commands on stdin.
3692 ****************************************************************************/
3693
3694 static int process_stdin(void)
3695 {
3696         const char *ptr;
3697         int rc = 0;
3698
3699         while (1) {
3700                 pstring tok;
3701                 pstring the_prompt;
3702                 char *cline;
3703                 pstring line;
3704                 int i;
3705                 
3706                 /* display a prompt */
3707                 slprintf(the_prompt, sizeof(the_prompt)-1, "smb: %s> ", cur_dir);
3708                 cline = smb_readline(the_prompt, readline_callback, completion_fn);
3709                         
3710                 if (!cline) break;
3711                 
3712                 pstrcpy(line, cline);
3713
3714                 /* special case - first char is ! */
3715                 if (*line == '!') {
3716                         system(line + 1);
3717                         continue;
3718                 }
3719       
3720                 /* and get the first part of the command */
3721                 ptr = line;
3722                 if (!next_token_nr(&ptr,tok,NULL,sizeof(tok))) continue;
3723
3724                 if ((i = process_tok(tok)) >= 0) {
3725                         rc = commands[i].fn();
3726                 } else if (i == -2) {
3727                         d_printf("%s: command abbreviation ambiguous\n",tok);
3728                 } else {
3729                         d_printf("%s: command not found\n",tok);
3730                 }
3731         }
3732         return rc;
3733 }
3734
3735 /****************************************************************************
3736  Process commands from the client.
3737 ****************************************************************************/
3738
3739 static int process(char *base_directory)
3740 {
3741         int rc = 0;
3742
3743         cli = cli_cm_open(desthost, service, True);
3744         if (!cli) {
3745                 return 1;
3746         }
3747
3748         if (*base_directory) {
3749                 rc = do_cd(base_directory);
3750                 if (rc) {
3751                         cli_cm_shutdown();
3752                         return rc;
3753                 }
3754         }
3755         
3756         if (cmdstr) {
3757                 rc = process_command_string(cmdstr);
3758         } else {
3759                 process_stdin();
3760         }
3761   
3762         cli_cm_shutdown();
3763         return rc;
3764 }
3765
3766 /****************************************************************************
3767  Handle a -L query.
3768 ****************************************************************************/
3769
3770 static int do_host_query(char *query_host)
3771 {
3772         cli = cli_cm_open(query_host, "IPC$", True);
3773         if (!cli)
3774                 return 1;
3775
3776         browse_host(True);
3777
3778         if (port != 139) {
3779
3780                 /* Workgroups simply don't make sense over anything
3781                    else but port 139... */
3782
3783                 cli_cm_shutdown();
3784                 cli_cm_set_port( 139 );
3785                 cli = cli_cm_open(query_host, "IPC$", True);
3786         }
3787
3788         if (cli == NULL) {
3789                 d_printf("NetBIOS over TCP disabled -- no workgroup available\n");
3790                 return 1;
3791         }
3792
3793         list_servers(lp_workgroup());
3794
3795         cli_cm_shutdown();
3796         
3797         return(0);
3798 }
3799
3800 /****************************************************************************
3801  Handle a tar operation.
3802 ****************************************************************************/
3803
3804 static int do_tar_op(char *base_directory)
3805 {
3806         int ret;
3807
3808         /* do we already have a connection? */
3809         if (!cli) {
3810                 cli = cli_cm_open(desthost, service, True);
3811                 if (!cli)
3812                         return 1;
3813         }
3814
3815         recurse=True;
3816
3817         if (*base_directory)  {
3818                 ret = do_cd(base_directory);
3819                 if (ret) {
3820                         cli_cm_shutdown();
3821                         return ret;
3822                 }
3823         }
3824         
3825         ret=process_tar();
3826
3827         cli_cm_shutdown();
3828
3829         return(ret);
3830 }
3831
3832 /****************************************************************************
3833  Handle a message operation.
3834 ****************************************************************************/
3835
3836 static int do_message_op(void)
3837 {
3838         struct in_addr ip;
3839         struct nmb_name called, calling;
3840         fstring server_name;
3841         char name_type_hex[10];
3842         int msg_port;
3843
3844         make_nmb_name(&calling, calling_name, 0x0);
3845         make_nmb_name(&called , desthost, name_type);
3846
3847         fstrcpy(server_name, desthost);
3848         snprintf(name_type_hex, sizeof(name_type_hex), "#%X", name_type);
3849         fstrcat(server_name, name_type_hex);
3850
3851         zero_ip(&ip);
3852         if (have_ip) 
3853                 ip = dest_ip;
3854
3855         /* we can only do messages over port 139 (to windows clients at least) */
3856
3857         msg_port = port ? port : 139;
3858
3859         if (!(cli=cli_initialise()) || (cli_set_port(cli, msg_port) != msg_port) ||
3860             !cli_connect(cli, server_name, &ip)) {
3861                 d_printf("Connection to %s failed\n", desthost);
3862                 return 1;
3863         }
3864
3865         if (!cli_session_request(cli, &calling, &called)) {
3866                 d_printf("session request failed\n");
3867                 cli_cm_shutdown();
3868                 return 1;
3869         }
3870
3871         send_message();
3872         cli_cm_shutdown();
3873
3874         return 0;
3875 }
3876
3877
3878 /****************************************************************************
3879   main program
3880 ****************************************************************************/
3881
3882  int main(int argc,char *argv[])
3883 {
3884         pstring base_directory;
3885         int opt;
3886         pstring query_host;
3887         BOOL message = False;
3888         pstring term_code;
3889         static const char *new_name_resolve_order = NULL;
3890         poptContext pc;
3891         char *p;
3892         int rc = 0;
3893         fstring new_workgroup;
3894         BOOL tar_opt = False;
3895         BOOL service_opt = False;
3896         struct poptOption long_options[] = {
3897                 POPT_AUTOHELP
3898
3899                 { "name-resolve", 'R', POPT_ARG_STRING, &new_name_resolve_order, 'R', "Use these name resolution services only", "NAME-RESOLVE-ORDER" },
3900                 { "message", 'M', POPT_ARG_STRING, NULL, 'M', "Send message", "HOST" },
3901                 { "ip-address", 'I', POPT_ARG_STRING, NULL, 'I', "Use this IP to connect to", "IP" },
3902                 { "stderr", 'E', POPT_ARG_NONE, NULL, 'E', "Write messages to stderr instead of stdout" },
3903                 { "list", 'L', POPT_ARG_STRING, NULL, 'L', "Get a list of shares available on a host", "HOST" },
3904                 { "terminal", 't', POPT_ARG_STRING, NULL, 't', "Terminal I/O code {sjis|euc|jis7|jis8|junet|hex}", "CODE" },
3905                 { "max-protocol", 'm', POPT_ARG_STRING, NULL, 'm', "Set the max protocol level", "LEVEL" },
3906                 { "tar", 'T', POPT_ARG_STRING, NULL, 'T', "Command line tar", "<c|x>IXFqgbNan" },
3907                 { "directory", 'D', POPT_ARG_STRING, NULL, 'D', "Start from directory", "DIR" },
3908                 { "command", 'c', POPT_ARG_STRING, &cmdstr, 'c', "Execute semicolon separated commands" }, 
3909                 { "send-buffer", 'b', POPT_ARG_INT, &io_bufsize, 'b', "Changes the transmit/send buffer", "BYTES" },
3910                 { "port", 'p', POPT_ARG_INT, &port, 'p', "Port to connect to", "PORT" },
3911                 { "grepable", 'g', POPT_ARG_NONE, NULL, 'g', "Produce grepable output" },
3912                 POPT_COMMON_SAMBA
3913                 POPT_COMMON_CONNECTION
3914                 POPT_COMMON_CREDENTIALS
3915                 POPT_TABLEEND
3916         };
3917         
3918         load_case_tables();
3919
3920 #ifdef KANJI
3921         pstrcpy(term_code, KANJI);
3922 #else /* KANJI */
3923         *term_code = 0;
3924 #endif /* KANJI */
3925
3926         *query_host = 0;
3927         *base_directory = 0;
3928         
3929         /* initialize the workgroup name so we can determine whether or 
3930            not it was set by a command line option */
3931            
3932         set_global_myworkgroup( "" );
3933         set_global_myname( "" );
3934
3935         /* set default debug level to 0 regardless of what smb.conf sets */
3936         setup_logging( "smbclient", True );
3937         DEBUGLEVEL_CLASS[DBGC_ALL] = 1;
3938         if ((dbf = x_fdup(x_stderr))) {
3939                 x_setbuf( dbf, NULL );
3940         }
3941
3942         /* skip argv(0) */
3943         pc = poptGetContext("smbclient", argc, (const char **) argv, long_options, 0);
3944         poptSetOtherOptionHelp(pc, "service <password>");
3945
3946         in_client = True;   /* Make sure that we tell lp_load we are */
3947
3948         while ((opt = poptGetNextOpt(pc)) != -1) {
3949
3950                 /* if the tar option has been called previouslt, now we need to eat out the leftovers */
3951                 /* I see no other way to keep things sane --SSS */
3952                 if (tar_opt == True) {
3953                         while (poptPeekArg(pc)) {
3954                                 poptGetArg(pc);
3955                         }
3956                         tar_opt = False;
3957                 }
3958
3959                 /* if the service has not yet been specified lets see if it is available in the popt stack */
3960                 if (!service_opt && poptPeekArg(pc)) {
3961                         pstrcpy(service, poptGetArg(pc));
3962                         /* Convert any '/' characters in the service name to '\' characters */
3963                         string_replace(service, '/','\\');
3964
3965                         if (count_chars(service,'\\') < 3) {
3966                                 d_printf("\n%s: Not enough '\\' characters in service\n",service);
3967                                 poptPrintUsage(pc, stderr, 0);
3968                                 exit(1);
3969                         }
3970                         service_opt = True;
3971                 }
3972
3973                 /* if the service has already been retrieved then check if we have also a password */
3974                 if (service_opt && (!cmdline_auth_info.got_pass) && poptPeekArg(pc)) {
3975                         pstrcpy(cmdline_auth_info.password, poptGetArg(pc));
3976                         cmdline_auth_info.got_pass = True;
3977                 }
3978         
3979                 switch (opt) {
3980                 case 'M':
3981                         /* Messages are sent to NetBIOS name type 0x3
3982                          * (Messenger Service).  Make sure we default
3983                          * to port 139 instead of port 445. srl,crh
3984                          */
3985                         name_type = 0x03; 
3986                         cli_cm_set_dest_name_type( name_type );
3987                         pstrcpy(desthost,poptGetOptArg(pc));
3988                         if( !port )
3989                                 cli_cm_set_port( 139 );
3990                         message = True;
3991                         break;
3992                 case 'I':
3993                         {
3994                                 dest_ip = *interpret_addr2(poptGetOptArg(pc));
3995                                 if (is_zero_ip(dest_ip))
3996                                         exit(1);
3997                                 have_ip = True;
3998
3999                                 cli_cm_set_dest_ip( dest_ip );
4000                         }
4001                         break;
4002                 case 'E':
4003                         if (dbf) {
4004                                 x_fclose(dbf);
4005                         }
4006                         dbf = x_stderr;
4007                         display_set_stderr();
4008                         break;
4009
4010                 case 'L':
4011                         pstrcpy(query_host, poptGetOptArg(pc));
4012                         break;
4013                 case 't':
4014                         pstrcpy(term_code, poptGetOptArg(pc));
4015                         break;
4016                 case 'm':
4017                         max_protocol = interpret_protocol(poptGetOptArg(pc), max_protocol);
4018                         break;
4019                 case 'T':
4020                         /* We must use old option processing for this. Find the
4021                          * position of the -T option in the raw argv[]. */
4022                         {
4023                                 int i, optnum;
4024                                 for (i = 1; i < argc; i++) {
4025                                         if (strncmp("-T", argv[i],2)==0)
4026                                                 break;
4027                                 }
4028                                 i++;
4029                                 if (!(optnum = tar_parseargs(argc, argv, poptGetOptArg(pc), i))) {
4030                                         poptPrintUsage(pc, stderr, 0);
4031                                         exit(1);
4032                                 }
4033                         }
4034                         /* this must be the last option, mark we have parsed it so that we know we have */
4035                         tar_opt = True;
4036                         break;
4037                 case 'D':
4038                         pstrcpy(base_directory,poptGetOptArg(pc));
4039                         break;
4040                 case 'g':
4041                         grepable=True;
4042                         break;
4043                 }
4044         }
4045
4046         /* We may still have some leftovers after the last popt option has been called */
4047         if (tar_opt == True) {
4048                 while (poptPeekArg(pc)) {
4049                         poptGetArg(pc);
4050                 }
4051                 tar_opt = False;
4052         }
4053
4054         /* if the service has not yet been specified lets see if it is available in the popt stack */
4055         if (!service_opt && poptPeekArg(pc)) {
4056                 pstrcpy(service, poptGetArg(pc));
4057                 /* Convert any '/' characters in the service name to '\' characters */
4058                 string_replace(service, '/','\\');
4059
4060                 if (count_chars(service,'\\') < 3) {
4061                         d_printf("\n%s: Not enough '\\' characters in service\n",service);
4062                         poptPrintUsage(pc, stderr, 0);
4063                         exit(1);
4064                 }
4065                 service_opt = True;
4066         }
4067
4068         /* if the service has already been retrieved then check if we have also a password */
4069         if (service_opt && (!cmdline_auth_info.got_pass) && poptPeekArg(pc)) {
4070                 pstrcpy(cmdline_auth_info.password, poptGetArg(pc));
4071                 cmdline_auth_info.got_pass = True;
4072         }
4073         
4074         /* check for the -P option */
4075
4076         if ( port != 0 )
4077                 cli_cm_set_port( port );
4078
4079         /*
4080          * Don't load debug level from smb.conf. It should be
4081          * set by cmdline arg or remain default (0)
4082          */
4083         AllowDebugChange = False;
4084         
4085         /* save the workgroup...
4086         
4087            FIXME!! do we need to do this for other options as well 
4088            (or maybe a generic way to keep lp_load() from overwriting 
4089            everything)?  */
4090         
4091         fstrcpy( new_workgroup, lp_workgroup() );
4092         pstrcpy( calling_name, global_myname() );
4093         
4094         if ( override_logfile )
4095                 setup_logging( lp_logfile(), False );
4096         
4097         if (!lp_load(dyn_CONFIGFILE,True,False,False,True)) {
4098                 fprintf(stderr, "%s: Can't load %s - run testparm to debug it\n",
4099                         argv[0], dyn_CONFIGFILE);
4100         }
4101         
4102         load_interfaces();
4103         
4104         if ( strlen(new_workgroup) != 0 )
4105                 set_global_myworkgroup( new_workgroup );
4106
4107         if ( strlen(calling_name) != 0 )
4108                 set_global_myname( calling_name );
4109         else
4110                 pstrcpy( calling_name, global_myname() );
4111
4112         init_names();
4113
4114         if(new_name_resolve_order)
4115                 lp_set_name_resolve_order(new_name_resolve_order);
4116
4117         if (!tar_type && !*query_host && !*service && !message) {
4118                 poptPrintUsage(pc, stderr, 0);
4119                 exit(1);
4120         }
4121
4122         poptFreeContext(pc);
4123
4124         /* store the username an password for dfs support */
4125
4126         cli_cm_set_credentials( &cmdline_auth_info );
4127         pstrcpy(username, cmdline_auth_info.username);
4128
4129         DEBUG(3,("Client started (version %s).\n", SAMBA_VERSION_STRING));
4130
4131         if (tar_type) {
4132                 if (cmdstr)
4133                         process_command_string(cmdstr);
4134                 return do_tar_op(base_directory);
4135         }
4136
4137         if (*query_host) {
4138                 char *qhost = query_host;
4139                 char *slash;
4140
4141                 while (*qhost == '\\' || *qhost == '/')
4142                         qhost++;
4143
4144                 if ((slash = strchr_m(qhost, '/'))
4145                     || (slash = strchr_m(qhost, '\\'))) {
4146                         *slash = 0;
4147                 }
4148
4149                 if ((p=strchr_m(qhost, '#'))) {
4150                         *p = 0;
4151                         p++;
4152                         sscanf(p, "%x", &name_type);
4153                         cli_cm_set_dest_name_type( name_type );
4154                 }
4155
4156                 return do_host_query(qhost);
4157         }
4158
4159         if (message) {
4160                 return do_message_op();
4161         }
4162         
4163         if (process(base_directory)) {
4164                 return 1;
4165         }
4166
4167         talloc_destroy( ctx);
4168         return rc;
4169 }