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