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