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