r4202: added smbclient commands "addprivileges" and "delprivileges" for
[kai/samba-autobuild/.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("privileges <sid|name>\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 add privileges for a user
1948 ****************************************************************************/
1949 static int cmd_addprivileges(const char **cmd_ptr)
1950 {
1951         fstring buf;
1952         TALLOC_CTX *mem_ctx = talloc(NULL, 0);
1953         NTSTATUS status;
1954         struct dom_sid *sid;
1955         struct lsa_RightSet rights;
1956
1957         if (!next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
1958                 d_printf("addprivileges <sid> <privilege...>\n");
1959                 talloc_free(mem_ctx);
1960                 return 1;
1961         }
1962
1963         sid = dom_sid_parse_talloc(mem_ctx, buf);
1964         if (sid == NULL) {
1965                 const char *sid_str;
1966                 status = smblsa_lookup_name(cli, buf, mem_ctx, &sid_str);
1967                 if (!NT_STATUS_IS_OK(status)) {
1968                         d_printf("lsa_LookupNames - %s\n", nt_errstr(status));
1969                         talloc_free(mem_ctx);
1970                         return 1;
1971                 }
1972                 sid = dom_sid_parse_talloc(mem_ctx, sid_str);
1973         }
1974
1975         ZERO_STRUCT(rights);
1976         while (next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
1977                 rights.names = talloc_realloc_p(mem_ctx, rights.names, 
1978                                                 struct lsa_String, rights.count+1);
1979                 rights.names[rights.count].string = talloc_strdup(mem_ctx, buf);
1980                 rights.count++;
1981         }
1982
1983
1984         status = smblsa_sid_add_privileges(cli, sid, mem_ctx, &rights);
1985         if (!NT_STATUS_IS_OK(status)) {
1986                 d_printf("lsa_AddAccountRights - %s\n", nt_errstr(status));
1987                 talloc_free(mem_ctx);
1988                 return 1;
1989         }
1990
1991         talloc_free(mem_ctx);
1992
1993         return 0;
1994 }
1995
1996 /****************************************************************************
1997 delete privileges for a user
1998 ****************************************************************************/
1999 static int cmd_delprivileges(const char **cmd_ptr)
2000 {
2001         fstring buf;
2002         TALLOC_CTX *mem_ctx = talloc(NULL, 0);
2003         NTSTATUS status;
2004         struct dom_sid *sid;
2005         struct lsa_RightSet rights;
2006
2007         if (!next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
2008                 d_printf("delprivileges <sid> <privilege...>\n");
2009                 talloc_free(mem_ctx);
2010                 return 1;
2011         }
2012
2013         sid = dom_sid_parse_talloc(mem_ctx, buf);
2014         if (sid == NULL) {
2015                 const char *sid_str;
2016                 status = smblsa_lookup_name(cli, buf, mem_ctx, &sid_str);
2017                 if (!NT_STATUS_IS_OK(status)) {
2018                         d_printf("lsa_LookupNames - %s\n", nt_errstr(status));
2019                         talloc_free(mem_ctx);
2020                         return 1;
2021                 }
2022                 sid = dom_sid_parse_talloc(mem_ctx, sid_str);
2023         }
2024
2025         ZERO_STRUCT(rights);
2026         while (next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
2027                 rights.names = talloc_realloc_p(mem_ctx, rights.names, 
2028                                                 struct lsa_String, rights.count+1);
2029                 rights.names[rights.count].string = talloc_strdup(mem_ctx, buf);
2030                 rights.count++;
2031         }
2032
2033
2034         status = smblsa_sid_del_privileges(cli, sid, mem_ctx, &rights);
2035         if (!NT_STATUS_IS_OK(status)) {
2036                 d_printf("lsa_RemoveAccountRights - %s\n", nt_errstr(status));
2037                 talloc_free(mem_ctx);
2038                 return 1;
2039         }
2040
2041         talloc_free(mem_ctx);
2042
2043         return 0;
2044 }
2045
2046
2047 /****************************************************************************
2048 ****************************************************************************/
2049 static int cmd_open(const char **cmd_ptr)
2050 {
2051         pstring mask;
2052         fstring buf;
2053         
2054         pstrcpy(mask,cur_dir);
2055         
2056         if (!next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
2057                 d_printf("open <filename>\n");
2058                 return 1;
2059         }
2060         pstrcat(mask,buf);
2061
2062         smbcli_open(cli->tree, mask, O_RDWR, DENY_ALL);
2063
2064         return 0;
2065 }
2066
2067
2068 /****************************************************************************
2069 remove a directory
2070 ****************************************************************************/
2071 static int cmd_rmdir(const char **cmd_ptr)
2072 {
2073         pstring mask;
2074         fstring buf;
2075   
2076         pstrcpy(mask,cur_dir);
2077         
2078         if (!next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
2079                 d_printf("rmdir <dirname>\n");
2080                 return 1;
2081         }
2082         pstrcat(mask,buf);
2083
2084         if (NT_STATUS_IS_ERR(smbcli_rmdir(cli->tree, mask))) {
2085                 d_printf("%s removing remote directory file %s\n",
2086                          smbcli_errstr(cli->tree),mask);
2087         }
2088         
2089         return 0;
2090 }
2091
2092 /****************************************************************************
2093  UNIX hardlink.
2094 ****************************************************************************/
2095 static int cmd_link(const char **cmd_ptr)
2096 {
2097         pstring src,dest;
2098         fstring buf,buf2;
2099   
2100         if (!(cli->transport->negotiate.capabilities & CAP_UNIX)) {
2101                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2102                 return 1;
2103         }
2104
2105         pstrcpy(src,cur_dir);
2106         pstrcpy(dest,cur_dir);
2107   
2108         if (!next_token(cmd_ptr,buf,NULL,sizeof(buf)) || 
2109             !next_token(cmd_ptr,buf2,NULL, sizeof(buf2))) {
2110                 d_printf("link <src> <dest>\n");
2111                 return 1;
2112         }
2113
2114         pstrcat(src,buf);
2115         pstrcat(dest,buf2);
2116
2117         if (NT_STATUS_IS_ERR(smbcli_unix_hardlink(cli->tree, src, dest))) {
2118                 d_printf("%s linking files (%s -> %s)\n", smbcli_errstr(cli->tree), src, dest);
2119                 return 1;
2120         }  
2121
2122         return 0;
2123 }
2124
2125 /****************************************************************************
2126  UNIX symlink.
2127 ****************************************************************************/
2128
2129 static int cmd_symlink(const char **cmd_ptr)
2130 {
2131         pstring src,dest;
2132         fstring buf,buf2;
2133   
2134         if (!(cli->transport->negotiate.capabilities & CAP_UNIX)) {
2135                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2136                 return 1;
2137         }
2138
2139         pstrcpy(src,cur_dir);
2140         pstrcpy(dest,cur_dir);
2141         
2142         if (!next_token(cmd_ptr,buf,NULL,sizeof(buf)) || 
2143             !next_token(cmd_ptr,buf2,NULL, sizeof(buf2))) {
2144                 d_printf("symlink <src> <dest>\n");
2145                 return 1;
2146         }
2147
2148         pstrcat(src,buf);
2149         pstrcat(dest,buf2);
2150
2151         if (NT_STATUS_IS_ERR(smbcli_unix_symlink(cli->tree, src, dest))) {
2152                 d_printf("%s symlinking files (%s -> %s)\n",
2153                         smbcli_errstr(cli->tree), src, dest);
2154                 return 1;
2155         } 
2156
2157         return 0;
2158 }
2159
2160 /****************************************************************************
2161  UNIX chmod.
2162 ****************************************************************************/
2163
2164 static int cmd_chmod(const char **cmd_ptr)
2165 {
2166         pstring src;
2167         mode_t mode;
2168         fstring buf, buf2;
2169   
2170         if (!(cli->transport->negotiate.capabilities & CAP_UNIX)) {
2171                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2172                 return 1;
2173         }
2174
2175         pstrcpy(src,cur_dir);
2176         
2177         if (!next_token(cmd_ptr,buf,NULL,sizeof(buf)) || 
2178             !next_token(cmd_ptr,buf2,NULL, sizeof(buf2))) {
2179                 d_printf("chmod mode file\n");
2180                 return 1;
2181         }
2182
2183         mode = (mode_t)strtol(buf, NULL, 8);
2184         pstrcat(src,buf2);
2185
2186         if (NT_STATUS_IS_ERR(smbcli_unix_chmod(cli->tree, src, mode))) {
2187                 d_printf("%s chmod file %s 0%o\n",
2188                         smbcli_errstr(cli->tree), src, (uint_t)mode);
2189                 return 1;
2190         } 
2191
2192         return 0;
2193 }
2194
2195 /****************************************************************************
2196  UNIX chown.
2197 ****************************************************************************/
2198
2199 static int cmd_chown(const char **cmd_ptr)
2200 {
2201         pstring src;
2202         uid_t uid;
2203         gid_t gid;
2204         fstring buf, buf2, buf3;
2205   
2206         if (!(cli->transport->negotiate.capabilities & CAP_UNIX)) {
2207                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2208                 return 1;
2209         }
2210
2211         pstrcpy(src,cur_dir);
2212         
2213         if (!next_token(cmd_ptr,buf,NULL,sizeof(buf)) || 
2214             !next_token(cmd_ptr,buf2,NULL, sizeof(buf2)) ||
2215             !next_token(cmd_ptr,buf3,NULL, sizeof(buf3))) {
2216                 d_printf("chown uid gid file\n");
2217                 return 1;
2218         }
2219
2220         uid = (uid_t)atoi(buf);
2221         gid = (gid_t)atoi(buf2);
2222         pstrcat(src,buf3);
2223
2224         if (NT_STATUS_IS_ERR(smbcli_unix_chown(cli->tree, src, uid, gid))) {
2225                 d_printf("%s chown file %s uid=%d, gid=%d\n",
2226                         smbcli_errstr(cli->tree), src, (int)uid, (int)gid);
2227                 return 1;
2228         } 
2229
2230         return 0;
2231 }
2232
2233 /****************************************************************************
2234 rename some files
2235 ****************************************************************************/
2236 static int cmd_rename(const char **cmd_ptr)
2237 {
2238         pstring src,dest;
2239         fstring buf,buf2;
2240   
2241         pstrcpy(src,cur_dir);
2242         pstrcpy(dest,cur_dir);
2243         
2244         if (!next_token(cmd_ptr,buf,NULL,sizeof(buf)) || 
2245             !next_token(cmd_ptr,buf2,NULL, sizeof(buf2))) {
2246                 d_printf("rename <src> <dest>\n");
2247                 return 1;
2248         }
2249
2250         pstrcat(src,buf);
2251         pstrcat(dest,buf2);
2252
2253         if (NT_STATUS_IS_ERR(smbcli_rename(cli->tree, src, dest))) {
2254                 d_printf("%s renaming files\n",smbcli_errstr(cli->tree));
2255                 return 1;
2256         }
2257         
2258         return 0;
2259 }
2260
2261
2262 /****************************************************************************
2263 toggle the prompt flag
2264 ****************************************************************************/
2265 static int cmd_prompt(const char **cmd_ptr)
2266 {
2267         prompt = !prompt;
2268         DEBUG(2,("prompting is now %s\n",prompt?"on":"off"));
2269         
2270         return 1;
2271 }
2272
2273
2274 /****************************************************************************
2275 set the newer than time
2276 ****************************************************************************/
2277 static int cmd_newer(const char **cmd_ptr)
2278 {
2279         fstring buf;
2280         BOOL ok;
2281         struct stat sbuf;
2282
2283         ok = next_token(cmd_ptr,buf,NULL,sizeof(buf));
2284         if (ok && (stat(buf,&sbuf) == 0)) {
2285                 newer_than = sbuf.st_mtime;
2286                 DEBUG(1,("Getting files newer than %s",
2287                          asctime(localtime(&newer_than))));
2288         } else {
2289                 newer_than = 0;
2290         }
2291
2292         if (ok && newer_than == 0) {
2293                 d_printf("Error setting newer-than time\n");
2294                 return 1;
2295         }
2296
2297         return 0;
2298 }
2299
2300 /****************************************************************************
2301 set the archive level
2302 ****************************************************************************/
2303 static int cmd_archive(const char **cmd_ptr)
2304 {
2305         fstring buf;
2306
2307         if (next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
2308                 archive_level = atoi(buf);
2309         } else
2310                 d_printf("Archive level is %d\n",archive_level);
2311
2312         return 0;
2313 }
2314
2315 /****************************************************************************
2316 toggle the lowercaseflag
2317 ****************************************************************************/
2318 static int cmd_lowercase(const char **cmd_ptr)
2319 {
2320         lowercase = !lowercase;
2321         DEBUG(2,("filename lowercasing is now %s\n",lowercase?"on":"off"));
2322
2323         return 0;
2324 }
2325
2326
2327
2328
2329 /****************************************************************************
2330 toggle the recurse flag
2331 ****************************************************************************/
2332 static int cmd_recurse(const char **cmd_ptr)
2333 {
2334         recurse = !recurse;
2335         DEBUG(2,("directory recursion is now %s\n",recurse?"on":"off"));
2336
2337         return 0;
2338 }
2339
2340 /****************************************************************************
2341 toggle the translate flag
2342 ****************************************************************************/
2343 static int cmd_translate(const char **cmd_ptr)
2344 {
2345         translation = !translation;
2346         DEBUG(2,("CR/LF<->LF and print text translation now %s\n",
2347                  translation?"on":"off"));
2348
2349         return 0;
2350 }
2351
2352
2353 /****************************************************************************
2354 do a printmode command
2355 ****************************************************************************/
2356 static int cmd_printmode(const char **cmd_ptr)
2357 {
2358         fstring buf;
2359         fstring mode;
2360
2361         if (next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
2362                 if (strequal(buf,"text")) {
2363                         printmode = 0;      
2364                 } else {
2365                         if (strequal(buf,"graphics"))
2366                                 printmode = 1;
2367                         else
2368                                 printmode = atoi(buf);
2369                 }
2370         }
2371
2372         switch(printmode)
2373                 {
2374                 case 0: 
2375                         fstrcpy(mode,"text");
2376                         break;
2377                 case 1: 
2378                         fstrcpy(mode,"graphics");
2379                         break;
2380                 default: 
2381                         slprintf(mode,sizeof(mode)-1,"%d",printmode);
2382                         break;
2383                 }
2384         
2385         DEBUG(2,("the printmode is now %s\n",mode));
2386
2387         return 0;
2388 }
2389
2390 /****************************************************************************
2391  do the lcd command
2392  ****************************************************************************/
2393 static int cmd_lcd(const char **cmd_ptr)
2394 {
2395         fstring buf;
2396         pstring d;
2397         
2398         if (next_token(cmd_ptr,buf,NULL,sizeof(buf)))
2399                 chdir(buf);
2400         DEBUG(2,("the local directory is now %s\n",sys_getwd(d)));
2401
2402         return 0;
2403 }
2404
2405 /****************************************************************************
2406  get a file restarting at end of local file
2407  ****************************************************************************/
2408 static int cmd_reget(const char **cmd_ptr)
2409 {
2410         pstring local_name;
2411         pstring remote_name;
2412         char *p;
2413
2414         pstrcpy(remote_name, cur_dir);
2415         pstrcat(remote_name, "\\");
2416         
2417         p = remote_name + strlen(remote_name);
2418         
2419         if (!next_token(cmd_ptr, p, NULL, sizeof(remote_name) - strlen(remote_name))) {
2420                 d_printf("reget <filename>\n");
2421                 return 1;
2422         }
2423         pstrcpy(local_name, p);
2424         dos_clean_name(remote_name);
2425         
2426         next_token(cmd_ptr, local_name, NULL, sizeof(local_name));
2427         
2428         return do_get(remote_name, local_name, True);
2429 }
2430
2431 /****************************************************************************
2432  put a file restarting at end of local file
2433  ****************************************************************************/
2434 static int cmd_reput(const char **cmd_ptr)
2435 {
2436         pstring local_name;
2437         pstring remote_name;
2438         fstring buf;
2439         char *p = buf;
2440         struct stat st;
2441         
2442         pstrcpy(remote_name, cur_dir);
2443         pstrcat(remote_name, "\\");
2444   
2445         if (!next_token(cmd_ptr, p, NULL, sizeof(buf))) {
2446                 d_printf("reput <filename>\n");
2447                 return 1;
2448         }
2449         pstrcpy(local_name, p);
2450   
2451         if (!file_exist(local_name, &st)) {
2452                 d_printf("%s does not exist\n", local_name);
2453                 return 1;
2454         }
2455
2456         if (next_token(cmd_ptr, p, NULL, sizeof(buf)))
2457                 pstrcat(remote_name, p);
2458         else
2459                 pstrcat(remote_name, local_name);
2460         
2461         dos_clean_name(remote_name);
2462
2463         return do_put(remote_name, local_name, True);
2464 }
2465
2466
2467 /*
2468   return a string representing a share type
2469 */
2470 static const char *share_type_str(uint32_t type)
2471 {
2472         switch (type & 0xF) {
2473         case STYPE_DISKTREE: 
2474                 return "Disk";
2475         case STYPE_PRINTQ: 
2476                 return "Printer";
2477         case STYPE_DEVICE: 
2478                 return "Device";
2479         case STYPE_IPC: 
2480                 return "IPC";
2481         default:
2482                 return "Unknown";
2483         }
2484 }
2485
2486
2487 /*
2488   display a list of shares from a level 1 share enum
2489 */
2490 static void display_share_result(struct srvsvc_NetShareCtr1 *ctr1)
2491 {
2492         int i;
2493
2494         for (i=0;i<ctr1->count;i++) {
2495                 struct srvsvc_NetShareInfo1 *info = ctr1->array+i;
2496
2497                 printf("\t%-15s %-10.10s %s\n", 
2498                        info->name, 
2499                        share_type_str(info->type), 
2500                        info->comment);
2501         }
2502 }
2503
2504
2505
2506 /****************************************************************************
2507 try and browse available shares on a host
2508 ****************************************************************************/
2509 static BOOL browse_host(const char *query_host)
2510 {
2511         struct dcerpc_pipe *p;
2512         char *binding;
2513         NTSTATUS status;
2514         struct srvsvc_NetShareEnumAll r;
2515         uint32_t resume_handle = 0;
2516         TALLOC_CTX *mem_ctx = talloc_init("browse_host");
2517         struct srvsvc_NetShareCtr1 ctr1;
2518
2519         binding = talloc_asprintf(mem_ctx, "ncacn_np:%s", query_host);
2520
2521         status = dcerpc_pipe_connect(&p, binding, 
2522                                      DCERPC_SRVSVC_UUID, 
2523                                      DCERPC_SRVSVC_VERSION,
2524                                      domain, 
2525                                      username, password);
2526         if (!NT_STATUS_IS_OK(status)) {
2527                 d_printf("Failed to connect to %s - %s\n", 
2528                          binding, nt_errstr(status));
2529                 talloc_destroy(mem_ctx);
2530                 return False;
2531         }
2532         talloc_steal(mem_ctx, p);
2533
2534         r.in.server_unc = talloc_asprintf(mem_ctx,"\\\\%s",dcerpc_server_name(p));
2535         r.in.level = 1;
2536         r.in.ctr.ctr1 = &ctr1;
2537         r.in.max_buffer = ~0;
2538         r.in.resume_handle = &resume_handle;
2539
2540         d_printf("\n\tSharename       Type       Comment\n");
2541         d_printf("\t---------       ----       -------\n");
2542
2543         do {
2544                 ZERO_STRUCT(ctr1);
2545                 status = dcerpc_srvsvc_NetShareEnumAll(p, mem_ctx, &r);
2546
2547                 if (NT_STATUS_IS_OK(status) && 
2548                     (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA) ||
2549                      W_ERROR_IS_OK(r.out.result)) &&
2550                     r.out.ctr.ctr1) {
2551                         display_share_result(r.out.ctr.ctr1);
2552                         resume_handle += r.out.ctr.ctr1->count;
2553                 }
2554         } while (NT_STATUS_IS_OK(status) && W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA));
2555
2556         talloc_destroy(mem_ctx);
2557
2558         if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(r.out.result)) {
2559                 d_printf("Failed NetShareEnumAll %s - %s/%s\n", 
2560                          binding, nt_errstr(status), win_errstr(r.out.result));
2561                 return False;
2562         }
2563
2564         return False;
2565 }
2566
2567 /****************************************************************************
2568 try and browse available connections on a host
2569 ****************************************************************************/
2570 static BOOL list_servers(const char *wk_grp)
2571 {
2572         d_printf("REWRITE: list servers not implemented\n");
2573         return False;
2574 }
2575
2576 /* Some constants for completing filename arguments */
2577
2578 #define COMPL_NONE        0          /* No completions */
2579 #define COMPL_REMOTE      1          /* Complete remote filename */
2580 #define COMPL_LOCAL       2          /* Complete local filename */
2581
2582 /* This defines the commands supported by this client.
2583  * NOTE: The "!" must be the last one in the list because it's fn pointer
2584  *       field is NULL, and NULL in that field is used in process_tok()
2585  *       (below) to indicate the end of the list.  crh
2586  */
2587 static struct
2588 {
2589   const char *name;
2590   int (*fn)(const char **cmd_ptr);
2591   const char *description;
2592   char compl_args[2];      /* Completion argument info */
2593 } commands[] = 
2594 {
2595   {"?",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
2596   {"addprivileges",cmd_addprivileges,"<sid|user> <privilege...> add privileges for a user",{COMPL_NONE,COMPL_NONE}},
2597   {"altname",cmd_altname,"<file> show alt name",{COMPL_NONE,COMPL_NONE}},
2598   {"acl",cmd_acl,"<file> show file ACL",{COMPL_NONE,COMPL_NONE}},
2599   {"allinfo",cmd_allinfo,"<file> show all possible info about a file",{COMPL_NONE,COMPL_NONE}},
2600   {"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}},
2601   {"cancel",cmd_cancel,"<jobid> cancel a print queue entry",{COMPL_NONE,COMPL_NONE}},
2602   {"cd",cmd_cd,"[directory] change/report the remote directory",{COMPL_REMOTE,COMPL_NONE}},
2603   {"chmod",cmd_chmod,"<src> <mode> chmod a file using UNIX permission",{COMPL_REMOTE,COMPL_REMOTE}},
2604   {"chown",cmd_chown,"<src> <uid> <gid> chown a file using UNIX uids and gids",{COMPL_REMOTE,COMPL_REMOTE}},
2605   {"del",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
2606   {"delprivileges",cmd_delprivileges,"<sid|user> <privilege...> remove privileges for a user",{COMPL_NONE,COMPL_NONE}},
2607   {"deltree",cmd_deltree,"<dir> delete a whole directory tree",{COMPL_REMOTE,COMPL_NONE}},
2608   {"dir",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
2609   {"du",cmd_du,"<mask> computes the total size of the current directory",{COMPL_REMOTE,COMPL_NONE}},
2610   {"exit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
2611   {"get",cmd_get,"<remote name> [local name] get a file",{COMPL_REMOTE,COMPL_LOCAL}},
2612   {"help",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
2613   {"history",cmd_history,"displays the command history",{COMPL_NONE,COMPL_NONE}},
2614   {"lcd",cmd_lcd,"[directory] change/report the local current working directory",{COMPL_LOCAL,COMPL_NONE}},
2615   {"link",cmd_link,"<src> <dest> create a UNIX hard link",{COMPL_REMOTE,COMPL_REMOTE}},
2616   {"lookupname",cmd_lookupname,"<name> show SID for name",{COMPL_NONE,COMPL_NONE}},
2617   {"lookupsid",cmd_lookupsid,"<sid> show name for SID",{COMPL_NONE,COMPL_NONE}},
2618   {"lowercase",cmd_lowercase,"toggle lowercasing of filenames for get",{COMPL_NONE,COMPL_NONE}},  
2619   {"ls",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
2620   {"mask",cmd_select,"<mask> mask all filenames against this",{COMPL_REMOTE,COMPL_NONE}},
2621   {"md",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
2622   {"mget",cmd_mget,"<mask> get all the matching files",{COMPL_REMOTE,COMPL_NONE}},
2623   {"mkdir",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
2624   {"more",cmd_more,"<remote name> view a remote file with your pager",{COMPL_REMOTE,COMPL_NONE}},  
2625   {"mput",cmd_mput,"<mask> put all matching files",{COMPL_REMOTE,COMPL_NONE}},
2626   {"newer",cmd_newer,"<file> only mget files newer than the specified local file",{COMPL_LOCAL,COMPL_NONE}},
2627   {"open",cmd_open,"<mask> open a file",{COMPL_REMOTE,COMPL_NONE}},
2628   {"privileges",cmd_privileges,"<user> show privileges for a user",{COMPL_NONE,COMPL_NONE}},
2629   {"print",cmd_print,"<file name> print a file",{COMPL_NONE,COMPL_NONE}},
2630   {"printmode",cmd_printmode,"<graphics or text> set the print mode",{COMPL_NONE,COMPL_NONE}},
2631   {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput",{COMPL_NONE,COMPL_NONE}},  
2632   {"put",cmd_put,"<local name> [remote name] put a file",{COMPL_LOCAL,COMPL_REMOTE}},
2633   {"pwd",cmd_pwd,"show current remote directory (same as 'cd' with no args)",{COMPL_NONE,COMPL_NONE}},
2634   {"q",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
2635   {"queue",cmd_queue,"show the print queue",{COMPL_NONE,COMPL_NONE}},
2636   {"quit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
2637   {"rd",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
2638   {"recurse",cmd_recurse,"toggle directory recursion for mget and mput",{COMPL_NONE,COMPL_NONE}},  
2639   {"reget",cmd_reget,"<remote name> [local name] get a file restarting at end of local file",{COMPL_REMOTE,COMPL_LOCAL}},
2640   {"rename",cmd_rename,"<src> <dest> rename some files",{COMPL_REMOTE,COMPL_REMOTE}},
2641   {"reput",cmd_reput,"<local name> [remote name] put a file restarting at end of remote file",{COMPL_LOCAL,COMPL_REMOTE}},
2642   {"rm",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
2643   {"rmdir",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
2644   {"symlink",cmd_symlink,"<src> <dest> create a UNIX symlink",{COMPL_REMOTE,COMPL_REMOTE}},
2645   {"translate",cmd_translate,"toggle text translation for printing",{COMPL_NONE,COMPL_NONE}},
2646   
2647   /* Yes, this must be here, see crh's comment above. */
2648   {"!",NULL,"run a shell command on the local system",{COMPL_NONE,COMPL_NONE}},
2649   {NULL,NULL,NULL,{COMPL_NONE,COMPL_NONE}}
2650 };
2651
2652
2653 /*******************************************************************
2654   lookup a command string in the list of commands, including 
2655   abbreviations
2656   ******************************************************************/
2657 static int process_tok(fstring tok)
2658 {
2659         int i = 0, matches = 0;
2660         int cmd=0;
2661         int tok_len = strlen(tok);
2662         
2663         while (commands[i].fn != NULL) {
2664                 if (strequal(commands[i].name,tok)) {
2665                         matches = 1;
2666                         cmd = i;
2667                         break;
2668                 } else if (strncasecmp(commands[i].name, tok, tok_len) == 0) {
2669                         matches++;
2670                         cmd = i;
2671                 }
2672                 i++;
2673         }
2674   
2675         if (matches == 0)
2676                 return(-1);
2677         else if (matches == 1)
2678                 return(cmd);
2679         else
2680                 return(-2);
2681 }
2682
2683 /****************************************************************************
2684 help
2685 ****************************************************************************/
2686 static int cmd_help(const char **cmd_ptr)
2687 {
2688         int i=0,j;
2689         fstring buf;
2690         
2691         if (next_token(cmd_ptr,buf,NULL,sizeof(buf))) {
2692                 if ((i = process_tok(buf)) >= 0)
2693                         d_printf("HELP %s:\n\t%s\n\n",commands[i].name,commands[i].description);
2694         } else {
2695                 while (commands[i].description) {
2696                         for (j=0; commands[i].description && (j<5); j++) {
2697                                 d_printf("%-15s",commands[i].name);
2698                                 i++;
2699                         }
2700                         d_printf("\n");
2701                 }
2702         }
2703         return 0;
2704 }
2705
2706 /****************************************************************************
2707 process a -c command string
2708 ****************************************************************************/
2709 static int process_command_string(char *cmd)
2710 {
2711         pstring line;
2712         const char *ptr;
2713         int rc = 0;
2714
2715         /* establish the connection if not already */
2716         
2717         if (!cli) {
2718                 cli = do_connect(desthost, service);
2719                 if (!cli)
2720                         return 0;
2721         }
2722         
2723         while (cmd[0] != '\0')    {
2724                 char *p;
2725                 fstring tok;
2726                 int i;
2727                 
2728                 if ((p = strchr_m(cmd, ';')) == 0) {
2729                         strncpy(line, cmd, 999);
2730                         line[1000] = '\0';
2731                         cmd += strlen(cmd);
2732                 } else {
2733                         if (p - cmd > 999) p = cmd + 999;
2734                         strncpy(line, cmd, p - cmd);
2735                         line[p - cmd] = '\0';
2736                         cmd = p + 1;
2737                 }
2738                 
2739                 /* and get the first part of the command */
2740                 ptr = line;
2741                 if (!next_token(&ptr,tok,NULL,sizeof(tok))) continue;
2742                 
2743                 if ((i = process_tok(tok)) >= 0) {
2744                         rc = commands[i].fn(&ptr);
2745                 } else if (i == -2) {
2746                         d_printf("%s: command abbreviation ambiguous\n",tok);
2747                 } else {
2748                         d_printf("%s: command not found\n",tok);
2749                 }
2750         }
2751         
2752         return rc;
2753 }       
2754
2755 #define MAX_COMPLETIONS 100
2756
2757 typedef struct {
2758         pstring dirmask;
2759         char **matches;
2760         int count, samelen;
2761         const char *text;
2762         int len;
2763 } completion_remote_t;
2764
2765 static void completion_remote_filter(struct clilist_file_info *f, const char *mask, void *state)
2766 {
2767         completion_remote_t *info = (completion_remote_t *)state;
2768
2769         if ((info->count < MAX_COMPLETIONS - 1) && (strncmp(info->text, f->name, info->len) == 0) && (strcmp(f->name, ".") != 0) && (strcmp(f->name, "..") != 0)) {
2770                 if ((info->dirmask[0] == 0) && !(f->attrib & FILE_ATTRIBUTE_DIRECTORY))
2771                         info->matches[info->count] = strdup(f->name);
2772                 else {
2773                         pstring tmp;
2774
2775                         if (info->dirmask[0] != 0)
2776                                 pstrcpy(tmp, info->dirmask);
2777                         else
2778                                 tmp[0] = 0;
2779                         pstrcat(tmp, f->name);
2780                         if (f->attrib & FILE_ATTRIBUTE_DIRECTORY)
2781                                 pstrcat(tmp, "/");
2782                         info->matches[info->count] = strdup(tmp);
2783                 }
2784                 if (info->matches[info->count] == NULL)
2785                         return;
2786                 if (f->attrib & FILE_ATTRIBUTE_DIRECTORY)
2787                         smb_readline_ca_char(0);
2788
2789                 if (info->count == 1)
2790                         info->samelen = strlen(info->matches[info->count]);
2791                 else
2792                         while (strncmp(info->matches[info->count], info->matches[info->count-1], info->samelen) != 0)
2793                                 info->samelen--;
2794                 info->count++;
2795         }
2796 }
2797
2798 static char **remote_completion(const char *text, int len)
2799 {
2800         pstring dirmask;
2801         int i;
2802         completion_remote_t info = { "", NULL, 1, 0, NULL, 0 };
2803
2804         info.samelen = len;
2805         info.text = text;
2806         info.len = len;
2807  
2808         if (len >= PATH_MAX)
2809                 return(NULL);
2810
2811         info.matches = malloc_array_p(char *, MAX_COMPLETIONS);
2812         if (!info.matches) return NULL;
2813         info.matches[0] = NULL;
2814
2815         for (i = len-1; i >= 0; i--)
2816                 if ((text[i] == '/') || (text[i] == '\\'))
2817                         break;
2818         info.text = text+i+1;
2819         info.samelen = info.len = len-i-1;
2820
2821         if (i > 0) {
2822                 strncpy(info.dirmask, text, i+1);
2823                 info.dirmask[i+1] = 0;
2824                 snprintf(dirmask, sizeof(dirmask), "%s%*s*", cur_dir, i-1, text);
2825         } else
2826                 snprintf(dirmask, sizeof(dirmask), "%s*", cur_dir);
2827
2828         if (smbcli_list(cli->tree, dirmask, 
2829                      FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN, 
2830                      completion_remote_filter, &info) < 0)
2831                 goto cleanup;
2832
2833         if (info.count == 2)
2834                 info.matches[0] = strdup(info.matches[1]);
2835         else {
2836                 info.matches[0] = malloc(info.samelen+1);
2837                 if (!info.matches[0])
2838                         goto cleanup;
2839                 strncpy(info.matches[0], info.matches[1], info.samelen);
2840                 info.matches[0][info.samelen] = 0;
2841         }
2842         info.matches[info.count] = NULL;
2843         return info.matches;
2844
2845 cleanup:
2846         for (i = 0; i < info.count; i++)
2847                 free(info.matches[i]);
2848         free(info.matches);
2849         return NULL;
2850 }
2851
2852 static char **completion_fn(const char *text, int start, int end)
2853 {
2854         smb_readline_ca_char(' ');
2855
2856         if (start) {
2857                 const char *buf, *sp;
2858                 int i;
2859                 char compl_type;
2860
2861                 buf = smb_readline_get_line_buffer();
2862                 if (buf == NULL)
2863                         return NULL;
2864                 
2865                 sp = strchr(buf, ' ');
2866                 if (sp == NULL)
2867                         return NULL;
2868                 
2869                 for (i = 0; commands[i].name; i++)
2870                         if ((strncmp(commands[i].name, text, sp - buf) == 0) && (commands[i].name[sp - buf] == 0))
2871                                 break;
2872                 if (commands[i].name == NULL)
2873                         return NULL;
2874
2875                 while (*sp == ' ')
2876                         sp++;
2877
2878                 if (sp == (buf + start))
2879                         compl_type = commands[i].compl_args[0];
2880                 else
2881                         compl_type = commands[i].compl_args[1];
2882
2883                 if (compl_type == COMPL_REMOTE)
2884                         return remote_completion(text, end - start);
2885                 else /* fall back to local filename completion */
2886                         return NULL;
2887         } else {
2888                 char **matches;
2889                 int i, len, samelen = 0, count=1;
2890
2891                 matches = malloc_array_p(char *, MAX_COMPLETIONS);
2892                 if (!matches) return NULL;
2893                 matches[0] = NULL;
2894
2895                 len = strlen(text);
2896                 for (i=0;commands[i].fn && count < MAX_COMPLETIONS-1;i++) {
2897                         if (strncmp(text, commands[i].name, len) == 0) {
2898                                 matches[count] = strdup(commands[i].name);
2899                                 if (!matches[count])
2900                                         goto cleanup;
2901                                 if (count == 1)
2902                                         samelen = strlen(matches[count]);
2903                                 else
2904                                         while (strncmp(matches[count], matches[count-1], samelen) != 0)
2905                                                 samelen--;
2906                                 count++;
2907                         }
2908                 }
2909
2910                 switch (count) {
2911                 case 0: /* should never happen */
2912                 case 1:
2913                         goto cleanup;
2914                 case 2:
2915                         matches[0] = strdup(matches[1]);
2916                         break;
2917                 default:
2918                         matches[0] = malloc(samelen+1);
2919                         if (!matches[0])
2920                                 goto cleanup;
2921                         strncpy(matches[0], matches[1], samelen);
2922                         matches[0][samelen] = 0;
2923                 }
2924                 matches[count] = NULL;
2925                 return matches;
2926
2927 cleanup:
2928                 while (i >= 0) {
2929                         free(matches[i]);
2930                         i--;
2931                 }
2932                 free(matches);
2933                 return NULL;
2934         }
2935 }
2936
2937 /****************************************************************************
2938 make sure we swallow keepalives during idle time
2939 ****************************************************************************/
2940 static void readline_callback(void)
2941 {
2942         static time_t last_t;
2943         time_t t;
2944
2945         t = time(NULL);
2946
2947         if (t - last_t < 5) return;
2948
2949         last_t = t;
2950
2951         smbcli_transport_process(cli->transport);
2952
2953         if (cli->tree) {
2954                 smbcli_chkpath(cli->tree, "\\");
2955         }
2956 }
2957
2958
2959 /****************************************************************************
2960 process commands on stdin
2961 ****************************************************************************/
2962 static void process_stdin(void)
2963 {
2964         while (1) {
2965                 fstring tok;
2966                 fstring the_prompt;
2967                 char *cline;
2968                 pstring line;
2969                 const char *ptr;
2970                 int i;
2971                 
2972                 /* display a prompt */
2973                 slprintf(the_prompt, sizeof(the_prompt)-1, "smb: %s> ", cur_dir);
2974                 cline = smb_readline(the_prompt, readline_callback, completion_fn);
2975                         
2976                 if (!cline) break;
2977                 
2978                 pstrcpy(line, cline);
2979
2980                 /* special case - first char is ! */
2981                 if (*line == '!') {
2982                         system(line + 1);
2983                         continue;
2984                 }
2985       
2986                 /* and get the first part of the command */
2987                 ptr = line;
2988                 if (!next_token(&ptr,tok,NULL,sizeof(tok))) continue;
2989
2990                 if ((i = process_tok(tok)) >= 0) {
2991                         commands[i].fn(&ptr);
2992                 } else if (i == -2) {
2993                         d_printf("%s: command abbreviation ambiguous\n",tok);
2994                 } else {
2995                         d_printf("%s: command not found\n",tok);
2996                 }
2997         }
2998 }
2999
3000
3001 /***************************************************** 
3002 return a connection to a server
3003 *******************************************************/
3004 static struct smbcli_state *do_connect(const char *server, const char *share)
3005 {
3006         struct smbcli_state *c;
3007         struct nmb_name called, calling;
3008         const char *server_n;
3009         fstring servicename;
3010         char *sharename;
3011         NTSTATUS status;
3012         
3013         /* make a copy so we don't modify the global string 'service' */
3014         fstrcpy(servicename, share);
3015         sharename = servicename;
3016         if (*sharename == '\\') {
3017                 server = sharename+2;
3018                 sharename = strchr_m(server,'\\');
3019                 if (!sharename) return NULL;
3020                 *sharename = 0;
3021                 sharename++;
3022         }
3023
3024         asprintf(&sharename, "\\\\%s\\%s", server, sharename);
3025
3026         server_n = dest_ip?dest_ip:server;
3027         
3028         make_nmb_name(&calling, lp_netbios_name(), 0x0);
3029         choose_called_name(&called, server, name_type);
3030
3031  again:
3032         /* have to open a new connection */
3033         if (!(c=smbcli_state_init(NULL)) || !smbcli_socket_connect(c, server_n)) {
3034                 d_printf("Connection to %s failed\n", server_n);
3035                 return NULL;
3036         }
3037
3038         if (!smbcli_transport_establish(c, &calling, &called)) {
3039                 char *p;
3040                 d_printf("session request to %s failed\n", 
3041                          called.name);
3042                 smbcli_shutdown(c);
3043                 if ((p=strchr_m(called.name, '.'))) {
3044                         *p = 0;
3045                         goto again;
3046                 }
3047                 if (strcmp(called.name, "*SMBSERVER")) {
3048                         make_nmb_name(&called , "*SMBSERVER", 0x20);
3049                         goto again;
3050                 }
3051                 return NULL;
3052         }
3053
3054         DEBUG(4,(" session request ok\n"));
3055
3056         if (NT_STATUS_IS_ERR(smbcli_negprot(c))) {
3057                 d_printf("protocol negotiation failed\n");
3058                 smbcli_shutdown(c);
3059                 return NULL;
3060         }
3061
3062         status = smbcli_session_setup(c, username, password, domain);
3063         if (NT_STATUS_IS_ERR(status)) {
3064                 d_printf("authenticated session setup failed: %s\n", nt_errstr(status));
3065                 /* if a password was not supplied then try again with a null username */
3066                 if (password[0] || !username[0]) {
3067                         status = smbcli_session_setup(c, "", "", lp_workgroup());
3068                 }
3069                 if (NT_STATUS_IS_ERR(status)) {
3070                         d_printf("session setup failed: %s\n", nt_errstr(status));
3071                         smbcli_shutdown(c);
3072                         return NULL;
3073                 }
3074                 d_printf("Anonymous login successful\n");
3075         }
3076
3077         DEBUG(4,(" session setup ok\n"));
3078
3079         if (NT_STATUS_IS_ERR(smbcli_send_tconX(c, sharename, "?????", password))) {
3080                 d_printf("tree connect failed: %s\n", smbcli_errstr(c->tree));
3081                 smbcli_shutdown(c);
3082                 return NULL;
3083         }
3084
3085         DEBUG(4,(" tconx ok\n"));
3086
3087         return c;
3088 }
3089
3090
3091 /****************************************************************************
3092   process commands from the client
3093 ****************************************************************************/
3094 static int process(char *base_directory)
3095 {
3096         int rc = 0;
3097
3098         cli = do_connect(desthost, service);
3099         if (!cli) {
3100                 return 1;
3101         }
3102
3103         if (*base_directory) do_cd(base_directory);
3104         
3105         if (cmdstr) {
3106                 rc = process_command_string(cmdstr);
3107         } else {
3108                 process_stdin();
3109         }
3110   
3111         smbcli_shutdown(cli);
3112         return rc;
3113 }
3114
3115 /****************************************************************************
3116 handle a -L query
3117 ****************************************************************************/
3118 static int do_host_query(char *query_host)
3119 {
3120         browse_host(query_host);
3121         list_servers(lp_workgroup());
3122         return(0);
3123 }
3124
3125
3126 /****************************************************************************
3127 handle a message operation
3128 ****************************************************************************/
3129 static int do_message_op(void)
3130 {
3131         struct nmb_name called, calling;
3132         const char *server_name;
3133
3134         make_nmb_name(&calling, lp_netbios_name(), 0x0);
3135         choose_called_name(&called, desthost, name_type);
3136
3137         server_name = dest_ip ? dest_ip : desthost;
3138
3139         if (!(cli=smbcli_state_init(NULL)) || !smbcli_socket_connect(cli, server_name)) {
3140                 d_printf("Connection to %s failed\n", server_name);
3141                 return 1;
3142         }
3143
3144         if (!smbcli_transport_establish(cli, &calling, &called)) {
3145                 d_printf("session request failed\n");
3146                 smbcli_shutdown(cli);
3147                 return 1;
3148         }
3149
3150         send_message();
3151         smbcli_shutdown(cli);
3152
3153         return 0;
3154 }
3155
3156
3157 /**
3158  * Process "-L hostname" option.
3159  *
3160  * We don't actually do anything yet -- we just stash the name in a
3161  * global variable and do the query when all options have been read.
3162  **/
3163 static void remember_query_host(const char *arg,
3164                                 pstring query_host)
3165 {
3166         char *slash;
3167         
3168         while (*arg == '\\' || *arg == '/')
3169                 arg++;
3170         pstrcpy(query_host, arg);
3171         if ((slash = strchr(query_host, '/'))
3172             || (slash = strchr(query_host, '\\'))) {
3173                 *slash = 0;
3174         }
3175 }
3176
3177
3178 /****************************************************************************
3179   main program
3180 ****************************************************************************/
3181  int main(int argc,char *argv[])
3182 {
3183         fstring base_directory;
3184         int opt;
3185         pstring query_host;
3186         BOOL message = False;
3187         pstring term_code;
3188         poptContext pc;
3189         char *p;
3190         int rc = 0;
3191         TALLOC_CTX *mem_ctx;
3192         struct poptOption long_options[] = {
3193                 POPT_AUTOHELP
3194
3195                 { "message", 'M', POPT_ARG_STRING, NULL, 'M', "Send message", "HOST" },
3196                 { "ip-address", 'I', POPT_ARG_STRING, NULL, 'I', "Use this IP to connect to", "IP" },
3197                 { "stderr", 'E', POPT_ARG_NONE, NULL, 'E', "Write messages to stderr instead of stdout" },
3198                 { "list", 'L', POPT_ARG_STRING, NULL, 'L', "Get a list of shares available on a host", "HOST" },
3199                 { "terminal", 't', POPT_ARG_STRING, NULL, 't', "Terminal I/O code {sjis|euc|jis7|jis8|junet|hex}", "CODE" },
3200                 { "directory", 'D', POPT_ARG_STRING, NULL, 'D', "Start from directory", "DIR" },
3201                 { "command", 'c', POPT_ARG_STRING, &cmdstr, 'c', "Execute semicolon separated commands" }, 
3202                 { "send-buffer", 'b', POPT_ARG_INT, NULL, 'b', "Changes the transmit/send buffer", "BYTES" },
3203                 { "port", 'p', POPT_ARG_INT, &port, 'p', "Port to connect to", "PORT" },
3204                 POPT_COMMON_SAMBA
3205                 POPT_COMMON_CONNECTION
3206                 POPT_COMMON_CREDENTIALS
3207                 POPT_COMMON_VERSION
3208                 POPT_TABLEEND
3209         };
3210         
3211 #ifdef KANJI
3212         pstrcpy(term_code, KANJI);
3213 #else /* KANJI */
3214         *term_code = 0;
3215 #endif /* KANJI */
3216
3217         *query_host = 0;
3218         *base_directory = 0;
3219
3220         setup_logging(argv[0],DEBUG_STDOUT);
3221         mem_ctx = talloc_init("client.c/main");
3222         if (!mem_ctx) {
3223                 d_printf("\nclient.c: Not enough memory\n");
3224                 exit(1);
3225         }
3226
3227         if (!lp_load(dyn_CONFIGFILE,True,False,False)) {
3228                 fprintf(stderr, "%s: Can't load %s - run testparm to debug it\n",
3229                         argv[0], dyn_CONFIGFILE);
3230         }
3231         
3232         pc = poptGetContext("smbclient", argc, (const char **) argv, long_options, 0);
3233         poptSetOtherOptionHelp(pc, "[OPTIONS] service <password>");
3234
3235         in_client = True;   /* Make sure that we tell lp_load we are */
3236
3237         while ((opt = poptGetNextOpt(pc)) != -1) {
3238                 switch (opt) {
3239                 case 'M':
3240                         /* Messages are sent to NetBIOS name type 0x3
3241                          * (Messenger Service).  Make sure we default
3242                          * to port 139 instead of port 445. srl,crh
3243                          */
3244                         name_type = 0x03; 
3245                         pstrcpy(desthost,poptGetOptArg(pc));
3246                         if( 0 == port ) port = 139;
3247                         message = True;
3248                         break;
3249                 case 'I':
3250                         dest_ip = poptGetOptArg(pc);
3251                         break;
3252                 case 'E':
3253                         setup_logging("client", DEBUG_STDERR);
3254                         break;
3255
3256                 case 'L':
3257                         remember_query_host(poptGetOptArg(pc), query_host);
3258                         break;
3259                 case 't':
3260                         pstrcpy(term_code, poptGetOptArg(pc));
3261                         break;
3262                 case 'D':
3263                         fstrcpy(base_directory,poptGetOptArg(pc));
3264                         break;
3265                 case 'b':
3266                         io_bufsize = MAX(1, atoi(poptGetOptArg(pc)));
3267                         break;
3268                 }
3269         }
3270
3271         load_interfaces();
3272
3273         smbclient_init_subsystems;
3274
3275         if(poptPeekArg(pc)) {
3276                 pstrcpy(service,poptGetArg(pc));  
3277                 /* Convert any '/' characters in the service name to '\' characters */
3278                 string_replace(service, '/','\\');
3279
3280                 if (count_chars(service,'\\') < 3) {
3281                         d_printf("\n%s: Not enough '\\' characters in service\n",service);
3282                         poptPrintUsage(pc, stderr, 0);
3283                         exit(1);
3284                 }
3285         }
3286
3287         if (poptPeekArg(pc)) { 
3288                 cmdline_set_userpassword(poptGetArg(pc));
3289         }
3290
3291         /*init_names(); */
3292
3293         if (!*query_host && !*service && !message) {
3294                 poptPrintUsage(pc, stderr, 0);
3295                 exit(1);
3296         }
3297
3298         poptFreeContext(pc);
3299
3300         pstrcpy(username, cmdline_get_username());
3301         pstrcpy(domain, cmdline_get_userdomain());
3302         pstrcpy(password, cmdline_get_userpassword());
3303
3304         DEBUG( 3, ( "Client started (version %s).\n", SAMBA_VERSION_STRING ) );
3305
3306         talloc_destroy(mem_ctx);
3307
3308         if ((p=strchr_m(query_host,'#'))) {
3309                 *p = 0;
3310                 p++;
3311                 sscanf(p, "%x", &name_type);
3312         }
3313   
3314         if (*query_host) {
3315                 return do_host_query(query_host);
3316         }
3317
3318         if (message) {
3319                 return do_message_op();
3320         }
3321         
3322         if (process(base_directory)) {
3323                 return 1;
3324         }
3325
3326         return rc;
3327 }