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