RIP BOOL. Convert BOOL -> bool. I found a few interesting
[nivanova/samba-autobuild/.git] / source3 / client / smbctool.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    Copyright (C) Kalim Moghul                   2005
9    
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "libsmbclient.h"
26 #include "client/client_proto.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 service;
38 static pstring desthost;
39 static pstring username;
40 static pstring workgroup;
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 /* 30 second timeout on most commands */
54 #define CLIENT_TIMEOUT (30*1000)
55 #define SHORT_TIMEOUT (5*1000)
56
57 /* value for unused fid field in trans2 secondary request */
58 #define FID_UNUSED (0xFFFF)
59
60 time_t newer_than = 0;
61 static int archive_level = 0;
62
63 static bool translation = False;
64 static bool have_ip;
65
66 /* clitar bits insert */
67 extern int blocksize;
68 extern bool tar_inc;
69 extern bool tar_reset;
70 /* clitar bits end */
71  
72
73 static bool prompt = True;
74
75 static bool recurse = False;
76 bool lowercase = False;
77
78 static struct in_addr dest_ip;
79
80 #define SEPARATORS " \t\n\r"
81
82 static bool abort_mget = True;
83
84 static pstring fileselection = "";
85
86 extern file_info def_finfo;
87
88 /* timing globals */
89 SMB_BIG_UINT get_total_size = 0;
90 unsigned int get_total_time_ms = 0;
91 static SMB_BIG_UINT put_total_size = 0;
92 static unsigned int put_total_time_ms = 0;
93
94 /* totals globals */
95 static double dir_total;
96
97 /* root cli_state connection */
98
99 struct cli_state *cli;
100
101
102 /****************************************************************************
103  Authentication callback function for libsmbclient 
104 ****************************************************************************/
105
106 static void
107 get_auth_data_fn(const char * pServer, const char * pShare,
108         char * pWorkgroup, int maxLenWorkgroup,
109         char * pUsername, int maxLenUsername,
110         char * pPassword, int maxLenPassword)
111 {
112         char temp[sizeof(fstring)];
113         
114         static char authUsername[sizeof(fstring)];
115         static char authWorkgroup[sizeof(fstring)];
116         static char authPassword[sizeof(fstring)];
117         static char authSet = 0;
118
119         
120         if (authSet)
121         {
122                 strncpy(pWorkgroup, authWorkgroup, maxLenWorkgroup - 1);
123                 strncpy(pUsername, authUsername, maxLenUsername - 1);
124                 strncpy(pPassword, authPassword, maxLenPassword - 1);
125         }
126         else
127         {
128                 d_printf("Workgroup: %s\n", workgroup);
129                 strncpy(pWorkgroup, workgroup, maxLenWorkgroup - 1);
130                 strncpy(authWorkgroup, workgroup, maxLenWorkgroup - 1);
131                 
132                 d_printf("Username: %s\n", username);
133                 strncpy(pUsername, username, maxLenUsername - 1);
134                 strncpy(authUsername, username, maxLenUsername - 1);
135                 
136                 if (cmdline_auth_info.got_pass)
137                 {
138                         strncpy(pPassword, cmdline_auth_info.password, maxLenPassword - 1);
139                         strncpy(authPassword, cmdline_auth_info.password, maxLenPassword - 1);
140                 }
141                 else
142                 {
143                         char *pass = getpass("Password: ");
144                         if (pass)
145                                 fstrcpy(temp, pass);
146                         if (temp[strlen(temp) - 1] == '\n') /* A new line? */
147                         {
148                                 temp[strlen(temp) - 1] = '\0';
149                         }                
150                         if (temp[0] != '\0')
151                         {
152                                 strncpy(pPassword, temp, maxLenPassword - 1);
153                                 strncpy(authPassword, pPassword, maxLenPassword - 1);
154                         }
155                 }
156                 pstrcpy(cmdline_auth_info.username, authUsername);
157                 pstrcpy(cmdline_auth_info.password, authPassword);
158                 cmdline_auth_info.got_pass = True;
159                 set_global_myworkgroup(authWorkgroup);
160                 cli_cm_set_credentials(&cmdline_auth_info);
161                 authSet = 1;
162         }
163 }
164
165 /*******************************************************************
166  Return a string representing an attribute for a file.
167 ********************************************************************/
168
169 fstring *mode_t_string(mode_t mode)
170 {
171         static fstring attrstr;
172
173         attrstr[0] = 0;
174         
175         S_ISDIR(mode) ? fstrcat(attrstr, "d") : fstrcat(attrstr, "-");
176         (mode & S_IRUSR) ? fstrcat(attrstr, "r") : fstrcat(attrstr, "-");
177         (mode & S_IWUSR) ? fstrcat(attrstr, "w") : fstrcat(attrstr, "-");
178         (mode & S_IXUSR) ? fstrcat(attrstr, "x") : fstrcat(attrstr, "-");
179         
180         (mode & S_IRGRP) ? fstrcat(attrstr, "r") : fstrcat(attrstr, "-");
181         (mode & S_IWGRP) ? fstrcat(attrstr, "w") : fstrcat(attrstr, "-");
182         (mode & S_IXGRP) ? fstrcat(attrstr, "x") : fstrcat(attrstr, "-");
183         
184         (mode & S_IROTH) ? fstrcat(attrstr, "r") : fstrcat(attrstr, "-");
185         (mode & S_IWOTH) ? fstrcat(attrstr, "w") : fstrcat(attrstr, "-");
186         (mode & S_IXOTH) ? fstrcat(attrstr, "x") : fstrcat(attrstr, "-");
187         
188
189         return(&attrstr);
190 }
191
192 /****************************************************************************
193  Write to a local file with CR/LF->LF translation if appropriate. Return the 
194  number taken from the buffer. This may not equal the number written.
195 ****************************************************************************/
196
197 static int writefile(int f, char *b, int n)
198 {
199         int i;
200
201         if (!translation) {
202                 return write(f,b,n);
203         }
204
205         i = 0;
206         while (i < n) {
207                 if (*b == '\r' && (i<(n-1)) && *(b+1) == '\n') {
208                         b++;i++;
209                 }
210                 if (write(f, b, 1) != 1) {
211                         break;
212                 }
213                 b++;
214                 i++;
215         }
216   
217         return(i);
218 }
219
220 /****************************************************************************
221  Read from a file with LF->CR/LF translation if appropriate. Return the 
222  number read. read approx n bytes.
223 ****************************************************************************/
224
225 static int readfile(char *b, int n, XFILE *f)
226 {
227         int i;
228         int c;
229
230         if (!translation)
231                 return x_fread(b,1,n,f);
232   
233         i = 0;
234         while (i < (n - 1) && (i < BUFFER_SIZE)) {
235                 if ((c = x_getc(f)) == EOF) {
236                         break;
237                 }
238           
239                 if (c == '\n') { /* change all LFs to CR/LF */
240                         b[i++] = '\r';
241                 }
242           
243                 b[i++] = c;
244         }
245   
246         return(i);
247 }
248  
249 /****************************************************************************
250  Send a message.
251 ****************************************************************************/
252
253 static void send_message(void)
254 {
255         int total_len = 0;
256         int grp_id;
257
258         if (!cli_message_start(cli, desthost, username, &grp_id)) {
259                 d_printf("message start: %s\n", cli_errstr(cli));
260                 return;
261         }
262
263
264         d_printf("Connected. Type your message, ending it with a Control-D\n");
265
266         while (!feof(stdin) && total_len < 1600) {
267                 int maxlen = MIN(1600 - total_len,127);
268                 pstring msg;
269                 int l=0;
270                 int c;
271
272                 ZERO_ARRAY(msg);
273
274                 for (l=0;l<maxlen && (c=fgetc(stdin))!=EOF;l++) {
275                         if (c == '\n')
276                                 msg[l++] = '\r';
277                         msg[l] = c;       
278                 }
279
280                 if (!cli_message_text(cli, msg, l, grp_id)) {
281                         d_printf("SMBsendtxt failed (%s)\n",cli_errstr(cli));
282                         return;
283                 }          
284                 
285                 total_len += l;
286         }
287
288         if (total_len >= 1600)
289                 d_printf("the message was truncated to 1600 bytes\n");
290         else
291                 d_printf("sent %d bytes\n",total_len);
292
293         if (!cli_message_end(cli, grp_id)) {
294                 d_printf("SMBsendend failed (%s)\n",cli_errstr(cli));
295                 return;
296         }          
297 }
298
299 /****************************************************************************
300  Check the space on a device.
301 ****************************************************************************/
302
303 static int do_dskattr(void)
304 {
305         int total, bsize, avail;
306         struct cli_state *targetcli;
307         pstring targetpath;
308
309         if ( !cli_resolve_path( "", cli, cur_dir, &targetcli, targetpath ) ) {
310                 d_printf("Error in dskattr: %s\n", cli_errstr(cli));
311                 return 1;
312         }
313
314         if (!cli_dskattr(targetcli, &bsize, &total, &avail)) {
315                 d_printf("Error in dskattr: %s\n",cli_errstr(targetcli)); 
316                 return 1;
317         }
318
319         d_printf("\n\t\t%d blocks of size %d. %d blocks available\n",
320                  total, bsize, avail);
321
322         return 0;
323 }
324
325 /****************************************************************************
326  Show cd/pwd.
327 ****************************************************************************/
328
329 static int cmd_pwd(void)
330 {
331         d_printf("Current directory is %s",service);
332         d_printf("%s\n",cur_dir);
333         return 0;
334 }
335
336 /****************************************************************************
337  Change directory - inner section.
338 ****************************************************************************/
339
340 static int do_cd(char *newdir)
341 {
342         char *p = newdir;
343         pstring saved_dir;
344         pstring dname;
345         pstring targetpath;
346         struct cli_state *targetcli;
347         SMB_STRUCT_STAT sbuf;
348         uint32 attributes;
349         int dh;
350         
351         unix_format(newdir);
352
353         /* Save the current directory in case the new directory is invalid */
354         pstrcpy(saved_dir, cur_dir);
355
356         pstrcpy(dname, p);                      /* first save the argument */
357         
358         if (*p == '/')
359                 pstrcpy(cur_dir,dname);
360         else
361                 pstrcat(cur_dir,dname);
362
363         if (*(cur_dir+strlen(cur_dir)-1) != '/') {
364                 pstrcat(cur_dir, "/");
365         }
366         
367         all_string_sub(cur_dir, "/./", "/", 0);
368         
369         /* Format the directory in a libmsmbclient friendly way */
370         clean_name(cur_dir);
371         all_string_sub(cur_dir, "/./", "/", 0);
372         pstrcpy(targetpath, "smb:");
373         pstrcat(targetpath, service);
374         pstrcat(targetpath, cur_dir);
375         unix_format(targetpath);
376
377         dh = smbc_opendir(targetpath);
378         
379         if (dh < 0)
380         {
381                 d_printf("%s changing to directory %s\n", strerror(errno), cur_dir);
382                 pstrcpy(cur_dir, saved_dir);
383                 return 1;
384         }
385         smbc_closedir(dh);
386
387         return 0;
388 }
389
390 /****************************************************************************
391  Change directory.
392 ****************************************************************************/
393
394 static int cmd_cd(void)
395 {
396         pstring buf;
397         int rc = 0;
398                 
399         if (next_token_nr(NULL,buf,NULL,sizeof(buf)))
400                 rc = do_cd(buf);
401         else
402                 d_printf("Current directory is %s\n",cur_dir);
403
404         return rc;
405 }
406
407 /*******************************************************************
408  Decide if a file should be operated on.
409 ********************************************************************/
410
411 static bool do_this_one(file_info *finfo)
412 {
413         if (finfo->mode & aDIR)
414                 return(True);
415
416         if (*fileselection && 
417                 !mask_match(finfo->name,fileselection,False)) {
418                 DEBUG(3,("mask_match %s failed\n", finfo->name));
419                 return False;
420         }
421
422         if (newer_than && finfo->mtime < newer_than) {
423                 DEBUG(3,("newer_than %s failed\n", finfo->name));
424                 return(False);
425         }
426
427         if ((archive_level==1 || archive_level==2) && !(finfo->mode & aARCH)) {
428                 DEBUG(3,("archive %s failed\n", finfo->name));
429                 return(False);
430         }
431         
432         return(True);
433 }
434
435 /****************************************************************************
436  Display info about a file.
437 ****************************************************************************/
438
439 static void display_finfo(file_info *finfo)
440 {
441         if (do_this_one(finfo)) {
442                 time_t t = finfo->mtime; /* the time is assumed to be passed as GMT */
443                 d_printf("  %-30s%7.7s %8.0f  %s",
444                          finfo->name,
445                          attrib_string(finfo->mode),
446                          (double)finfo->size,
447                          time_to_asc(t));
448                 dir_total += finfo->size;
449         }
450 }
451
452 /****************************************************************************
453  Display info about a file.
454 ****************************************************************************/
455
456 static void display_stat(char *name, struct stat *st)
457 {
458         time_t t = st->st_mtime;
459         pstring time_str;
460         pstrcpy(time_str, time_to_asc(t));
461         time_str[strlen(time_str)-1] = 0;
462         d_printf("> %-30s", name);
463         d_printf("%10.10s %8.0f  %s\n", *mode_t_string(st->st_mode), (double)st->st_size, time_str);
464 }
465
466 /****************************************************************************
467  Accumulate size of a file.
468 ****************************************************************************/
469
470 static void do_du(file_info *finfo)
471 {
472         if (do_this_one(finfo)) {
473                 dir_total += finfo->size;
474         }
475 }
476
477 static bool do_list_recurse;
478 static bool do_list_dirs;
479 static char *do_list_queue = 0;
480 static long do_list_queue_size = 0;
481 static long do_list_queue_start = 0;
482 static long do_list_queue_end = 0;
483 static void (*do_list_fn)(file_info *);
484 static void (*tool_list_fn)(char *, struct stat *);
485
486 /****************************************************************************
487  Functions for do_list_queue.
488 ****************************************************************************/
489
490 /*
491  * The do_list_queue is a NUL-separated list of strings stored in a
492  * char*.  Since this is a FIFO, we keep track of the beginning and
493  * ending locations of the data in the queue.  When we overflow, we
494  * double the size of the char*.  When the start of the data passes
495  * the midpoint, we move everything back.  This is logically more
496  * complex than a linked list, but easier from a memory management
497  * angle.  In any memory error condition, do_list_queue is reset.
498  * Functions check to ensure that do_list_queue is non-NULL before
499  * accessing it.
500  */
501
502 static void reset_do_list_queue(void)
503 {
504         SAFE_FREE(do_list_queue);
505         do_list_queue_size = 0;
506         do_list_queue_start = 0;
507         do_list_queue_end = 0;
508 }
509
510 static void init_do_list_queue(void)
511 {
512         reset_do_list_queue();
513         do_list_queue_size = 1024;
514         do_list_queue = SMB_MALLOC(do_list_queue_size);
515         if (do_list_queue == 0) { 
516                 d_printf("malloc fail for size %d\n",
517                          (int)do_list_queue_size);
518                 reset_do_list_queue();
519         } else {
520                 memset(do_list_queue, 0, do_list_queue_size);
521         }
522 }
523
524 static void adjust_do_list_queue(void)
525 {
526         /*
527          * If the starting point of the queue is more than half way through,
528          * move everything toward the beginning.
529          */
530
531         if (do_list_queue == NULL) {
532                 DEBUG(4,("do_list_queue is empty\n"));
533                 do_list_queue_start = do_list_queue_end = 0;
534                 return;
535         }
536                 
537         if (do_list_queue_start == do_list_queue_end) {
538                 DEBUG(4,("do_list_queue is empty\n"));
539                 do_list_queue_start = do_list_queue_end = 0;
540                 *do_list_queue = '\0';
541         } else if (do_list_queue_start > (do_list_queue_size / 2)) {
542                 DEBUG(4,("sliding do_list_queue backward\n"));
543                 memmove(do_list_queue,
544                         do_list_queue + do_list_queue_start,
545                         do_list_queue_end - do_list_queue_start);
546                 do_list_queue_end -= do_list_queue_start;
547                 do_list_queue_start = 0;
548         }
549 }
550
551 static void add_to_do_list_queue(const char* entry)
552 {
553         long new_end = do_list_queue_end + ((long)strlen(entry)) + 1;
554         while (new_end > do_list_queue_size) {
555                 do_list_queue_size *= 2;
556                 DEBUG(4,("enlarging do_list_queue to %d\n",
557                          (int)do_list_queue_size));
558                 do_list_queue = SMB_REALLOC(do_list_queue, do_list_queue_size);
559                 if (!do_list_queue) {
560                         d_printf("failure enlarging do_list_queue to %d bytes\n",
561                                  (int)do_list_queue_size);
562                         reset_do_list_queue();
563                 } else {
564                         memset(do_list_queue + do_list_queue_size / 2,
565                                    0, do_list_queue_size / 2);
566                 }
567         }
568         if (do_list_queue) {
569                 safe_strcpy_base(do_list_queue + do_list_queue_end, 
570                                  entry, do_list_queue, do_list_queue_size);
571                 do_list_queue_end = new_end;
572                 DEBUG(4,("added %s to do_list_queue (start=%d, end=%d)\n",
573                          entry, (int)do_list_queue_start, (int)do_list_queue_end));
574         }
575 }
576
577 static char *do_list_queue_head(void)
578 {
579         return do_list_queue + do_list_queue_start;
580 }
581
582 static void remove_do_list_queue_head(void)
583 {
584         if (do_list_queue_end > do_list_queue_start) {
585                 do_list_queue_start += strlen(do_list_queue_head()) + 1;
586                 adjust_do_list_queue();
587                 DEBUG(4,("removed head of do_list_queue (start=%d, end=%d)\n",
588                          (int)do_list_queue_start, (int)do_list_queue_end));
589         }
590 }
591
592 static int do_list_queue_empty(void)
593 {
594         return (! (do_list_queue && *do_list_queue));
595 }
596
597 /****************************************************************************
598  A helper for tool_list.
599 ****************************************************************************/
600
601 static void tool_list_helper(const char *mntpoint, struct stat *f, const char *mask, void *state)
602 {
603         /*if (f is a directory)
604         {
605                 if (we want to do directories and we want to do this f)
606                 {
607                         execute the callback on f
608                 }
609                 if (recursion is set and f isn't . and it isn't ..)
610                 {
611                         make sure the name is valid
612                         construct a full path out of the name
613                         add the full path to the list
614                 }
615                 return;
616         }
617         if (we want to do this f)
618         {
619                 execute the callback on f
620         }*/
621 }
622
623 /****************************************************************************
624  A cli_list-like function that executes fn on each directory entry.
625  fn operates on the returned entry name and struct stat.
626 ****************************************************************************/
627
628 int tool_list(  char *mask,
629                                 mode_t mode,
630                                 void (*fn)(char *, struct stat *),
631                                 bool rec,
632                                 bool dirs)
633 {
634         int dh;
635         pstring dentname;
636         pstring res;
637         struct stat stat;
638         struct smbc_dirent* dent;
639         
640         pstrcpy(res, "smb:");
641         pstrcat(res, service);
642         pstrcat(res, cur_dir);
643         
644         if ((dh = smbc_opendir(res)) < 1)
645         {
646                 d_printf("Error: %s opening %s\n", strerror(errno), res);
647                 return 1;
648         }
649         
650         while (dent = smbc_readdir(dh))
651         {
652                 switch(dent->smbc_type)
653                 {
654                 case SMBC_WORKGROUP:
655                 case SMBC_SERVER:
656                 case SMBC_FILE_SHARE:
657                 case SMBC_PRINTER_SHARE:
658                 case SMBC_COMMS_SHARE:
659                 case SMBC_IPC_SHARE:
660                         break;
661                 case SMBC_DIR:
662                         if (!dirs)
663                                 break;
664                 case SMBC_FILE:
665                         pstrcpy(dentname, res);
666                         pstrcat(dentname, dent->name);
667                         /*if (mask_match(dent->name, mask, False))*/
668                         if (mask_match(dentname, mask, False))
669                         {
670                                 if (smbc_stat(dentname, &stat) < 0)
671                                 {
672                                         d_printf("> %s - stat error: %s\n", dent->name, strerror(errno));
673                                 }
674                                 else
675                                 {
676                                         fn(dent->name, &stat);
677                                 }
678                         }
679                         break;
680                 case SMBC_LINK:
681                         break;
682                 }
683         }
684         smbc_closedir(dh);
685 }
686
687 /****************************************************************************
688  A helper for do_list.
689 ****************************************************************************/
690
691 static void do_list_helper(const char *mntpoint, file_info *f, const char *mask, void *state)
692 {
693         if (f->mode & aDIR) {
694                 if (do_list_dirs && do_this_one(f)) {
695                         do_list_fn(f);
696                 }
697                 if (do_list_recurse && 
698                         !strequal(f->name,".") && 
699                         !strequal(f->name,"..")) {
700                         pstring mask2;
701                         char *p;
702
703                         if (!f->name[0]) {
704                                 d_printf("Empty dir name returned. Possible server misconfiguration.\n");
705                                 return;
706                         }
707
708                         pstrcpy(mask2, mntpoint);
709                         pstrcat(mask2, mask);
710                         p = strrchr_m(mask2,'/');
711                         if (!p)
712                                 return;
713                         p[1] = 0;
714                         pstrcat(mask2, f->name);
715                         pstrcat(mask2,"/*");
716                         add_to_do_list_queue(mask2);
717                 }
718                 return;
719         }
720
721         if (do_this_one(f)) {
722                 do_list_fn(f);
723         }
724 }
725
726 /****************************************************************************
727  A wrapper around cli_list that adds recursion.
728 ****************************************************************************/
729
730 void do_list(const char *mask,uint16 attribute,void (*fn)(file_info *),bool rec, bool dirs)
731 {
732         static int in_do_list = 0;
733         struct cli_state *targetcli;
734         pstring targetpath;
735
736         if (in_do_list && rec) {
737                 fprintf(stderr, "INTERNAL ERROR: do_list called recursively when the recursive flag is true\n");
738                 exit(1);
739         }
740
741         in_do_list = 1;
742
743         do_list_recurse = rec;
744         do_list_dirs = dirs;
745         do_list_fn = fn;
746
747         if (rec) {
748                 init_do_list_queue();
749                 add_to_do_list_queue(mask);
750                 
751                 while (! do_list_queue_empty()) {
752                         /*
753                          * Need to copy head so that it doesn't become
754                          * invalid inside the call to cli_list.  This
755                          * would happen if the list were expanded
756                          * during the call.
757                          * Fix from E. Jay Berkenbilt (ejb@ql.org)
758                          */
759                         pstring head;
760                         pstrcpy(head, do_list_queue_head());
761                         
762                         /* check for dfs */
763                         
764                         if ( !cli_resolve_path( "", cli, head, &targetcli, targetpath ) ) {
765                                 d_printf("do_list: [%s] %s\n", head, cli_errstr(cli));
766                                 remove_do_list_queue_head();
767                                 continue;
768                         }
769                         
770                         cli_list(targetcli, targetpath, attribute, do_list_helper, NULL);
771                         remove_do_list_queue_head();
772                         if ((! do_list_queue_empty()) && (fn == display_finfo)) {
773                                 char* next_file = do_list_queue_head();
774                                 char* save_ch = 0;
775                                 if ((strlen(next_file) >= 2) &&
776                                         (next_file[strlen(next_file) - 1] == '*') &&
777                                         (next_file[strlen(next_file) - 2] == '/')) {
778                                         save_ch = next_file +
779                                                 strlen(next_file) - 2;
780                                         *save_ch = '\0';
781                                 }
782                                 d_printf("\n%s\n",next_file);
783                                 if (save_ch) {
784                                         *save_ch = '/';
785                                 }
786                         }
787                 }
788         } else {
789                 /* check for dfs */
790                         
791                 if ( cli_resolve_path( "", cli, mask, &targetcli, targetpath ) ) {
792                         if (cli_list(targetcli, targetpath, attribute, do_list_helper, NULL) == -1) 
793                                 d_printf("%s listing %s\n", cli_errstr(targetcli), targetpath);
794                 }
795                 else
796                         d_printf("do_list: [%s] %s\n", mask, cli_errstr(cli));
797                 
798         }
799
800         in_do_list = 0;
801         reset_do_list_queue();
802 }
803
804 /****************************************************************************
805  Get a directory listing.
806 ****************************************************************************/
807
808 static int cmd_dir(void)
809 {
810         mode_t mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO;
811         pstring mask;
812         pstring buf;
813         char *p=buf;
814         
815         pstrcpy(mask, "smb:");
816         pstrcat(mask, service);
817         pstrcat(mask, cur_dir);
818         
819         if (next_token_nr(NULL,buf,NULL,sizeof(buf)))
820                 pstrcat(mask,buf);
821         else
822                 pstrcat(mask,"*");
823         
824         tool_list(mask, mode, display_stat, recurse, True);
825         return 0;
826 }
827
828 /****************************************************************************
829  Get a directory listing.
830 ****************************************************************************/
831
832 static int cmd_du(void)
833 {
834         uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
835         pstring mask;
836         pstring buf;
837         char *p=buf;
838         int rc;
839         
840         dir_total = 0;
841         pstrcpy(mask,cur_dir);
842         if(mask[strlen(mask)-1]!='/')
843                 pstrcat(mask,"/");
844         
845         if (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
846                 dos_format(p);
847                 if (*p == '/')
848                         pstrcpy(mask,p);
849                 else
850                         pstrcat(mask,p);
851         } else {
852                 pstrcat(mask,"*");
853         }
854
855         do_list(mask, attribute, do_du, recurse, True);
856
857         rc = do_dskattr();
858
859         d_printf("Total number of bytes: %.0f\n", dir_total);
860
861         return rc;
862 }
863
864 /****************************************************************************
865  Get a file from rname to lname
866 ****************************************************************************/
867
868 static int do_get(char *rname, char *lname, bool reget)
869 {  
870         int handle = 0, fnum;
871         bool newhandle = False;
872         char *data;
873         struct timeval tp_start;
874         int read_size = io_bufsize;
875         /*uint16 attr;*/
876         struct stat stat;
877         off_t start = 0;
878         off_t nread = 0;
879         int rc = 0;
880
881         if (lowercase) {
882                 strlower_m(lname);
883         }
884
885         GetTimeOfDay(&tp_start);
886         
887         fnum = smbc_open(rname, O_RDONLY, 0666);
888         if (fnum < 0)
889         {
890                 d_printf("%s opening remote file %s\n", strerror(errno), rname);
891                 return 1;
892         }
893
894         if(!strcmp(lname,"-")) {
895                 handle = fileno(stdout);
896         } else {
897                 if (reget) {
898                         handle = sys_open(lname, O_WRONLY|O_CREAT, 0644);
899                         if (handle >= 0) {
900                                 start = sys_lseek(handle, 0, SEEK_END);
901                                 if (start == -1) {
902                                         smbc_close(fnum);
903                                         d_printf("Error seeking local file\n");
904                                         return 1;
905                                 }
906                         }
907                 } else {
908                         handle = sys_open(lname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
909                 }
910                 newhandle = True;
911         }
912         if (handle < 0) {
913                 d_printf("Error opening local file %s\n",lname);
914                 smbc_close(fnum);
915                 return 1;
916         }
917
918         if (smbc_fstat(fnum, &stat) < 0)
919         {
920                 d_printf("%s trying to stat remote file %s\n", strerror(errno), rname);
921                 if (newhandle)
922                         close(handle);
923                 smbc_close(fnum);
924                 return 1;
925         }
926
927         DEBUG(1,("getting file %s of size %.0f as %s ", 
928                  rname, (double)stat.st_size, lname));
929
930         if(!(data = (char *)SMB_MALLOC(read_size))) { 
931                 d_printf("malloc fail for size %d\n", read_size);
932                 if (newhandle)
933                         close(handle);
934                 smbc_close(fnum);
935                 return 1;
936         }
937
938         if (smbc_lseek(fnum, start, SEEK_SET) < 0)
939         {
940                 d_printf("%s trying to lseek remote file %s\n", strerror(errno), rname);
941                 if (newhandle)
942                         close(handle);
943                 smbc_close(fnum);
944                 SAFE_FREE(data);
945                 return 1;
946         }
947         while (1) {
948                 int n = smbc_read(fnum, data, read_size);
949
950                 if (n < 0)
951                 {
952                         d_printf("%s while reading remote file %s\n", strerror(errno), rname);
953                         if (newhandle)
954                                 close(handle);
955                         smbc_close(fnum);
956                         SAFE_FREE(data);
957                         return 1;
958                 }
959                 if (n == 0)
960                         break;
961  
962                 if (writefile(handle,data, n) != n) {
963                         d_printf("Error writing local file\n");
964                         rc = 1;
965                         break;
966                 }
967           
968                 nread += n;
969         }
970
971         if (nread + start < stat.st_size) {
972                 DEBUG (1, ("Short read when getting file %s. Only got %ld bytes.\n", rname, (long)nread));
973                 rc = 1;
974         }
975
976         SAFE_FREE(data);
977         
978         if (smbc_close(fnum) < 0)
979         {
980                 d_printf("%s closing remote file %s\n", strerror(errno), rname);
981                 rc = 1;
982         }
983
984         if (newhandle) {
985                 close(handle);
986         }
987
988         /*if (archive_level >= 2 && (attr & aARCH)) {
989                 cli_setatr(cli, rname, attr & ~(uint16)aARCH, 0);
990         }*/
991
992         {
993                 struct timeval tp_end;
994                 int this_time;
995                 
996                 GetTimeOfDay(&tp_end);
997                 this_time = 
998                         (tp_end.tv_sec - tp_start.tv_sec)*1000 +
999                         (tp_end.tv_usec - tp_start.tv_usec)/1000;
1000                 get_total_time_ms += this_time;
1001                 get_total_size += nread;
1002                 
1003                 DEBUG(1,("(%3.1f kb/s) (average %3.1f kb/s)\n",
1004                          nread / (1.024*this_time + 1.0e-4),
1005                          get_total_size / (1.024*get_total_time_ms)));
1006         }
1007         
1008         return rc;
1009 }
1010
1011 /****************************************************************************
1012  Get a file.
1013 ****************************************************************************/
1014
1015 static int cmd_get(void)
1016 {
1017         pstring lname;
1018         pstring rname;
1019         char *p;
1020
1021         pstrcpy(rname, "smb:");
1022         pstrcat(rname, service);
1023         pstrcat(rname, cur_dir);
1024         
1025         p = rname + strlen(rname);
1026         
1027         if (!next_token_nr(NULL,p,NULL,sizeof(rname)-strlen(rname))) {
1028                 d_printf("get <filename>\n");
1029                 return 1;
1030         }
1031         pstrcpy(lname,p);
1032         
1033         next_token_nr(NULL,lname,NULL,sizeof(lname));
1034         /*d_printf("lname: %s, rname: %s\n", lname, rname);*/
1035         return do_get(rname, lname, False);
1036 }
1037
1038 /****************************************************************************
1039  Do an mget operation on one file.
1040 ****************************************************************************/
1041
1042 static void do_mget(char *name, struct stat *st)
1043 {
1044         pstring rname;
1045         pstring quest;
1046         pstring saved_curdir;
1047         pstring mget_mask;
1048         mode_t mode;
1049
1050         if (strequal(name,".") || strequal(name,".."))
1051                 return;
1052
1053         if (S_ISDIR(st->st_mode))
1054                 slprintf(quest,sizeof(pstring)-1, "Get directory %s%s? ", cur_dir, name);
1055         else
1056                 slprintf(quest,sizeof(pstring)-1, "Get file %s%s? ", cur_dir, name);
1057
1058         if (prompt && !yesno(quest))
1059                 return;
1060
1061         if (!S_ISDIR(st->st_mode)) {
1062                 pstrcpy(rname,"smb:");
1063                 pstrcat(rname,service);
1064                 pstrcat(rname,cur_dir);
1065                 pstrcat(rname,name);
1066                 do_get(rname,name, False);
1067                 return;
1068         }
1069
1070         /* handle directories */
1071         /* TODO: clean this code up for recursive calls */
1072         pstrcpy(saved_curdir,cur_dir);
1073
1074         pstrcat(cur_dir,name);
1075         pstrcat(cur_dir,"/");
1076
1077         unix_format(name);
1078         if (lowercase)
1079                 strlower_m(name);
1080         
1081         if (!directory_exist(name,NULL) && 
1082                 mkdir(name,0777) != 0) {
1083                 d_printf("failed to create directory %s\n",name);
1084                 pstrcpy(cur_dir,saved_curdir);
1085                 return;
1086         }
1087         
1088         if (chdir(name) != 0) {
1089                 d_printf("failed to chdir to directory %s\n",name);
1090                 pstrcpy(cur_dir,saved_curdir);
1091                 return;
1092         }
1093
1094         pstrcpy(mget_mask,"smb:");
1095         pstrcat(mget_mask,service);
1096         pstrcat(mget_mask,cur_dir);
1097         pstrcat(mget_mask,"*");
1098         
1099         /*d_printf("Calling with mask: %s\n", mget_mask);*/
1100         tool_list(mget_mask, mode, do_mget, recurse, recurse);
1101         chdir("..");
1102         pstrcpy(cur_dir,saved_curdir);
1103 }
1104
1105 /****************************************************************************
1106  View the file using the pager.
1107 ****************************************************************************/
1108
1109 static int cmd_more(void)
1110 {
1111         pstring rname,lname,pager_cmd;
1112         char *pager;
1113         int fd;
1114         int rc = 0;
1115
1116         pstrcpy(rname,cur_dir);
1117         pstrcat(rname,"/");
1118         
1119         slprintf(lname,sizeof(lname)-1, "%s/smbmore.XXXXXX",tmpdir());
1120         fd = smb_mkstemp(lname);
1121         if (fd == -1) {
1122                 d_printf("failed to create temporary file for more\n");
1123                 return 1;
1124         }
1125         close(fd);
1126
1127         if (!next_token_nr(NULL,rname+strlen(rname),NULL,sizeof(rname)-strlen(rname))) {
1128                 d_printf("more <filename>\n");
1129                 unlink(lname);
1130                 return 1;
1131         }
1132         clean_name(rname);
1133
1134         rc = do_get(rname, lname, False);
1135
1136         pager=getenv("PAGER");
1137
1138         slprintf(pager_cmd,sizeof(pager_cmd)-1,
1139                  "%s %s",(pager? pager:PAGER), lname);
1140         system(pager_cmd);
1141         unlink(lname);
1142         
1143         return rc;
1144 }
1145
1146 /****************************************************************************
1147  Do a mget command.
1148 ****************************************************************************/
1149
1150 static int cmd_mget(void)
1151 {
1152         mode_t mode;
1153         pstring mget_mask;
1154         pstring buf;
1155         char *p=buf;
1156
1157         *mget_mask = 0;
1158
1159         while (next_token_nr(NULL,p,NULL,sizeof(buf))) {
1160                 pstrcpy(mget_mask, "smb:");
1161                 pstrcat(mget_mask, service);
1162                 pstrcat(mget_mask,cur_dir);
1163                 if(mget_mask[strlen(mget_mask)-1]!='/')
1164                         pstrcat(mget_mask,"/");
1165                 
1166                 if (*p == '/')
1167                 {
1168                         pstrcpy(mget_mask, "smb:");
1169                         pstrcat(mget_mask, service);
1170                         pstrcat(mget_mask,p);
1171                 }
1172                 else
1173                         pstrcat(mget_mask,p);
1174                 /* TODO: enable directories on calls to tool_list
1175                    once recursion is worked out */
1176                 tool_list(mget_mask, mode, do_mget, recurse, recurse);
1177         }
1178
1179         if (!*mget_mask) {
1180                 pstrcpy(mget_mask, "smb:");
1181                 pstrcat(mget_mask, service);
1182                 pstrcat(mget_mask,cur_dir);
1183                 if(mget_mask[strlen(mget_mask)-1]!='/')
1184                         pstrcat(mget_mask,"/");
1185                 pstrcat(mget_mask,"*");
1186                 tool_list(mget_mask, mode, do_mget, recurse, recurse);
1187         }
1188         
1189         return 0;
1190 }
1191
1192 /****************************************************************************
1193  Make a directory of name "name".
1194 ****************************************************************************/
1195
1196 static bool do_mkdir(char *name)
1197 {
1198         if (smbc_mkdir(name, 755) < 0)
1199         {
1200                 d_printf("Error: %s making remote directory %s\n", strerror(errno), name);
1201                 return False;
1202         }
1203         
1204         return True;
1205 }
1206
1207 /****************************************************************************
1208  Show 8.3 name of a file.
1209 ****************************************************************************/
1210
1211 static bool do_altname(char *name)
1212 {
1213         pstring altname;
1214         if (!NT_STATUS_IS_OK(cli_qpathinfo_alt_name(cli, name, altname))) {
1215                 d_printf("%s getting alt name for %s\n",
1216                          cli_errstr(cli),name);
1217                 return(False);
1218         }
1219         d_printf("%s\n", altname);
1220
1221         return(True);
1222 }
1223
1224 /****************************************************************************
1225  Exit client.
1226 ****************************************************************************/
1227
1228 static int cmd_quit(void)
1229 {
1230         cli_cm_shutdown();
1231         exit(0);
1232         /* NOTREACHED */
1233         return 0;
1234 }
1235
1236 /****************************************************************************
1237  Make a directory.
1238 ****************************************************************************/
1239
1240 static int cmd_mkdir(void)
1241 {
1242         int dh;
1243         pstring mask;
1244         pstring buf;
1245         pstring targetname;
1246         char *p=buf;
1247   
1248         pstrcpy(mask,cur_dir);
1249
1250         if (!next_token_nr(NULL,p,NULL,sizeof(buf))) {
1251                 if (!recurse)
1252                         d_printf("mkdir <dirname>\n");
1253                 return 1;
1254         }
1255         pstrcat(mask,p);
1256         
1257         if (recurse) {
1258                 pstring ddir;
1259                 pstring ddir2;
1260                 *ddir2 = 0;
1261                 
1262                 pstrcpy(ddir,mask);
1263                 trim_char(ddir,'.','\0');
1264                 p = strtok(ddir,"/\\");
1265                 while (p) {
1266                         pstrcat(ddir2,p);
1267                         
1268                         pstrcpy(targetname, "smb:");
1269                         pstrcat(targetname, service);
1270                         pstrcat(targetname, "/");
1271                         pstrcat(targetname, ddir2);
1272                         DEBUG(3, ("Recursively making directory %s\n", targetname));
1273                         if ((dh = smbc_opendir(targetname)) < 0) {
1274                                 if (!do_mkdir(targetname))
1275                                         return 1;
1276                         }
1277                         else
1278                                 smbc_closedir(dh);
1279                         
1280                         pstrcat(ddir2,"/");
1281                         p = strtok(NULL,"/\\");
1282                 }
1283         }
1284         else {
1285                 pstrcpy(targetname, "smb:");
1286                 pstrcat(targetname, service);
1287                 pstrcat(targetname, mask);
1288                 
1289                 if (!do_mkdir(targetname))
1290                         return 1;
1291         }
1292         
1293         return 0;
1294 }
1295
1296 /****************************************************************************
1297  Show alt name.
1298 ****************************************************************************/
1299
1300 static int cmd_altname(void)
1301 {
1302         pstring name;
1303         pstring buf;
1304         char *p=buf;
1305   
1306         pstrcpy(name,cur_dir);
1307
1308         if (!next_token_nr(NULL,p,NULL,sizeof(buf))) {
1309                 d_printf("altname <file>\n");
1310                 return 1;
1311         }
1312         pstrcat(name,p);
1313
1314         do_altname(name);
1315
1316         return 0;
1317 }
1318
1319 /****************************************************************************
1320  Put a single file.
1321 ****************************************************************************/
1322
1323 static int do_put(char *rname, char *lname, bool reput)
1324 {
1325         int fnum;
1326         XFILE *f;
1327         SMB_OFF_T start = 0;
1328         off_t nread = 0;
1329         char *buf = NULL;
1330         int maxwrite = io_bufsize;
1331         int rc = 0;
1332         struct timeval tp_start;
1333         struct stat stat;
1334         
1335         GetTimeOfDay(&tp_start);
1336
1337         if (reput) {
1338                 fnum = smbc_open(rname, O_RDWR|O_CREAT, 0644);
1339                 if (fnum < 0)
1340                 {
1341                         d_printf("%s opening remote file %s\n", strerror(errno), rname);
1342                         return 1;
1343                 }
1344                 if (smbc_fstat(fnum, &stat) < 0)
1345                 {
1346                         d_printf("%s trying to stat remote file %s\n", strerror(errno), rname);
1347                         smbc_close(fnum);
1348                         return 1;
1349                 }
1350                 start = stat.st_size;
1351         } else {
1352                 fnum = smbc_creat(rname, 0644);
1353                 if (fnum < 0)
1354                 {
1355                         d_printf("%s trying to create remote file %s\n", strerror(errno), rname);
1356                         return 1;
1357                 }
1358         }
1359
1360         /* allow files to be piped into smbclient
1361            jdblair 24.jun.98
1362
1363            Note that in this case this function will exit(0) rather
1364            than returning. */
1365         if (!strcmp(lname, "-")) {
1366                 f = x_stdin;
1367                 /* size of file is not known */
1368         } else {
1369                 f = x_fopen(lname,O_RDONLY, 0);
1370                 if (f && reput) {
1371                         if (x_tseek(f, start, SEEK_SET) == -1) {
1372                                 d_printf("Error seeking local file\n");
1373                                 smbc_close(fnum);
1374                                 x_fclose(f);
1375                                 return 1;
1376                         }
1377                 }
1378         }
1379
1380         if (!f) {
1381                 d_printf("Error opening local file %s\n",lname);
1382                 smbc_close(fnum);
1383                 return 1;
1384         }
1385   
1386         DEBUG(1,("putting file %s as %s ",lname,rname));
1387   
1388         buf = (char *)SMB_MALLOC(maxwrite);
1389         if (!buf) {
1390                 d_printf("ERROR: Not enough memory!\n");
1391                 smbc_close(fnum);
1392                 if (f != x_stdin)
1393                         x_fclose(f);
1394                 return 1;
1395         }
1396         
1397         if (smbc_lseek(fnum, start, SEEK_SET) < 0)
1398         {
1399                 d_printf("%s trying to lseek remote file %s\n", strerror(errno), rname);
1400                 if (f != x_stdin)
1401                         x_fclose(f);
1402                 smbc_close(fnum);
1403                 SAFE_FREE(buf);
1404                 return 1;
1405         }
1406         while (!x_feof(f)) {
1407                 int n = maxwrite;
1408                 int ret;
1409
1410                 if ((n = readfile(buf,n,f)) < 1) {
1411                         if((n == 0) && x_feof(f))
1412                                 break; /* Empty local file. */
1413
1414                         d_printf("Error reading local file: %s\n", strerror(errno));
1415                         rc = 1;
1416                         break;
1417                 }
1418
1419                 ret = smbc_write(fnum, buf, n);
1420
1421                 if (n != ret) {
1422                         d_printf("Error writing file: %s\n", strerror(errno));
1423                         rc = 1;
1424                         break;
1425                 } 
1426
1427                 nread += n;
1428         }
1429
1430         if (smbc_close(fnum) < 0) {
1431                 d_printf("%s closing remote file %s\n",strerror(errno),rname);
1432                 if (f != x_stdin)
1433                         x_fclose(f);
1434                 SAFE_FREE(buf);
1435                 return 1;
1436         }
1437
1438         
1439         if (f != x_stdin) {
1440                 x_fclose(f);
1441         }
1442
1443         SAFE_FREE(buf);
1444
1445         {
1446                 struct timeval tp_end;
1447                 int this_time;
1448                 
1449                 GetTimeOfDay(&tp_end);
1450                 this_time = 
1451                         (tp_end.tv_sec - tp_start.tv_sec)*1000 +
1452                         (tp_end.tv_usec - tp_start.tv_usec)/1000;
1453                 put_total_time_ms += this_time;
1454                 put_total_size += nread;
1455                 
1456                 DEBUG(1,("(%3.1f kb/s) (average %3.1f kb/s)\n",
1457                          nread / (1.024*this_time + 1.0e-4),
1458                          put_total_size / (1.024*put_total_time_ms)));
1459         }
1460
1461         if (f == x_stdin) {
1462                 cli_cm_shutdown();
1463                 exit(0);
1464         }
1465         
1466         return rc;
1467 }
1468
1469 /****************************************************************************
1470  Put a file.
1471 ****************************************************************************/
1472
1473 static int cmd_put(void)
1474 {
1475         pstring lname;
1476         pstring rname;
1477         pstring buf;
1478         char *p=buf;
1479         
1480         pstrcpy(rname, "smb:");
1481         pstrcat(rname, service);
1482         pstrcat(rname, cur_dir);
1483   
1484         if (!next_token_nr(NULL,p,NULL,sizeof(buf))) {
1485                 d_printf("put <filename>\n");
1486                 return 1;
1487         }
1488         pstrcpy(lname,p);
1489   
1490         if (next_token_nr(NULL,p,NULL,sizeof(buf)))
1491                 pstrcat(rname,p);          
1492         else
1493                 pstrcat(rname,lname);
1494         
1495         {
1496                 SMB_STRUCT_STAT st;
1497                 /* allow '-' to represent stdin
1498                    jdblair, 24.jun.98 */
1499                 if (!file_exist(lname,&st) &&
1500                         (strcmp(lname,"-"))) {
1501                         d_printf("%s does not exist\n",lname);
1502                         return 1;
1503                 }
1504         }
1505
1506         /*d_printf("lname: %s, rname: %s\n", lname, rname);*/
1507         return do_put(rname, lname, False);
1508 }
1509
1510 /*************************************
1511  File list structure.
1512 *************************************/
1513
1514 static struct file_list {
1515         struct file_list *prev, *next;
1516         char *file_path;
1517         bool isdir;
1518 } *file_list;
1519
1520 /****************************************************************************
1521  Free a file_list structure.
1522 ****************************************************************************/
1523
1524 static void free_file_list (struct file_list * list)
1525 {
1526         struct file_list *tmp;
1527         
1528         while (list) {
1529                 tmp = list;
1530                 DLIST_REMOVE(list, list);
1531                 SAFE_FREE(tmp->file_path);
1532                 SAFE_FREE(tmp);
1533         }
1534 }
1535
1536 /****************************************************************************
1537  Seek in a directory/file list until you get something that doesn't start with
1538  the specified name.
1539 ****************************************************************************/
1540
1541 static bool seek_list(struct file_list *list, char *name)
1542 {
1543         while (list) {
1544                 trim_string(list->file_path,"./","\n");
1545                 if (strncmp(list->file_path, name, strlen(name)) != 0) {
1546                         return(True);
1547                 }
1548                 list = list->next;
1549         }
1550           
1551         return(False);
1552 }
1553
1554 /****************************************************************************
1555  Set the file selection mask.
1556 ****************************************************************************/
1557
1558 static int cmd_select(void)
1559 {
1560         pstrcpy(fileselection,"");
1561         next_token_nr(NULL,fileselection,NULL,sizeof(fileselection));
1562
1563         return 0;
1564 }
1565
1566 /****************************************************************************
1567   Recursive file matching function act as find
1568   match must be always set to True when calling this function
1569 ****************************************************************************/
1570
1571 static int file_find(struct file_list **list, const char *directory, 
1572                           const char *expression, bool match)
1573 {
1574         DIR *dir;
1575         struct file_list *entry;
1576                 struct stat statbuf;
1577                 int ret;
1578                 char *path;
1579         bool isdir;
1580         const char *dname;
1581
1582                 dir = opendir(directory);
1583         if (!dir)
1584                 return -1;
1585         
1586                 while ((dname = readdirname(dir))) {
1587                 if (!strcmp("..", dname))
1588                         continue;
1589                 if (!strcmp(".", dname))
1590                         continue;
1591                 
1592                 if (asprintf(&path, "%s/%s", directory, dname) <= 0) {
1593                         continue;
1594                 }
1595
1596                 isdir = False;
1597                 if (!match || !gen_fnmatch(expression, dname)) {
1598                         if (recurse) {
1599                                 ret = stat(path, &statbuf);
1600                                 if (ret == 0) {
1601                                         if (S_ISDIR(statbuf.st_mode)) {
1602                                                 isdir = True;
1603                                                 ret = file_find(list, path, expression, False);
1604                                         }
1605                                 } else {
1606                                         d_printf("file_find: cannot stat file %s\n", path);
1607                                 }
1608                                 
1609                                 if (ret == -1) {
1610                                         SAFE_FREE(path);
1611                                         closedir(dir);
1612                                         return -1;
1613                                 }
1614                         }
1615                         entry = SMB_MALLOC_P(struct file_list);
1616                         if (!entry) {
1617                                 d_printf("Out of memory in file_find\n");
1618                                 closedir(dir);
1619                                 return -1;
1620                         }
1621                         entry->file_path = path;
1622                         entry->isdir = isdir;
1623                                                 DLIST_ADD(*list, entry);
1624                 } else {
1625                         SAFE_FREE(path);
1626                 }
1627                 }
1628
1629         closedir(dir);
1630         return 0;
1631 }
1632
1633 /****************************************************************************
1634  mput some files.
1635 ****************************************************************************/
1636
1637 static int cmd_mput(void)
1638 {
1639         pstring buf;
1640         char *p=buf;
1641         
1642         while (next_token_nr(NULL,p,NULL,sizeof(buf))) {
1643                 int ret;
1644                 struct file_list *temp_list;
1645                 char *quest, *lname, *rname;
1646         
1647                 file_list = NULL;
1648
1649                 ret = file_find(&file_list, ".", p, True);
1650                 if (ret) {
1651                         free_file_list(file_list);
1652                         continue;
1653                 }
1654                 
1655                 quest = NULL;
1656                 lname = NULL;
1657                 rname = NULL;
1658                                 
1659                 for (temp_list = file_list; temp_list; 
1660                          temp_list = temp_list->next) {
1661
1662                         SAFE_FREE(lname);
1663                         if (asprintf(&lname, "%s/", temp_list->file_path) <= 0)
1664                                 continue;
1665                         trim_string(lname, "./", "/");
1666                         
1667                         /* check if it's a directory */
1668                         if (temp_list->isdir) {
1669                                 /* if (!recurse) continue; */
1670                                 
1671                                 SAFE_FREE(quest);
1672                                 if (asprintf(&quest, "Put directory %s? ", lname) < 0) break;
1673                                 if (prompt && !yesno(quest)) { /* No */
1674                                         /* Skip the directory */
1675                                         lname[strlen(lname)-1] = '/';
1676                                         if (!seek_list(temp_list, lname))
1677                                                 break;                  
1678                                 } else { /* Yes */
1679                                         SAFE_FREE(rname);
1680                                         if(asprintf(&rname, "smb:%s%s%s", service, cur_dir, lname) < 0) break;
1681                                         /*dos_format(rname);*/
1682                                         
1683                                         /* test if the directory exists by opening it */
1684                                         /*if (!((dh=smbc_opendir(rname)) < 0)) {
1685                                                 smbc_closedir(dh);
1686                                                 continue;
1687                                         }*/
1688                                         /* test if the directory exists by making it */
1689                                         ret = smbc_mkdir(rname, 755);
1690                                         if ((ret != 0) && (errno != EEXIST))
1691                                         {
1692                                                 d_printf("Error: %s. Unable to open or create dir %s, skipping...\n", strerror(errno), rname);
1693                                                 /* Skip the directory */
1694                                                 lname[strlen(lname)-1] = '/';
1695                                                 if (!seek_list(temp_list, lname))
1696                                                         break;
1697                                         }
1698                                 }
1699                                 continue;
1700                         } else {
1701                                 SAFE_FREE(quest);
1702                                 if (asprintf(&quest,"Put file %s? ", lname) < 0) break;
1703                                 if (prompt && !yesno(quest)) /* No */
1704                                         continue;
1705                                 
1706                                 /* Yes */
1707                                 SAFE_FREE(rname);
1708                                 if (asprintf(&rname, "smb:%s%s%s", service, cur_dir, lname) < 0) break;
1709                         }
1710
1711                         /*d_printf("PUT: rname: %s, lname: %s\n", rname, lname);*/
1712                         do_put(rname, lname, False);
1713                 }
1714                 free_file_list(file_list);
1715                 SAFE_FREE(quest);
1716                 SAFE_FREE(lname);
1717                 SAFE_FREE(rname);
1718         }
1719
1720         return 0;
1721 }
1722
1723 /****************************************************************************
1724  Cancel a print job.
1725 ****************************************************************************/
1726
1727 static int do_cancel(int job)
1728 {
1729         if (cli_printjob_del(cli, job)) {
1730                 d_printf("Job %d cancelled\n",job);
1731                 return 0;
1732         } else {
1733                 d_printf("Error cancelling job %d : %s\n",job,cli_errstr(cli));
1734                 return 1;
1735         }
1736 }
1737
1738 /****************************************************************************
1739  Cancel a print job.
1740 ****************************************************************************/
1741
1742 static int cmd_cancel(void)
1743 {
1744         pstring buf;
1745         int job; 
1746
1747         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1748                 d_printf("cancel <jobid> ...\n");
1749                 return 1;
1750         }
1751         do {
1752                 job = atoi(buf);
1753                 do_cancel(job);
1754         } while (next_token_nr(NULL,buf,NULL,sizeof(buf)));
1755         
1756         return 0;
1757 }
1758
1759 /****************************************************************************
1760  Print a file.
1761 ****************************************************************************/
1762
1763 static int cmd_print(void)
1764 {
1765         pstring lname;
1766         pstring rname;
1767         char *p;
1768
1769         if (!next_token_nr(NULL,lname,NULL, sizeof(lname))) {
1770                 d_printf("print <filename>\n");
1771                 return 1;
1772         }
1773
1774         pstrcpy(rname,lname);
1775         p = strrchr_m(rname,'/');
1776         if (p) {
1777                 slprintf(rname, sizeof(rname)-1, "%s-%d", p+1, (int)sys_getpid());
1778         }
1779
1780         if (strequal(lname,"-")) {
1781                 slprintf(rname, sizeof(rname)-1, "stdin-%d", (int)sys_getpid());
1782         }
1783
1784         return do_put(rname, lname, False);
1785 }
1786
1787 /****************************************************************************
1788  Show a print queue entry.
1789 ****************************************************************************/
1790
1791 static void queue_fn(struct print_job_info *p)
1792 {
1793         d_printf("%-6d   %-9d    %s\n", (int)p->id, (int)p->size, p->name);
1794 }
1795
1796 /****************************************************************************
1797  Show a print queue.
1798 ****************************************************************************/
1799
1800 static int cmd_queue(void)
1801 {
1802         cli_print_queue(cli, queue_fn);
1803         
1804         return 0;
1805 }
1806
1807 /****************************************************************************
1808  Delete some files.
1809 ****************************************************************************/
1810
1811 static void do_del(file_info *finfo)
1812 {
1813         pstring mask;
1814
1815         pstrcpy(mask,cur_dir);
1816         pstrcat(mask,finfo->name);
1817
1818         if (finfo->mode & aDIR) 
1819                 return;
1820
1821         if (!cli_unlink(cli, mask)) {
1822                 d_printf("%s deleting remote file %s\n",cli_errstr(cli),mask);
1823         }
1824 }
1825
1826 /****************************************************************************
1827  Delete some files.
1828 ****************************************************************************/
1829
1830 static int cmd_del(void)
1831 {
1832         pstring mask;
1833         pstring buf;
1834         uint16 attribute = aSYSTEM | aHIDDEN;
1835
1836         if (recurse)
1837                 attribute |= aDIR;
1838         
1839         pstrcpy(mask,cur_dir);
1840         
1841         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1842                 d_printf("del <filename>\n");
1843                 return 1;
1844         }
1845         pstrcat(mask,buf);
1846
1847         do_list(mask, attribute,do_del,False,False);
1848         
1849         return 0;
1850 }
1851
1852 /****************************************************************************
1853 ****************************************************************************/
1854
1855 static int cmd_open(void)
1856 {
1857         pstring mask;
1858         pstring buf;
1859         struct cli_state *targetcli;
1860         pstring targetname;
1861         
1862         pstrcpy(mask,cur_dir);
1863         
1864         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1865                 d_printf("open <filename>\n");
1866                 return 1;
1867         }
1868         pstrcat(mask,buf);
1869
1870         if ( !cli_resolve_path( "", cli, mask, &targetcli, targetname ) ) {
1871                 d_printf("open %s: %s\n", mask, cli_errstr(cli));
1872                 return 1;
1873         }
1874         
1875         cli_nt_create(targetcli, targetname, FILE_READ_DATA);
1876
1877         return 0;
1878 }
1879
1880
1881 /****************************************************************************
1882  Remove a directory.
1883 ****************************************************************************/
1884
1885 static int cmd_rmdir(void)
1886 {
1887         pstring mask;
1888         pstring buf;
1889         struct cli_state *targetcli;
1890         pstring targetname;
1891         
1892         pstrcpy(mask, "smb:");
1893         pstrcat(mask, service);
1894         pstrcat(mask,cur_dir);
1895         
1896         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1897                 d_printf("rmdir <dirname>\n");
1898                 return 1;
1899         }
1900         pstrcat(mask,buf);
1901
1902         /*if ( !cli_resolve_path( "", cli, mask, &targetcli, targetname ) ) {
1903                 d_printf("rmdir %s: %s\n", mask, cli_errstr(cli));
1904                 return 1;
1905         }
1906         
1907         if (!cli_rmdir(targetcli, targetname)) {
1908                 d_printf("%s removing remote directory file %s\n",
1909                          cli_errstr(targetcli),mask);
1910         }*/
1911         
1912         if (smbc_rmdir(mask) < 0)
1913                 d_printf("Error: %s removing remote directory file %s\n", strerror(errno), mask);
1914         
1915         return 0;
1916 }
1917
1918 /****************************************************************************
1919  UNIX hardlink.
1920 ****************************************************************************/
1921
1922 static int cmd_link(void)
1923 {
1924         pstring oldname,newname;
1925         pstring buf,buf2;
1926         struct cli_state *targetcli;
1927         pstring targetname;
1928   
1929         pstrcpy(oldname,cur_dir);
1930         pstrcpy(newname,cur_dir);
1931   
1932         if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) || 
1933                 !next_token_nr(NULL,buf2,NULL, sizeof(buf2))) {
1934                 d_printf("link <oldname> <newname>\n");
1935                 return 1;
1936         }
1937
1938         pstrcat(oldname,buf);
1939         pstrcat(newname,buf2);
1940
1941         if ( !cli_resolve_path( "", cli, oldname, &targetcli, targetname ) ) {
1942                 d_printf("link %s: %s\n", oldname, cli_errstr(cli));
1943                 return 1;
1944         }
1945         
1946         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
1947                 d_printf("Server doesn't support UNIX CIFS calls.\n");
1948                 return 1;
1949         }
1950         
1951         if (!cli_unix_hardlink(targetcli, targetname, newname)) {
1952                 d_printf("%s linking files (%s -> %s)\n", cli_errstr(targetcli), newname, oldname);
1953                 return 1;
1954         }  
1955
1956         return 0;
1957 }
1958
1959 /****************************************************************************
1960  UNIX symlink.
1961 ****************************************************************************/
1962
1963 static int cmd_symlink(void)
1964 {
1965         pstring oldname,newname;
1966         pstring buf,buf2;
1967   
1968         if (!SERVER_HAS_UNIX_CIFS(cli)) {
1969                 d_printf("Server doesn't support UNIX CIFS calls.\n");
1970                 return 1;
1971         }
1972
1973         pstrcpy(newname,cur_dir);
1974         
1975         if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) || 
1976                 !next_token_nr(NULL,buf2,NULL, sizeof(buf2))) {
1977                 d_printf("symlink <oldname> <newname>\n");
1978                 return 1;
1979         }
1980
1981         pstrcpy(oldname,buf);
1982         pstrcat(newname,buf2);
1983
1984         if (!cli_unix_symlink(cli, oldname, newname)) {
1985                 d_printf("%s symlinking files (%s -> %s)\n",
1986                         cli_errstr(cli), newname, oldname);
1987                 return 1;
1988         } 
1989
1990         return 0;
1991 }
1992
1993 /****************************************************************************
1994  UNIX chmod.
1995 ****************************************************************************/
1996
1997 static int cmd_chmod(void)
1998 {
1999         pstring src;
2000         mode_t mode;
2001         pstring buf, buf2;
2002         struct cli_state *targetcli;
2003         pstring targetname;
2004   
2005         pstrcpy(src,cur_dir);
2006         
2007         if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) || 
2008                 !next_token_nr(NULL,buf2,NULL, sizeof(buf2))) {
2009                 d_printf("chmod mode file\n");
2010                 return 1;
2011         }
2012
2013         mode = (mode_t)strtol(buf, NULL, 8);
2014         pstrcat(src,buf2);
2015
2016         if ( !cli_resolve_path( "", cli, src, &targetcli, targetname ) ) {
2017                 d_printf("chmod %s: %s\n", src, cli_errstr(cli));
2018                 return 1;
2019         }
2020         
2021         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
2022                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2023                 return 1;
2024         }
2025         
2026         if (!cli_unix_chmod(targetcli, targetname, mode)) {
2027                 d_printf("%s chmod file %s 0%o\n",
2028                         cli_errstr(targetcli), src, (unsigned int)mode);
2029                 return 1;
2030         } 
2031
2032         return 0;
2033 }
2034
2035 static const char *filetype_to_str(mode_t mode)
2036 {
2037         if (S_ISREG(mode)) {
2038                 return "regular file";
2039         } else if (S_ISDIR(mode)) {
2040                 return "directory";
2041         } else 
2042 #ifdef S_ISCHR
2043         if (S_ISCHR(mode)) {
2044                 return "character device";
2045         } else
2046 #endif
2047 #ifdef S_ISBLK
2048         if (S_ISBLK(mode)) {
2049                 return "block device";
2050         } else
2051 #endif
2052 #ifdef S_ISFIFO
2053         if (S_ISFIFO(mode)) {
2054                 return "fifo";
2055         } else
2056 #endif
2057 #ifdef S_ISLNK
2058         if (S_ISLNK(mode)) {
2059                 return "symbolic link";
2060         } else
2061 #endif
2062 #ifdef S_ISSOCK
2063         if (S_ISSOCK(mode)) {
2064                 return "socket";
2065         } else
2066 #endif
2067         return "";
2068 }
2069
2070 static char rwx_to_str(mode_t m, mode_t bt, char ret)
2071 {
2072         if (m & bt) {
2073                 return ret;
2074         } else {
2075                 return '-';
2076         }
2077 }
2078
2079 static char *unix_mode_to_str(char *s, mode_t m)
2080 {
2081         char *p = s;
2082         const char *str = filetype_to_str(m);
2083
2084         switch(str[0]) {
2085                 case 'd':
2086                         *p++ = 'd';
2087                         break;
2088                 case 'c':
2089                         *p++ = 'c';
2090                         break;
2091                 case 'b':
2092                         *p++ = 'b';
2093                         break;
2094                 case 'f':
2095                         *p++ = 'p';
2096                         break;
2097                 case 's':
2098                         *p++ = str[1] == 'y' ? 'l' : 's';
2099                         break;
2100                 case 'r':
2101                 default:
2102                         *p++ = '-';
2103                         break;
2104         }
2105         *p++ = rwx_to_str(m, S_IRUSR, 'r');
2106         *p++ = rwx_to_str(m, S_IWUSR, 'w');
2107         *p++ = rwx_to_str(m, S_IXUSR, 'x');
2108         *p++ = rwx_to_str(m, S_IRGRP, 'r');
2109         *p++ = rwx_to_str(m, S_IWGRP, 'w');
2110         *p++ = rwx_to_str(m, S_IXGRP, 'x');
2111         *p++ = rwx_to_str(m, S_IROTH, 'r');
2112         *p++ = rwx_to_str(m, S_IWOTH, 'w');
2113         *p++ = rwx_to_str(m, S_IXOTH, 'x');
2114         *p++ = '\0';
2115         return s;
2116 }
2117
2118 /****************************************************************************
2119  Utility function for UNIX getfacl.
2120 ****************************************************************************/
2121
2122 static char *perms_to_string(fstring permstr, unsigned char perms)
2123 {
2124         fstrcpy(permstr, "---");
2125         if (perms & SMB_POSIX_ACL_READ) {
2126                 permstr[0] = 'r';
2127         }
2128         if (perms & SMB_POSIX_ACL_WRITE) {
2129                 permstr[1] = 'w';
2130         }
2131         if (perms & SMB_POSIX_ACL_EXECUTE) {
2132                 permstr[2] = 'x';
2133         }
2134         return permstr;
2135 }
2136
2137 /****************************************************************************
2138  UNIX getfacl.
2139 ****************************************************************************/
2140
2141 static int cmd_getfacl(void)
2142 {
2143         pstring src, name;
2144         uint16 major, minor;
2145         uint32 caplow, caphigh;
2146         char *retbuf = NULL;
2147         size_t rb_size = 0;
2148         SMB_STRUCT_STAT sbuf;
2149         uint16 num_file_acls = 0;
2150         uint16 num_dir_acls = 0;
2151         uint16 i;
2152         struct cli_state *targetcli;
2153         pstring targetname;
2154  
2155         pstrcpy(src,cur_dir);
2156         
2157         if (!next_token_nr(NULL,name,NULL,sizeof(name))) {
2158                 d_printf("stat file\n");
2159                 return 1;
2160         }
2161
2162         pstrcat(src,name);
2163         
2164         if ( !cli_resolve_path( "", cli, src, &targetcli, targetname ) ) {
2165                 d_printf("stat %s: %s\n", src, cli_errstr(cli));
2166                 return 1;
2167         }
2168         
2169         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
2170                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2171                 return 1;
2172         }
2173         
2174         if (!cli_unix_extensions_version(targetcli, &major, &minor, &caplow, &caphigh)) {
2175                 d_printf("Can't get UNIX CIFS version from server.\n");
2176                 return 1;
2177         }
2178
2179         if (!(caplow & CIFS_UNIX_POSIX_ACLS_CAP)) {
2180                 d_printf("This server supports UNIX extensions but doesn't support POSIX ACLs.\n");
2181                 return 1;
2182         }
2183
2184
2185         if (!cli_unix_stat(targetcli, targetname, &sbuf)) {
2186                 d_printf("%s getfacl doing a stat on file %s\n",
2187                         cli_errstr(targetcli), src);
2188                 return 1;
2189         } 
2190
2191         if (!cli_unix_getfacl(targetcli, targetname, &rb_size, &retbuf)) {
2192                 d_printf("%s getfacl file %s\n",
2193                         cli_errstr(targetcli), src);
2194                 return 1;
2195         } 
2196
2197         /* ToDo : Print out the ACL values. */
2198         if (SVAL(retbuf,0) != SMB_POSIX_ACL_VERSION || rb_size < 6) {
2199                 d_printf("getfacl file %s, unknown POSIX acl version %u.\n",
2200                         src, (unsigned int)CVAL(retbuf,0) );
2201                 SAFE_FREE(retbuf);
2202                 return 1;
2203         }
2204
2205         num_file_acls = SVAL(retbuf,2);
2206         num_dir_acls = SVAL(retbuf,4);
2207         if (rb_size != SMB_POSIX_ACL_HEADER_SIZE + SMB_POSIX_ACL_ENTRY_SIZE*(num_file_acls+num_dir_acls)) {
2208                 d_printf("getfacl file %s, incorrect POSIX acl buffer size (should be %u, was %u).\n",
2209                         src,
2210                         (unsigned int)(SMB_POSIX_ACL_HEADER_SIZE + SMB_POSIX_ACL_ENTRY_SIZE*(num_file_acls+num_dir_acls)),
2211                         (unsigned int)rb_size);
2212
2213                 SAFE_FREE(retbuf);
2214                 return 1;
2215         }
2216
2217         d_printf("# file: %s\n", src);
2218         d_printf("# owner: %u\n# group: %u\n", (unsigned int)sbuf.st_uid, (unsigned int)sbuf.st_gid);
2219
2220         if (num_file_acls == 0 && num_dir_acls == 0) {
2221                 d_printf("No acls found.\n");
2222         }
2223
2224         for (i = 0; i < num_file_acls; i++) {
2225                 uint32 uorg;
2226                 fstring permstring;
2227                 unsigned char tagtype = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE));
2228                 unsigned char perms = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+1);
2229
2230                 switch(tagtype) {
2231                         case SMB_POSIX_ACL_USER_OBJ:
2232                                 d_printf("user::");
2233                                 break;
2234                         case SMB_POSIX_ACL_USER:
2235                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
2236                                 d_printf("user:%u:", uorg);
2237                                 break;
2238                         case SMB_POSIX_ACL_GROUP_OBJ:
2239                                 d_printf("group::");
2240                                 break;
2241                         case SMB_POSIX_ACL_GROUP:
2242                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
2243                                 d_printf("group:%u", uorg);
2244                                 break;
2245                         case SMB_POSIX_ACL_MASK:
2246                                 d_printf("mask::");
2247                                 break;
2248                         case SMB_POSIX_ACL_OTHER:
2249                                 d_printf("other::");
2250                                 break;
2251                         default:
2252                                 d_printf("getfacl file %s, incorrect POSIX acl tagtype (%u).\n",
2253                                         src, (unsigned int)tagtype );
2254                                 SAFE_FREE(retbuf);
2255                                 return 1;
2256                 }
2257
2258                 d_printf("%s\n", perms_to_string(permstring, perms));
2259         }
2260
2261         for (i = 0; i < num_dir_acls; i++) {
2262                 uint32 uorg;
2263                 fstring permstring;
2264                 unsigned char tagtype = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE));
2265                 unsigned char perms = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+1);
2266
2267                 switch(tagtype) {
2268                         case SMB_POSIX_ACL_USER_OBJ:
2269                                 d_printf("default:user::");
2270                                 break;
2271                         case SMB_POSIX_ACL_USER:
2272                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+2);
2273                                 d_printf("default:user:%u:", uorg);
2274                                 break;
2275                         case SMB_POSIX_ACL_GROUP_OBJ:
2276                                 d_printf("default:group::");
2277                                 break;
2278                         case SMB_POSIX_ACL_GROUP:
2279                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+2);
2280                                 d_printf("default:group:%u", uorg);
2281                                 break;
2282                         case SMB_POSIX_ACL_MASK:
2283                                 d_printf("default:mask::");
2284                                 break;
2285                         case SMB_POSIX_ACL_OTHER:
2286                                 d_printf("default:other::");
2287                                 break;
2288                         default:
2289                                 d_printf("getfacl file %s, incorrect POSIX acl tagtype (%u).\n",
2290                                         src, (unsigned int)tagtype );
2291                                 SAFE_FREE(retbuf);
2292                                 return 1;
2293                 }
2294
2295                 d_printf("%s\n", perms_to_string(permstring, perms));
2296         }
2297
2298         SAFE_FREE(retbuf);
2299         return 0;
2300 }
2301
2302 /****************************************************************************
2303  UNIX stat.
2304 ****************************************************************************/
2305
2306 static int cmd_stat(void)
2307 {
2308         pstring src, name;
2309         fstring mode_str;
2310         SMB_STRUCT_STAT sbuf;
2311         struct cli_state *targetcli;
2312         struct tm *lt;
2313         pstring targetname;
2314  
2315         if (!SERVER_HAS_UNIX_CIFS(cli)) {
2316                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2317                 return 1;
2318         }
2319
2320         pstrcpy(src,cur_dir);
2321         
2322         if (!next_token_nr(NULL,name,NULL,sizeof(name))) {
2323                 d_printf("stat file\n");
2324                 return 1;
2325         }
2326
2327         pstrcat(src,name);
2328
2329         
2330         if ( !cli_resolve_path( "", cli, src, &targetcli, targetname ) ) {
2331                 d_printf("stat %s: %s\n", src, cli_errstr(cli));
2332                 return 1;
2333         }
2334         
2335         if (!cli_unix_stat(targetcli, targetname, &sbuf)) {
2336                 d_printf("%s stat file %s\n",
2337                         cli_errstr(targetcli), src);
2338                 return 1;
2339         } 
2340
2341         /* Print out the stat values. */
2342         d_printf("File: %s\n", src);
2343         d_printf("Size: %-12.0f\tBlocks: %u\t%s\n",
2344                 (double)sbuf.st_size,
2345                 (unsigned int)sbuf.st_blocks,
2346                 filetype_to_str(sbuf.st_mode));
2347
2348 #if defined(S_ISCHR) && defined(S_ISBLK)
2349         if (S_ISCHR(sbuf.st_mode) || S_ISBLK(sbuf.st_mode)) {
2350                 d_printf("Inode: %.0f\tLinks: %u\tDevice type: %u,%u\n",
2351                         (double)sbuf.st_ino,
2352                         (unsigned int)sbuf.st_nlink,
2353                         unix_dev_major(sbuf.st_rdev),
2354                         unix_dev_minor(sbuf.st_rdev));
2355         } else 
2356 #endif
2357                 d_printf("Inode: %.0f\tLinks: %u\n",
2358                         (double)sbuf.st_ino,
2359                         (unsigned int)sbuf.st_nlink);
2360
2361         d_printf("Access: (0%03o/%s)\tUid: %u\tGid: %u\n",
2362                 ((int)sbuf.st_mode & 0777),
2363                 unix_mode_to_str(mode_str, sbuf.st_mode),
2364                 (unsigned int)sbuf.st_uid, 
2365                 (unsigned int)sbuf.st_gid);
2366
2367         lt = localtime(&sbuf.st_atime);
2368         if (lt) {
2369                 strftime(mode_str, sizeof(mode_str), "%F %T %z", lt);
2370         } else {
2371                 fstrcpy(mode_str, "unknown");
2372         }
2373         d_printf("Access: %s\n", mode_str);
2374
2375         lt = localtime(&sbuf.st_mtime);
2376         if (lt) {
2377                 strftime(mode_str, sizeof(mode_str), "%F %T %z", lt);
2378         } else {
2379                 fstrcpy(mode_str, "unknown");
2380         }
2381         d_printf("Modify: %s\n", mode_str);
2382
2383         lt = localtime(&sbuf.st_ctime);
2384         if (lt) {
2385                 strftime(mode_str, sizeof(mode_str), "%F %T %z", lt);
2386         } else {
2387                 fstrcpy(mode_str, "unknown");
2388         }
2389         d_printf("Change: %s\n", mode_str);
2390
2391         return 0;
2392 }
2393
2394
2395 /****************************************************************************
2396  UNIX chown.
2397 ****************************************************************************/
2398
2399 static int cmd_chown(void)
2400 {
2401         pstring src;
2402         uid_t uid;
2403         gid_t gid;
2404         pstring buf, buf2, buf3;
2405         struct cli_state *targetcli;
2406         pstring targetname;
2407   
2408         pstrcpy(src,cur_dir);
2409         
2410         if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) || 
2411                 !next_token_nr(NULL,buf2,NULL, sizeof(buf2)) ||
2412                 !next_token_nr(NULL,buf3,NULL, sizeof(buf3))) {
2413                 d_printf("chown uid gid file\n");
2414                 return 1;
2415         }
2416
2417         uid = (uid_t)atoi(buf);
2418         gid = (gid_t)atoi(buf2);
2419         pstrcat(src,buf3);
2420
2421         if ( !cli_resolve_path( "", cli, src, &targetcli, targetname ) ) {
2422                 d_printf("chown %s: %s\n", src, cli_errstr(cli));
2423                 return 1;
2424         }
2425
2426
2427         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
2428                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2429                 return 1;
2430         }
2431         
2432         if (!cli_unix_chown(targetcli, targetname, uid, gid)) {
2433                 d_printf("%s chown file %s uid=%d, gid=%d\n",
2434                         cli_errstr(targetcli), src, (int)uid, (int)gid);
2435                 return 1;
2436         } 
2437
2438         return 0;
2439 }
2440
2441 /****************************************************************************
2442  Rename some file.
2443 ****************************************************************************/
2444
2445 static int cmd_rename(void)
2446 {
2447         int err;
2448         pstring src, dest;
2449         pstring oname, nname;
2450   
2451         pstrcpy(src, "smb:");
2452         pstrcat(src, service);
2453         pstrcat(src, cur_dir);
2454         pstrcpy(dest, src);
2455         
2456         if (!next_token_nr(NULL,oname,NULL,sizeof(oname)) || 
2457                 !next_token_nr(NULL,nname,NULL, sizeof(nname))) {
2458                 d_printf("rename <src> <dest>\n");
2459                 return 1;
2460         }
2461
2462         pstrcat(src, oname);
2463         pstrcat(dest, nname);
2464         
2465         DEBUG(4, ("O: %s\nN: %s\n", src, dest));
2466
2467         err = smbc_rename(src, dest);
2468         if (err < 0)
2469         {
2470                 d_printf("%s renaming files\n", strerror(errno));
2471                 return 1;
2472         }
2473         
2474         return 0;
2475 }
2476
2477 /****************************************************************************
2478  Print the volume name.
2479 ****************************************************************************/
2480
2481 static int cmd_volume(void)
2482 {
2483         fstring volname;
2484         uint32 serial_num;
2485         time_t create_date;
2486   
2487         if (!cli_get_fs_volume_info(cli, volname, &serial_num, &create_date)) {
2488                 d_printf("Errr %s getting volume info\n",cli_errstr(cli));
2489                 return 1;
2490         }
2491         
2492         d_printf("Volume: |%s| serial number 0x%x\n", volname, (unsigned int)serial_num);
2493         return 0;
2494 }
2495
2496 /****************************************************************************
2497  Hard link files using the NT call.
2498 ****************************************************************************/
2499
2500 static int cmd_hardlink(void)
2501 {
2502         pstring src,dest;
2503         pstring buf,buf2;
2504         struct cli_state *targetcli;
2505         pstring targetname;
2506   
2507         pstrcpy(src,cur_dir);
2508         pstrcpy(dest,cur_dir);
2509         
2510         if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) || 
2511                 !next_token_nr(NULL,buf2,NULL, sizeof(buf2))) {
2512                 d_printf("hardlink <src> <dest>\n");
2513                 return 1;
2514         }
2515
2516         pstrcat(src,buf);
2517         pstrcat(dest,buf2);
2518
2519         if ( !cli_resolve_path( "", cli, src, &targetcli, targetname ) ) {
2520                 d_printf("hardlink %s: %s\n", src, cli_errstr(cli));
2521                 return 1;
2522         }
2523         
2524         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
2525                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2526                 return 1;
2527         }
2528         
2529         if (!cli_nt_hardlink(targetcli, targetname, dest)) {
2530                 d_printf("%s doing an NT hard link of files\n",cli_errstr(targetcli));
2531                 return 1;
2532         }
2533         
2534         return 0;
2535 }
2536
2537 /****************************************************************************
2538  Toggle the prompt flag.
2539 ****************************************************************************/
2540
2541 static int cmd_prompt(void)
2542 {
2543         prompt = !prompt;
2544         DEBUG(2,("prompting is now %s\n",prompt?"on":"off"));
2545         
2546         return 1;
2547 }
2548
2549 /****************************************************************************
2550  Set the newer than time.
2551 ****************************************************************************/
2552
2553 static int cmd_newer(void)
2554 {
2555         pstring buf;
2556         bool ok;
2557         SMB_STRUCT_STAT sbuf;
2558
2559         ok = next_token_nr(NULL,buf,NULL,sizeof(buf));
2560         if (ok && (sys_stat(buf,&sbuf) == 0)) {
2561                 newer_than = sbuf.st_mtime;
2562                 DEBUG(1,("Getting files newer than %s",
2563                          time_to_asc(newer_than)));
2564         } else {
2565                 newer_than = 0;
2566         }
2567
2568         if (ok && newer_than == 0) {
2569                 d_printf("Error setting newer-than time\n");
2570                 return 1;
2571         }
2572
2573         return 0;
2574 }
2575
2576 /****************************************************************************
2577  Set the archive level.
2578 ****************************************************************************/
2579
2580 static int cmd_archive(void)
2581 {
2582         pstring buf;
2583
2584         if (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
2585                 archive_level = atoi(buf);
2586         } else
2587                 d_printf("Archive level is %d\n",archive_level);
2588
2589         return 0;
2590 }
2591
2592 /****************************************************************************
2593  Toggle the lowercaseflag.
2594 ****************************************************************************/
2595
2596 static int cmd_lowercase(void)
2597 {
2598         lowercase = !lowercase;
2599         DEBUG(2,("filename lowercasing is now %s\n",lowercase?"on":"off"));
2600
2601         return 0;
2602 }
2603
2604 /****************************************************************************
2605  Toggle the case sensitive flag.
2606 ****************************************************************************/
2607
2608 static int cmd_setcase(void)
2609 {
2610         bool orig_case_sensitive = cli_set_case_sensitive(cli, False);
2611
2612         cli_set_case_sensitive(cli, !orig_case_sensitive);
2613         DEBUG(2,("filename case sensitivity is now %s\n",!orig_case_sensitive ?
2614                 "on":"off"));
2615
2616         return 0;
2617 }
2618
2619 /****************************************************************************
2620  Toggle the recurse flag.
2621 ****************************************************************************/
2622
2623 static int cmd_recurse(void)
2624 {
2625         recurse = !recurse;
2626         DEBUG(2,("directory recursion is now %s\n",recurse?"on":"off"));
2627
2628         return 0;
2629 }
2630
2631 /****************************************************************************
2632  Toggle the translate flag.
2633 ****************************************************************************/
2634
2635 static int cmd_translate(void)
2636 {
2637         translation = !translation;
2638         DEBUG(2,("CR/LF<->LF and print text translation now %s\n",
2639                  translation?"on":"off"));
2640
2641         return 0;
2642 }
2643
2644 /****************************************************************************
2645  Do the lcd command.
2646  ****************************************************************************/
2647
2648 static int cmd_lcd(void)
2649 {
2650         pstring buf;
2651         pstring d;
2652         
2653         if (next_token_nr(NULL,buf,NULL,sizeof(buf)))
2654                 chdir(buf);
2655         DEBUG(2,("the local directory is now %s\n",sys_getwd(d)));
2656
2657         return 0;
2658 }
2659
2660 /****************************************************************************
2661  Get a file restarting at end of local file.
2662  ****************************************************************************/
2663
2664 static int cmd_reget(void)
2665 {
2666         pstring local_name;
2667         pstring remote_name;
2668         char *p;
2669
2670         pstrcpy(remote_name, cur_dir);
2671         pstrcat(remote_name, "/");
2672         
2673         p = remote_name + strlen(remote_name);
2674         
2675         if (!next_token_nr(NULL, p, NULL, sizeof(remote_name) - strlen(remote_name))) {
2676                 d_printf("reget <filename>\n");
2677                 return 1;
2678         }
2679         pstrcpy(local_name, p);
2680         clean_name(remote_name);
2681         
2682         next_token_nr(NULL, local_name, NULL, sizeof(local_name));
2683         
2684         return do_get(remote_name, local_name, True);
2685 }
2686
2687 /****************************************************************************
2688  Put a file restarting at end of local file.
2689  ****************************************************************************/
2690
2691 static int cmd_reput(void)
2692 {
2693         pstring local_name;
2694         pstring remote_name;
2695         pstring buf;
2696         char *p = buf;
2697         SMB_STRUCT_STAT st;
2698         
2699         pstrcpy(remote_name, cur_dir);
2700         pstrcat(remote_name, "/");
2701   
2702         if (!next_token_nr(NULL, p, NULL, sizeof(buf))) {
2703                 d_printf("reput <filename>\n");
2704                 return 1;
2705         }
2706         pstrcpy(local_name, p);
2707   
2708         if (!file_exist(local_name, &st)) {
2709                 d_printf("%s does not exist\n", local_name);
2710                 return 1;
2711         }
2712
2713         if (next_token_nr(NULL, p, NULL, sizeof(buf)))
2714                 pstrcat(remote_name, p);
2715         else
2716                 pstrcat(remote_name, local_name);
2717         
2718         clean_name(remote_name);
2719
2720         return do_put(remote_name, local_name, True);
2721 }
2722
2723 /****************************************************************************
2724  List a share name.
2725  ****************************************************************************/
2726
2727 static void browse_fn(const char *name, uint32 m, 
2728                       const char *comment, void *state)
2729 {
2730         fstring typestr;
2731
2732         *typestr=0;
2733
2734         switch (m)
2735         {
2736           case STYPE_DISKTREE:
2737             fstrcpy(typestr,"Disk"); break;
2738           case STYPE_PRINTQ:
2739             fstrcpy(typestr,"Printer"); break;
2740           case STYPE_DEVICE:
2741             fstrcpy(typestr,"Device"); break;
2742           case STYPE_IPC:
2743             fstrcpy(typestr,"IPC"); break;
2744         }
2745         /* FIXME: If the remote machine returns non-ascii characters
2746            in any of these fields, they can corrupt the output.  We
2747            should remove them. */
2748         if (!grepable) {
2749                 d_printf("\t%-15s %-10.10s%s\n",
2750                         name,typestr,comment);
2751         } else {
2752                 d_printf ("%s|%s|%s\n",typestr,name,comment);
2753         }
2754 }
2755
2756 /****************************************************************************
2757  Try and browse available connections on a host.
2758 ****************************************************************************/
2759
2760 static bool browse_host(bool sort)
2761 {
2762         int ret;
2763         if (!grepable) {
2764                 d_printf("\n\tSharename       Type      Comment\n");
2765                 d_printf("\t---------       ----      -------\n");
2766         }
2767
2768         if((ret = cli_RNetShareEnum(cli, browse_fn, NULL)) == -1)
2769                 d_printf("Error returning browse list: %s\n", cli_errstr(cli));
2770
2771         return (ret != -1);
2772 }
2773
2774 /****************************************************************************
2775  List a server name.
2776 ****************************************************************************/
2777
2778 static void server_fn(const char *name, uint32 m, 
2779                       const char *comment, void *state)
2780 {
2781         
2782         if (!grepable){
2783                 d_printf("\t%-16s     %s\n", name, comment);
2784         } else {
2785                 d_printf("%s|%s|%s\n",(char *)state, name, comment);
2786         }
2787 }
2788
2789 /****************************************************************************
2790  Try and browse available connections on a host.
2791 ****************************************************************************/
2792
2793 static bool list_servers(const char *wk_grp)
2794 {
2795         fstring state;
2796
2797         if (!cli->server_domain)
2798                 return False;
2799
2800         if (!grepable) {
2801                 d_printf("\n\tServer               Comment\n");
2802                 d_printf("\t---------            -------\n");
2803         };
2804         fstrcpy( state, "Server" );
2805         cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_ALL, server_fn,
2806                           state);
2807
2808         if (!grepable) {
2809                 d_printf("\n\tWorkgroup            Master\n");
2810                 d_printf("\t---------            -------\n");
2811         }; 
2812
2813         fstrcpy( state, "Workgroup" );
2814         cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_DOMAIN_ENUM,
2815                           server_fn, state);
2816         return True;
2817 }
2818
2819 /****************************************************************************
2820  Print or set current VUID
2821 ****************************************************************************/
2822
2823 static int cmd_vuid(void)
2824 {
2825         fstring buf;
2826         
2827         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
2828                 d_printf("Current VUID is %d\n", cli->vuid);
2829                 return 0;
2830         }
2831
2832         cli->vuid = atoi(buf);
2833         return 0;
2834 }
2835
2836 /****************************************************************************
2837  Setup a new VUID, by issuing a session setup
2838 ****************************************************************************/
2839
2840 static int cmd_logon(void)
2841 {
2842         pstring l_username, l_password;
2843         pstring buf,buf2;
2844   
2845         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
2846                 d_printf("logon <username> [<password>]\n");
2847                 return 0;
2848         }
2849
2850         pstrcpy(l_username, buf);
2851
2852         if (!next_token_nr(NULL,buf2,NULL,sizeof(buf))) 
2853         {
2854                 char *pass = getpass("Password: ");
2855                 if (pass) 
2856                         pstrcpy(l_password, pass);
2857         } 
2858         else
2859                 pstrcpy(l_password, buf2);
2860
2861         if (!cli_session_setup(cli, l_username, 
2862                                    l_password, strlen(l_password),
2863                                    l_password, strlen(l_password),
2864                                    lp_workgroup())) {
2865                 d_printf("session setup failed: %s\n", cli_errstr(cli));
2866                 return -1;
2867         }
2868
2869         d_printf("Current VUID is %d\n", cli->vuid);
2870         return 0;
2871 }
2872
2873
2874 /****************************************************************************
2875  list active connections
2876 ****************************************************************************/
2877
2878 static int cmd_list_connect(void)
2879 {
2880         cli_cm_display();
2881
2882         return 0;
2883 }
2884
2885 /****************************************************************************
2886  display the current active client connection
2887 ****************************************************************************/
2888
2889 static int cmd_show_connect( void )
2890 {
2891         struct cli_state *targetcli;
2892         pstring targetpath;
2893         
2894         if ( !cli_resolve_path( "", cli, cur_dir, &targetcli, targetpath ) ) {
2895                 d_printf("showconnect %s: %s\n", cur_dir, cli_errstr(cli));
2896                 return 1;
2897         }
2898         
2899         d_printf("//%s/%s\n", targetcli->desthost, targetcli->share);
2900         return 0;
2901 }
2902
2903 /* Some constants for completing filename arguments */
2904
2905 #define COMPL_NONE                0                      /* No completions */
2906 #define COMPL_REMOTE      1                      /* Complete remote filename */
2907 #define COMPL_LOCAL               2                      /* Complete local filename */
2908
2909 /* This defines the commands supported by this client.
2910  * NOTE: The "!" must be the last one in the list because it's fn pointer
2911  *               field is NULL, and NULL in that field is used in process_tok()
2912  *               (below) to indicate the end of the list.  crh
2913  */
2914 static struct
2915 {
2916   const char *name;
2917   int (*fn)(void);
2918   const char *description;
2919   char compl_args[2];      /* Completion argument info */
2920 } commands[] = {
2921   {"?",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
2922 /*       {"altname",cmd_altname,"<file> show alt name",{COMPL_NONE,COMPL_NONE}}, */
2923   {"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}},
2924   {"blocksize",cmd_block,"blocksize <number> (default 20)",{COMPL_NONE,COMPL_NONE}},
2925 /*       {"cancel",cmd_cancel,"<jobid> cancel a print queue entry",{COMPL_NONE,COMPL_NONE}}, */
2926 /*       {"case_sensitive",cmd_setcase,"toggle the case sensitive flag to server",{COMPL_NONE,COMPL_NONE}}, */
2927   {"cd",cmd_cd,"[directory] change/report the remote directory",{COMPL_REMOTE,COMPL_NONE}},
2928 /*       {"chmod",cmd_chmod,"<src> <mode> chmod a file using UNIX permission",{COMPL_REMOTE,COMPL_REMOTE}}, */
2929 /*       {"chown",cmd_chown,"<src> <uid> <gid> chown a file using UNIX uids and gids",{COMPL_REMOTE,COMPL_REMOTE}}, */
2930 /*       {"del",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}}, */
2931   {"dir",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
2932 /*       {"du",cmd_du,"<mask> computes the total size of the current directory",{COMPL_REMOTE,COMPL_NONE}}, */
2933   {"exit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
2934   {"get",cmd_get,"<remote name> [local name] get a file",{COMPL_REMOTE,COMPL_LOCAL}},
2935 /*       {"getfacl",cmd_getfacl,"<file name> get the POSIX ACL on a file (UNIX extensions only)",{COMPL_REMOTE,COMPL_LOCAL}}, */
2936 /*       {"hardlink",cmd_hardlink,"<src> <dest> create a Windows hard link",{COMPL_REMOTE,COMPL_REMOTE}}, */
2937   {"help",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
2938   {"history",cmd_history,"displays the command history",{COMPL_NONE,COMPL_NONE}},
2939   {"lcd",cmd_lcd,"[directory] change/report the local current working directory",{COMPL_LOCAL,COMPL_NONE}},
2940 /*       {"link",cmd_link,"<oldname> <newname> create a UNIX hard link",{COMPL_REMOTE,COMPL_REMOTE}}, */
2941 /*       {"listconnect",cmd_list_connect,"list open connections",{COMPL_NONE,COMPL_NONE}}, */
2942 /*       {"logon",cmd_logon,"establish new logon",{COMPL_NONE,COMPL_NONE}}, */
2943   {"lowercase",cmd_lowercase,"toggle lowercasing of filenames for get",{COMPL_NONE,COMPL_NONE}},  
2944   {"ls",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
2945 /*       {"mask",cmd_select,"<mask> mask all filenames against this",{COMPL_REMOTE,COMPL_NONE}}, */
2946   {"md",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
2947   {"mget",cmd_mget,"<mask> get all the matching files",{COMPL_REMOTE,COMPL_NONE}},
2948   {"mkdir",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
2949 /*       {"more",cmd_more,"<remote name> view a remote file with your pager",{COMPL_REMOTE,COMPL_NONE}}, */      
2950   {"mput",cmd_mput,"<mask> put all matching files",{COMPL_REMOTE,COMPL_NONE}},
2951   {"newer",cmd_newer,"<file> only mget files newer than the specified local file",{COMPL_LOCAL,COMPL_NONE}},
2952 /*       {"open",cmd_open,"<mask> open a file",{COMPL_REMOTE,COMPL_NONE}}, */
2953 /*       {"print",cmd_print,"<file name> print a file",{COMPL_NONE,COMPL_NONE}}, */
2954   {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput",{COMPL_NONE,COMPL_NONE}},      
2955   {"put",cmd_put,"<local name> [remote name] put a file",{COMPL_LOCAL,COMPL_REMOTE}},
2956   {"pwd",cmd_pwd,"show current remote directory (same as 'cd' with no args)",{COMPL_NONE,COMPL_NONE}},
2957   {"q",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
2958 /*       {"queue",cmd_queue,"show the print queue",{COMPL_NONE,COMPL_NONE}}, */
2959   {"quit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
2960   {"rd",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
2961   {"recurse",cmd_recurse,"toggle directory recursion for mget and mput",{COMPL_NONE,COMPL_NONE}},
2962 /*      {"reget",cmd_reget,"<remote name> [local name] get a file restarting at end of local file",{COMPL_REMOTE,COMPL_LOCAL}},*/
2963   {"rename",cmd_rename,"<src> <dest> rename some files",{COMPL_REMOTE,COMPL_REMOTE}},
2964 /*      {"reput",cmd_reput,"<local name> [remote name] put a file restarting at end of remote file",{COMPL_LOCAL,COMPL_REMOTE}},*/
2965 /*      {"rm",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},*/
2966   {"rmdir",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
2967 /*      {"setmode",cmd_setmode,"filename <setmode string> change modes of file",{COMPL_REMOTE,COMPL_NONE}},*/
2968 /*      {"showconnect",cmd_show_connect,"display the current active connection",{COMPL_NONE,COMPL_NONE}},*/
2969 /*      {"stat",cmd_stat,"filename Do a UNIX extensions stat call on a file",{COMPL_REMOTE,COMPL_REMOTE}},*/
2970 /*      {"symlink",cmd_symlink,"<oldname> <newname> create a UNIX symlink",{COMPL_REMOTE,COMPL_REMOTE}},*/
2971   {"tar",cmd_tar,"tar <c|x>[IXFqbgNan] current directory to/from <file name>",{COMPL_NONE,COMPL_NONE}},
2972   {"tarmode",cmd_tarmode,"<full|inc|reset|noreset> tar's behaviour towards archive bits",{COMPL_NONE,COMPL_NONE}},
2973   {"translate",cmd_translate,"toggle text translation for printing",{COMPL_NONE,COMPL_NONE}},
2974 /*      {"volume",cmd_volume,"print the volume name",{COMPL_NONE,COMPL_NONE}}, */
2975 /*      {"vuid",cmd_vuid,"change current vuid",{COMPL_NONE,COMPL_NONE}}, */
2976   
2977   /* Yes, this must be here, see crh's comment above. */
2978   {"!",NULL,"run a shell command on the local system",{COMPL_NONE,COMPL_NONE}},
2979   {NULL,NULL,NULL,{COMPL_NONE,COMPL_NONE}}
2980 };
2981
2982 /*******************************************************************
2983  Lookup a command string in the list of commands, including 
2984  abbreviations.
2985 ******************************************************************/
2986
2987 static int process_tok(pstring tok)
2988 {
2989         int i = 0, matches = 0;
2990         int cmd=0;
2991         int tok_len = strlen(tok);
2992         
2993         while ((commands[i].fn != NULL) || (strequal(commands[i].name, "!"))) {
2994                 if (strequal(commands[i].name,tok)) {
2995                         matches = 1;
2996                         cmd = i;
2997                         break;
2998                 } else if (strnequal(commands[i].name, tok, tok_len)) {
2999                         matches++;
3000                         cmd = i;
3001                 }
3002                 i++;
3003         }
3004   
3005         if (matches == 0)
3006                 return(-1);
3007         else if (matches == 1)
3008                 return(cmd);
3009         else
3010                 return(-2);
3011 }
3012
3013 /****************************************************************************
3014  Help.
3015 ****************************************************************************/
3016
3017 static int cmd_help(void)
3018 {
3019         int i=0,j;
3020         pstring buf;
3021         
3022         if (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
3023                 if ((i = process_tok(buf)) >= 0)
3024                         d_printf("HELP %s:\n\t%s\n\n",commands[i].name,commands[i].description);
3025         } else {
3026                 while (commands[i].description) {
3027                         for (j=0; commands[i].description && (j<5); j++) {
3028                                 d_printf("%-15s",commands[i].name);
3029                                 i++;
3030                         }
3031                         d_printf("\n");
3032                 }
3033         }
3034         return 0;
3035 }
3036
3037 /****************************************************************************
3038  Process a -c command string.
3039 ****************************************************************************/
3040
3041 static int process_command_string(char *cmd)
3042 {
3043         pstring line;
3044         const char *ptr;
3045         int rc = 0;
3046
3047         /* establish the connection if not already */
3048         
3049         if (!cli) {
3050                 cli = cli_cm_open(desthost, service, True);
3051                 if (!cli)
3052                         return 0;
3053         }
3054         
3055         while (cmd[0] != '\0')    {
3056                 char *p;
3057                 pstring tok;
3058                 int i;
3059                 
3060                 if ((p = strchr_m(cmd, ';')) == 0) {
3061                         strncpy(line, cmd, 999);
3062                         line[1000] = '\0';
3063                         cmd += strlen(cmd);
3064                 } else {
3065                         if (p - cmd > 999)
3066                                 p = cmd + 999;
3067                         strncpy(line, cmd, p - cmd);
3068                         line[p - cmd] = '\0';
3069                         cmd = p + 1;
3070                 }
3071                 
3072                 /* and get the first part of the command */
3073                 ptr = line;
3074                 if (!next_token_nr(&ptr,tok,NULL,sizeof(tok))) continue;
3075                 
3076                 if ((i = process_tok(tok)) >= 0) {
3077                         rc = commands[i].fn();
3078                 } else if (i == -2) {
3079                         d_printf("%s: command abbreviation ambiguous\n",tok);
3080                 } else {
3081                         d_printf("%s: command not found\n",tok);
3082                 }
3083         }
3084         
3085         return rc;
3086 }       
3087
3088 #define MAX_COMPLETIONS 100
3089
3090 typedef struct {
3091         pstring dirmask;
3092         char **matches;
3093         int count, samelen;
3094         const char *text;
3095         int len;
3096 } completion_remote_t;
3097
3098 static void completion_remote_filter(const char *mnt, file_info *f, const char *mask, void *state)
3099 {
3100         completion_remote_t *info = (completion_remote_t *)state;
3101
3102         if ((info->count < MAX_COMPLETIONS - 1) && (strncmp(info->text, f->name, info->len) == 0) && (strcmp(f->name, ".") != 0) && (strcmp(f->name, "..") != 0)) {
3103                 if ((info->dirmask[0] == 0) && !(f->mode & aDIR))
3104                         info->matches[info->count] = SMB_STRDUP(f->name);
3105                 else {
3106                         pstring tmp;
3107
3108                         if (info->dirmask[0] != 0)
3109                                 pstrcpy(tmp, info->dirmask);
3110                         else
3111                                 tmp[0] = 0;
3112                         pstrcat(tmp, f->name);
3113                         if (f->mode & aDIR)
3114                                 pstrcat(tmp, "/");
3115                         info->matches[info->count] = SMB_STRDUP(tmp);
3116                 }
3117                 if (info->matches[info->count] == NULL)
3118                         return;
3119                 if (f->mode & aDIR)
3120                         smb_readline_ca_char(0);
3121
3122                 if (info->count == 1)
3123                         info->samelen = strlen(info->matches[info->count]);
3124                 else
3125                         while (strncmp(info->matches[info->count], info->matches[info->count-1], info->samelen) != 0)
3126                                 info->samelen--;
3127                 info->count++;
3128         }
3129 }
3130
3131 static char **remote_completion(const char *text, int len)
3132 {
3133         pstring dirmask;
3134         int i;
3135         completion_remote_t info = { "", NULL, 1, 0, NULL, 0 };
3136
3137         /* can't have non-static intialisation on Sun CC, so do it
3138            at run time here */
3139         info.samelen = len;
3140         info.text = text;
3141         info.len = len;
3142                 
3143         if (len >= PATH_MAX)
3144                 return(NULL);
3145
3146         info.matches