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