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