r5518: Add initial msdfs support to smbclient. Currently I can only
[samba.git] / source / client / client.c
1 /* 
2    Unix SMB/CIFS implementation.
3    SMB client
4    Copyright (C) Andrew Tridgell          1994-1998
5    Copyright (C) Simo Sorce               2001-2002
6    Copyright (C) Jelmer Vernooij          2003
7    Copyright (C) Gerald (Jerry) Carter    2004
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 #define NO_SYSLOG
25
26 #include "includes.h"
27 #include "client/client_proto.h"
28 #ifndef REGISTER
29 #define REGISTER 0
30 #endif
31
32 extern BOOL in_client;
33 static int port = 0;
34 pstring cur_dir = "\\";
35 static pstring cd_path = "";
36 static pstring service;
37 static pstring desthost;
38 static pstring username;
39 static pstring password;
40 static BOOL use_kerberos;
41 static BOOL got_pass;
42 static BOOL grepable=False;
43 static char *cmdstr = NULL;
44
45 static int io_bufsize = 64512;
46
47 static int name_type = 0x20;
48 static int max_protocol = PROTOCOL_NT1;
49
50 static int process_tok(pstring tok);
51 static int cmd_help(void);
52
53 /* 30 second timeout on most commands */
54 #define CLIENT_TIMEOUT (30*1000)
55 #define SHORT_TIMEOUT (5*1000)
56
57 /* value for unused fid field in trans2 secondary request */
58 #define FID_UNUSED (0xFFFF)
59
60 time_t newer_than = 0;
61 static int archive_level = 0;
62
63 static BOOL translation = False;
64
65 static BOOL have_ip;
66
67 /* clitar bits insert */
68 extern int blocksize;
69 extern BOOL tar_inc;
70 extern BOOL tar_reset;
71 /* clitar bits end */
72  
73
74 static BOOL prompt = True;
75
76 static int printmode = 1;
77
78 static BOOL recurse = False;
79 BOOL lowercase = False;
80
81 static struct in_addr dest_ip;
82
83 #define SEPARATORS " \t\n\r"
84
85 static BOOL abort_mget = True;
86
87 static pstring fileselection = "";
88
89 extern file_info def_finfo;
90
91 /* timing globals */
92 SMB_BIG_UINT get_total_size = 0;
93 unsigned int get_total_time_ms = 0;
94 static SMB_BIG_UINT put_total_size = 0;
95 static unsigned int put_total_time_ms = 0;
96
97 /* totals globals */
98 static double dir_total;
99
100
101 struct client_connection {
102         struct client_connection *prev, *next;
103         struct client_connection *parent;
104         struct cli_state *cli;
105         pstring mntpath;
106 };
107
108 struct cli_state *cli;
109 static struct client_connection *connections;
110
111 /********************************************************************
112  Return a connection to a server.
113 ********************************************************************/
114
115 static struct cli_state *do_connect( const char *server, const char *share,
116                                      BOOL show_sessetup )
117 {
118         struct cli_state *c;
119         struct nmb_name called, calling;
120         const char *server_n;
121         struct in_addr ip;
122         pstring servicename;
123         char *sharename;
124         
125         /* make a copy so we don't modify the global string 'service' */
126         pstrcpy(servicename, share);
127         sharename = servicename;
128         if (*sharename == '\\') {
129                 server = sharename+2;
130                 sharename = strchr_m(server,'\\');
131                 if (!sharename) return NULL;
132                 *sharename = 0;
133                 sharename++;
134         }
135
136         server_n = server;
137         
138         zero_ip(&ip);
139
140         make_nmb_name(&calling, global_myname(), 0x0);
141         make_nmb_name(&called , server, name_type);
142
143  again:
144         zero_ip(&ip);
145         if (have_ip) ip = dest_ip;
146
147         /* have to open a new connection */
148         if (!(c=cli_initialise(NULL)) || (cli_set_port(c, port) != port) ||
149             !cli_connect(c, server_n, &ip)) {
150                 d_printf("Connection to %s failed\n", server_n);
151                 return NULL;
152         }
153
154         c->protocol = max_protocol;
155         c->use_kerberos = use_kerberos;
156         cli_setup_signing_state(c, cmdline_auth_info.signing_state);
157                 
158
159         if (!cli_session_request(c, &calling, &called)) {
160                 char *p;
161                 d_printf("session request to %s failed (%s)\n", 
162                          called.name, cli_errstr(c));
163                 cli_shutdown(c);
164                 if ((p=strchr_m(called.name, '.'))) {
165                         *p = 0;
166                         goto again;
167                 }
168                 if (strcmp(called.name, "*SMBSERVER")) {
169                         make_nmb_name(&called , "*SMBSERVER", 0x20);
170                         goto again;
171                 }
172                 return NULL;
173         }
174
175         DEBUG(4,(" session request ok\n"));
176
177         if (!cli_negprot(c)) {
178                 d_printf("protocol negotiation failed\n");
179                 cli_shutdown(c);
180                 return NULL;
181         }
182
183         if (!got_pass) {
184                 char *pass = getpass("Password: ");
185                 if (pass) {
186                         pstrcpy(password, pass);
187                         got_pass = 1;
188                 }
189         }
190
191         if (!cli_session_setup(c, username, 
192                                password, strlen(password),
193                                password, strlen(password),
194                                lp_workgroup())) {
195                 /* if a password was not supplied then try again with a null username */
196                 if (password[0] || !username[0] || use_kerberos ||
197                     !cli_session_setup(c, "", "", 0, "", 0, lp_workgroup())) { 
198                         d_printf("session setup failed: %s\n", cli_errstr(c));
199                         if (NT_STATUS_V(cli_nt_error(c)) == 
200                             NT_STATUS_V(NT_STATUS_MORE_PROCESSING_REQUIRED))
201                                 d_printf("did you forget to run kinit?\n");
202                         cli_shutdown(c);
203                         return NULL;
204                 }
205                 d_printf("Anonymous login successful\n");
206         }
207
208         if ( show_sessetup ) {
209                 if (*c->server_domain) {
210                         DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",
211                                 c->server_domain,c->server_os,c->server_type));
212                 } else if (*c->server_os || *c->server_type){
213                         DEBUG(1,("OS=[%s] Server=[%s]\n",
214                                  c->server_os,c->server_type));
215                 }               
216         }
217         DEBUG(4,(" session setup ok\n"));
218
219         if (!cli_send_tconX(c, sharename, "?????",
220                             password, strlen(password)+1)) {
221                 d_printf("tree connect failed: %s\n", cli_errstr(c));
222                 cli_shutdown(c);
223                 return NULL;
224         }
225
226         DEBUG(4,(" tconx ok\n"));
227
228         return c;
229 }
230
231 /********************************************************************
232  Add a new connection to the list
233 ********************************************************************/
234
235 static struct cli_state* cli_cm_connect( const char *server, const char *share,
236                                          BOOL show_hdr )
237 {
238         struct client_connection *node, *pparent, *p;
239         
240         node = SMB_XMALLOC_P( struct client_connection );
241         
242         node->cli = do_connect( server, share, show_hdr );
243
244         if ( !node->cli ) {
245                 SAFE_FREE( node );
246                 return NULL;
247         }
248
249         pparent = NULL;
250         for ( p=connections; p; p=p->next ) {
251                 if ( strequal(cli->desthost, p->cli->desthost) && strequal(cli->share, p->cli->share) )
252                         pparent = p;
253         }
254         
255         node->parent = pparent;
256         pstrcpy( node->mntpath, cur_dir );
257
258         DLIST_ADD( connections, node );
259
260         return node->cli;
261
262 }
263
264 /********************************************************************
265  Return a connection to a server.
266 ********************************************************************/
267
268 static struct cli_state* cli_cm_find( const char *server, const char *share )
269 {
270         struct client_connection *p;
271
272         for ( p=connections; p; p=p->next ) {
273                 if ( strequal(server, p->cli->desthost) && strequal(share,p->cli->share) )
274                         return p->cli;
275         }
276
277         return NULL;
278 }
279
280 /****************************************************************************
281  open a client connection to a \\server\share.  Set's the current *cli 
282  global variable as a side-effect (but only if the connection is successful).
283 ****************************************************************************/
284
285 struct cli_state* cli_cm_open( const char *server, const char *share, BOOL show_hdr )
286 {
287         struct cli_state *c;
288         
289         /* try to reuse an existing connection */
290
291         c = cli_cm_find( server, share );
292         
293         if ( !c )
294                 c = cli_cm_connect( server, share, show_hdr );
295
296         return c;
297 }
298
299 /****************************************************************************
300 ****************************************************************************/
301
302 struct cli_state* cli_cm_current( void )
303 {
304         return cli;
305 }
306
307 /****************************************************************************
308 ****************************************************************************/
309
310 const char* cli_cm_get_mntpath( struct cli_state *pcli )
311 {
312         struct client_connection *p;
313         
314         for ( p=connections; p; p=p->next ) {
315                 if ( strequal(pcli->desthost, p->cli->desthost) && strequal(pcli->share, p->cli->share) )
316                         break;
317         }
318         
319         if ( !p )
320                 return NULL;
321                 
322         return p->mntpath;
323 }
324
325 /****************************************************************************
326  Write to a local file with CR/LF->LF translation if appropriate. Return the 
327  number taken from the buffer. This may not equal the number written.
328 ****************************************************************************/
329
330 static int writefile(int f, char *b, int n)
331 {
332         int i;
333
334         if (!translation) {
335                 return write(f,b,n);
336         }
337
338         i = 0;
339         while (i < n) {
340                 if (*b == '\r' && (i<(n-1)) && *(b+1) == '\n') {
341                         b++;i++;
342                 }
343                 if (write(f, b, 1) != 1) {
344                         break;
345                 }
346                 b++;
347                 i++;
348         }
349   
350         return(i);
351 }
352
353 /****************************************************************************
354  Read from a file with LF->CR/LF translation if appropriate. Return the 
355  number read. read approx n bytes.
356 ****************************************************************************/
357
358 static int readfile(char *b, int n, XFILE *f)
359 {
360         int i;
361         int c;
362
363         if (!translation)
364                 return x_fread(b,1,n,f);
365   
366         i = 0;
367         while (i < (n - 1) && (i < BUFFER_SIZE)) {
368                 if ((c = x_getc(f)) == EOF) {
369                         break;
370                 }
371       
372                 if (c == '\n') { /* change all LFs to CR/LF */
373                         b[i++] = '\r';
374                 }
375       
376                 b[i++] = c;
377         }
378   
379         return(i);
380 }
381  
382 /****************************************************************************
383  Send a message.
384 ****************************************************************************/
385
386 static void send_message(void)
387 {
388         int total_len = 0;
389         int grp_id;
390
391         if (!cli_message_start(cli, desthost, username, &grp_id)) {
392                 d_printf("message start: %s\n", cli_errstr(cli));
393                 return;
394         }
395
396
397         d_printf("Connected. Type your message, ending it with a Control-D\n");
398
399         while (!feof(stdin) && total_len < 1600) {
400                 int maxlen = MIN(1600 - total_len,127);
401                 pstring msg;
402                 int l=0;
403                 int c;
404
405                 ZERO_ARRAY(msg);
406
407                 for (l=0;l<maxlen && (c=fgetc(stdin))!=EOF;l++) {
408                         if (c == '\n')
409                                 msg[l++] = '\r';
410                         msg[l] = c;   
411                 }
412
413                 if (!cli_message_text(cli, msg, l, grp_id)) {
414                         d_printf("SMBsendtxt failed (%s)\n",cli_errstr(cli));
415                         return;
416                 }      
417                 
418                 total_len += l;
419         }
420
421         if (total_len >= 1600)
422                 d_printf("the message was truncated to 1600 bytes\n");
423         else
424                 d_printf("sent %d bytes\n",total_len);
425
426         if (!cli_message_end(cli, grp_id)) {
427                 d_printf("SMBsendend failed (%s)\n",cli_errstr(cli));
428                 return;
429         }      
430 }
431
432 /****************************************************************************
433  Check the space on a device.
434 ****************************************************************************/
435
436 static int do_dskattr(void)
437 {
438         int total, bsize, avail;
439         struct cli_state *targetcli;
440         pstring targetpath;
441
442         if ( !cli_resolve_path( cli, cur_dir, &targetcli, targetpath ) ) {
443                 d_printf("Error in dskattr: %s\n", cli_errstr(cli));
444         }
445
446         if (!cli_dskattr(targetcli, &bsize, &total, &avail)) {
447                 d_printf("Error in dskattr: %s\n",cli_errstr(targetcli)); 
448                 return 1;
449         }
450
451         d_printf("\n\t\t%d blocks of size %d. %d blocks available\n",
452                  total, bsize, avail);
453
454         return 0;
455 }
456
457 /****************************************************************************
458  Show cd/pwd.
459 ****************************************************************************/
460
461 static int cmd_pwd(void)
462 {
463         d_printf("Current directory is %s",service);
464         d_printf("%s\n",cur_dir);
465         return 0;
466 }
467
468 /****************************************************************************
469  Change directory - inner section.
470 ****************************************************************************/
471
472 static int do_cd(char *newdir)
473 {
474         char *p = newdir;
475         pstring saved_dir;
476         pstring dname;
477         pstring targetpath;
478         struct cli_state *targetcli;
479       
480         dos_format(newdir);
481
482         /* Save the current directory in case the new directory is invalid */
483
484         pstrcpy(saved_dir, cur_dir);
485
486         if (*p == '\\')
487                 pstrcpy(cur_dir,p);
488         else
489                 pstrcat(cur_dir,p);
490
491         if (*(cur_dir+strlen(cur_dir)-1) != '\\') {
492                 pstrcat(cur_dir, "\\");
493         }
494
495         dos_clean_name(cur_dir);
496         pstrcpy( dname, cur_dir );
497         pstrcat(cur_dir,"\\");
498         dos_clean_name(cur_dir);
499         
500         if ( !cli_resolve_path( cli, dname, &targetcli, targetpath ) ) {
501                 d_printf("cd %s: %s\n", dname, cli_errstr(cli));
502                 pstrcpy(cur_dir,saved_dir);
503         }
504
505         pstrcat( targetpath, "\\" );
506         dos_clean_name( targetpath );
507
508         if ( !strequal(targetpath,"\\") ) {     
509                 if ( !cli_chkpath(targetcli, targetpath) ) {
510                         d_printf("cd %s: %s\n", dname, cli_errstr(targetcli));
511                         pstrcpy(cur_dir,saved_dir);
512                 }
513         }
514
515         pstrcpy(cd_path,cur_dir);
516
517         return 0;
518 }
519
520 /****************************************************************************
521  Change directory.
522 ****************************************************************************/
523
524 static int cmd_cd(void)
525 {
526         pstring buf;
527         int rc = 0;
528                 
529         if (next_token_nr(NULL,buf,NULL,sizeof(buf)))
530                 rc = do_cd(buf);
531         else
532                 d_printf("Current directory is %s\n",cur_dir);
533
534         return rc;
535 }
536
537 /*******************************************************************
538  Decide if a file should be operated on.
539 ********************************************************************/
540
541 static BOOL do_this_one(file_info *finfo)
542 {
543         if (finfo->mode & aDIR)
544                 return(True);
545
546         if (*fileselection && 
547             !mask_match(finfo->name,fileselection,False)) {
548                 DEBUG(3,("mask_match %s failed\n", finfo->name));
549                 return False;
550         }
551
552         if (newer_than && finfo->mtime < newer_than) {
553                 DEBUG(3,("newer_than %s failed\n", finfo->name));
554                 return(False);
555         }
556
557         if ((archive_level==1 || archive_level==2) && !(finfo->mode & aARCH)) {
558                 DEBUG(3,("archive %s failed\n", finfo->name));
559                 return(False);
560         }
561         
562         return(True);
563 }
564
565 /****************************************************************************
566  Display info about a file.
567 ****************************************************************************/
568
569 static void display_finfo(file_info *finfo)
570 {
571         if (do_this_one(finfo)) {
572                 time_t t = finfo->mtime; /* the time is assumed to be passed as GMT */
573                 d_printf("  %-30s%7.7s %8.0f  %s",
574                          finfo->name,
575                          attrib_string(finfo->mode),
576                          (double)finfo->size,
577                          asctime(LocalTime(&t)));
578                 dir_total += finfo->size;
579         }
580 }
581
582 /****************************************************************************
583  Accumulate size of a file.
584 ****************************************************************************/
585
586 static void do_du(file_info *finfo)
587 {
588         if (do_this_one(finfo)) {
589                 dir_total += finfo->size;
590         }
591 }
592
593 static BOOL do_list_recurse;
594 static BOOL do_list_dirs;
595 static char *do_list_queue = 0;
596 static long do_list_queue_size = 0;
597 static long do_list_queue_start = 0;
598 static long do_list_queue_end = 0;
599 static void (*do_list_fn)(file_info *);
600
601 /****************************************************************************
602  Functions for do_list_queue.
603 ****************************************************************************/
604
605 /*
606  * The do_list_queue is a NUL-separated list of strings stored in a
607  * char*.  Since this is a FIFO, we keep track of the beginning and
608  * ending locations of the data in the queue.  When we overflow, we
609  * double the size of the char*.  When the start of the data passes
610  * the midpoint, we move everything back.  This is logically more
611  * complex than a linked list, but easier from a memory management
612  * angle.  In any memory error condition, do_list_queue is reset.
613  * Functions check to ensure that do_list_queue is non-NULL before
614  * accessing it.
615  */
616
617 static void reset_do_list_queue(void)
618 {
619         SAFE_FREE(do_list_queue);
620         do_list_queue_size = 0;
621         do_list_queue_start = 0;
622         do_list_queue_end = 0;
623 }
624
625 static void init_do_list_queue(void)
626 {
627         reset_do_list_queue();
628         do_list_queue_size = 1024;
629         do_list_queue = SMB_MALLOC(do_list_queue_size);
630         if (do_list_queue == 0) { 
631                 d_printf("malloc fail for size %d\n",
632                          (int)do_list_queue_size);
633                 reset_do_list_queue();
634         } else {
635                 memset(do_list_queue, 0, do_list_queue_size);
636         }
637 }
638
639 static void adjust_do_list_queue(void)
640 {
641         /*
642          * If the starting point of the queue is more than half way through,
643          * move everything toward the beginning.
644          */
645         if (do_list_queue && (do_list_queue_start == do_list_queue_end)) {
646                 DEBUG(4,("do_list_queue is empty\n"));
647                 do_list_queue_start = do_list_queue_end = 0;
648                 *do_list_queue = '\0';
649         } else if (do_list_queue_start > (do_list_queue_size / 2)) {
650                 DEBUG(4,("sliding do_list_queue backward\n"));
651                 memmove(do_list_queue,
652                         do_list_queue + do_list_queue_start,
653                         do_list_queue_end - do_list_queue_start);
654                 do_list_queue_end -= do_list_queue_start;
655                 do_list_queue_start = 0;
656         }
657 }
658
659 static void add_to_do_list_queue(const char* entry)
660 {
661         char *dlq;
662         long new_end = do_list_queue_end + ((long)strlen(entry)) + 1;
663         while (new_end > do_list_queue_size) {
664                 do_list_queue_size *= 2;
665                 DEBUG(4,("enlarging do_list_queue to %d\n",
666                          (int)do_list_queue_size));
667                 dlq = SMB_REALLOC(do_list_queue, do_list_queue_size);
668                 if (! dlq) {
669                         d_printf("failure enlarging do_list_queue to %d bytes\n",
670                                  (int)do_list_queue_size);
671                         reset_do_list_queue();
672                 } else {
673                         do_list_queue = dlq;
674                         memset(do_list_queue + do_list_queue_size / 2,
675                                0, do_list_queue_size / 2);
676                 }
677         }
678         if (do_list_queue) {
679                 safe_strcpy_base(do_list_queue + do_list_queue_end, 
680                                  entry, do_list_queue, do_list_queue_size);
681                 do_list_queue_end = new_end;
682                 DEBUG(4,("added %s to do_list_queue (start=%d, end=%d)\n",
683                          entry, (int)do_list_queue_start, (int)do_list_queue_end));
684         }
685 }
686
687 static char *do_list_queue_head(void)
688 {
689         return do_list_queue + do_list_queue_start;
690 }
691
692 static void remove_do_list_queue_head(void)
693 {
694         if (do_list_queue_end > do_list_queue_start) {
695                 do_list_queue_start += strlen(do_list_queue_head()) + 1;
696                 adjust_do_list_queue();
697                 DEBUG(4,("removed head of do_list_queue (start=%d, end=%d)\n",
698                          (int)do_list_queue_start, (int)do_list_queue_end));
699         }
700 }
701
702 static int do_list_queue_empty(void)
703 {
704         return (! (do_list_queue && *do_list_queue));
705 }
706
707 /****************************************************************************
708  A helper for do_list.
709 ****************************************************************************/
710
711 static void do_list_helper(file_info *f, const char *mask, void *state)
712 {
713         if (f->mode & aDIR) {
714                 if (do_list_dirs && do_this_one(f)) {
715                         do_list_fn(f);
716                 }
717                 if (do_list_recurse && 
718                     !strequal(f->name,".") && 
719                     !strequal(f->name,"..")) {
720                         pstring mask2;
721                         char *p;
722
723                         if (!f->name[0]) {
724                                 d_printf("Empty dir name returned. Possible server misconfiguration.\n");
725                                 return;
726                         }
727
728                         pstrcpy(mask2, mask);
729                         p = strrchr_m(mask2,'\\');
730                         if (!p)
731                                 return;
732                         p[1] = 0;
733                         pstrcat(mask2, f->name);
734                         pstrcat(mask2,"\\*");
735                         add_to_do_list_queue(mask2);
736                 }
737                 return;
738         }
739
740         if (do_this_one(f)) {
741                 do_list_fn(f);
742         }
743 }
744
745 /****************************************************************************
746  A wrapper around cli_list that adds recursion.
747 ****************************************************************************/
748
749 void do_list(const char *mask,uint16 attribute,void (*fn)(file_info *),BOOL rec, BOOL dirs)
750 {
751         static int in_do_list = 0;
752         struct cli_state *targetcli;
753         pstring targetpath;
754
755         if (in_do_list && rec) {
756                 fprintf(stderr, "INTERNAL ERROR: do_list called recursively when the recursive flag is true\n");
757                 exit(1);
758         }
759
760         in_do_list = 1;
761
762         do_list_recurse = rec;
763         do_list_dirs = dirs;
764         do_list_fn = fn;
765
766         if (rec) {
767                 init_do_list_queue();
768                 add_to_do_list_queue(mask);
769                 
770                 while (! do_list_queue_empty()) {
771                         /*
772                          * Need to copy head so that it doesn't become
773                          * invalid inside the call to cli_list.  This
774                          * would happen if the list were expanded
775                          * during the call.
776                          * Fix from E. Jay Berkenbilt (ejb@ql.org)
777                          */
778                         pstring head;
779                         pstrcpy(head, do_list_queue_head());
780                         
781                         /* check for dfs */
782                         
783                         if ( !cli_resolve_path( cli, head, &targetcli, targetpath ) ) {
784                                 d_printf("do_list: [%s] %s\n", head, cli_errstr(cli));
785                                 continue;
786                         }
787                         
788                         cli_list(targetcli, targetpath, attribute, do_list_helper, NULL);
789                         remove_do_list_queue_head();
790                         if ((! do_list_queue_empty()) && (fn == display_finfo)) {
791                                 char* next_file = do_list_queue_head();
792                                 char* save_ch = 0;
793                                 if ((strlen(next_file) >= 2) &&
794                                     (next_file[strlen(next_file) - 1] == '*') &&
795                                     (next_file[strlen(next_file) - 2] == '\\')) {
796                                         save_ch = next_file +
797                                                 strlen(next_file) - 2;
798                                         *save_ch = '\0';
799                                 }
800                                 d_printf("\n%s\n",next_file);
801                                 if (save_ch) {
802                                         *save_ch = '\\';
803                                 }
804                         }
805                 }
806         } else {
807                 /* check for dfs */
808                         
809                 if ( cli_resolve_path( cli, mask, &targetcli, targetpath ) ) {
810                         if (cli_list(targetcli, targetpath, attribute, do_list_helper, NULL) == -1) 
811                                 d_printf("%s listing %s\n", cli_errstr(targetcli), targetpath);
812                 }
813                 else
814                         d_printf("do_list: [%s] %s\n", mask, cli_errstr(cli));
815                 
816         }
817
818         in_do_list = 0;
819         reset_do_list_queue();
820 }
821
822 /****************************************************************************
823  Get a directory listing.
824 ****************************************************************************/
825
826 static int cmd_dir(void)
827 {
828         uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
829         pstring mask;
830         pstring buf;
831         char *p=buf;
832         int rc;
833         
834         dir_total = 0;
835         if (strcmp(cur_dir, "\\") != 0) {
836                 pstrcpy(mask,cur_dir);
837                 if(mask[strlen(mask)-1]!='\\')
838                         pstrcat(mask,"\\");
839         } else {
840                 pstrcpy(mask, "\\");
841         }
842         
843         if (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
844                 dos_format(p);
845                 if (*p == '\\')
846                         pstrcpy(mask,p + 1);
847                 else
848                         pstrcat(mask,p);
849         } else {
850                 pstrcat(mask,"*");
851         }
852
853         do_list(mask, attribute, display_finfo, recurse, True);
854
855         rc = do_dskattr();
856
857         DEBUG(3, ("Total bytes listed: %.0f\n", dir_total));
858
859         return rc;
860 }
861
862 /****************************************************************************
863  Get a directory listing.
864 ****************************************************************************/
865
866 static int cmd_du(void)
867 {
868         uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
869         pstring mask;
870         pstring buf;
871         char *p=buf;
872         int rc;
873         
874         dir_total = 0;
875         pstrcpy(mask,cur_dir);
876         if(mask[strlen(mask)-1]!='\\')
877                 pstrcat(mask,"\\");
878         
879         if (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
880                 dos_format(p);
881                 if (*p == '\\')
882                         pstrcpy(mask,p);
883                 else
884                         pstrcat(mask,p);
885         } else {
886                 pstrcat(mask,"*");
887         }
888
889         do_list(mask, attribute, do_du, recurse, True);
890
891         rc = do_dskattr();
892
893         d_printf("Total number of bytes: %.0f\n", dir_total);
894
895         return rc;
896 }
897
898 /****************************************************************************
899  Get a file from rname to lname
900 ****************************************************************************/
901
902 static int do_get(char *rname, char *lname, BOOL reget)
903 {  
904         int handle = 0, fnum;
905         BOOL newhandle = False;
906         char *data;
907         struct timeval tp_start;
908         int read_size = io_bufsize;
909         uint16 attr;
910         size_t size;
911         off_t start = 0;
912         off_t nread = 0;
913         int rc = 0;
914
915         GetTimeOfDay(&tp_start);
916
917         if (lowercase) {
918                 strlower_m(lname);
919         }
920
921         fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
922
923         if (fnum == -1) {
924                 d_printf("%s opening remote file %s\n",cli_errstr(cli),rname);
925                 return 1;
926         }
927
928         if(!strcmp(lname,"-")) {
929                 handle = fileno(stdout);
930         } else {
931                 if (reget) {
932                         handle = sys_open(lname, O_WRONLY|O_CREAT, 0644);
933                         if (handle >= 0) {
934                                 start = sys_lseek(handle, 0, SEEK_END);
935                                 if (start == -1) {
936                                         d_printf("Error seeking local file\n");
937                                         return 1;
938                                 }
939                         }
940                 } else {
941                         handle = sys_open(lname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
942                 }
943                 newhandle = True;
944         }
945         if (handle < 0) {
946                 d_printf("Error opening local file %s\n",lname);
947                 return 1;
948         }
949
950
951         if (!cli_qfileinfo(cli, fnum, 
952                            &attr, &size, NULL, NULL, NULL, NULL, NULL) &&
953             !cli_getattrE(cli, fnum, 
954                           &attr, &size, NULL, NULL, NULL)) {
955                 d_printf("getattrib: %s\n",cli_errstr(cli));
956                 return 1;
957         }
958
959         DEBUG(1,("getting file %s of size %.0f as %s ", 
960                  rname, (double)size, lname));
961
962         if(!(data = (char *)SMB_MALLOC(read_size))) { 
963                 d_printf("malloc fail for size %d\n", read_size);
964                 cli_close(cli, fnum);
965                 return 1;
966         }
967
968         while (1) {
969                 int n = cli_read(cli, fnum, data, nread + start, read_size);
970
971                 if (n <= 0)
972                         break;
973  
974                 if (writefile(handle,data, n) != n) {
975                         d_printf("Error writing local file\n");
976                         rc = 1;
977                         break;
978                 }
979       
980                 nread += n;
981         }
982
983         if (nread + start < size) {
984                 DEBUG (0, ("Short read when getting file %s. Only got %ld bytes.\n",
985                             rname, (long)nread));
986
987                 rc = 1;
988         }
989
990         SAFE_FREE(data);
991         
992         if (!cli_close(cli, fnum)) {
993                 d_printf("Error %s closing remote file\n",cli_errstr(cli));
994                 rc = 1;
995         }
996
997         if (newhandle) {
998                 close(handle);
999         }
1000
1001         if (archive_level >= 2 && (attr & aARCH)) {
1002                 cli_setatr(cli, rname, attr & ~(uint16)aARCH, 0);
1003         }
1004
1005         {
1006                 struct timeval tp_end;
1007                 int this_time;
1008                 
1009                 GetTimeOfDay(&tp_end);
1010                 this_time = 
1011                         (tp_end.tv_sec - tp_start.tv_sec)*1000 +
1012                         (tp_end.tv_usec - tp_start.tv_usec)/1000;
1013                 get_total_time_ms += this_time;
1014                 get_total_size += nread;
1015                 
1016                 DEBUG(1,("(%3.1f kb/s) (average %3.1f kb/s)\n",
1017                          nread / (1.024*this_time + 1.0e-4),
1018                          get_total_size / (1.024*get_total_time_ms)));
1019         }
1020         
1021         return rc;
1022 }
1023
1024 /****************************************************************************
1025  Get a file.
1026 ****************************************************************************/
1027
1028 static int cmd_get(void)
1029 {
1030         pstring lname;
1031         pstring rname;
1032         char *p;
1033
1034         pstrcpy(rname,cur_dir);
1035         pstrcat(rname,"\\");
1036         
1037         p = rname + strlen(rname);
1038         
1039         if (!next_token_nr(NULL,p,NULL,sizeof(rname)-strlen(rname))) {
1040                 d_printf("get <filename>\n");
1041                 return 1;
1042         }
1043         pstrcpy(lname,p);
1044         dos_clean_name(rname);
1045         
1046         next_token_nr(NULL,lname,NULL,sizeof(lname));
1047         
1048         return do_get(rname, lname, False);
1049 }
1050
1051 /****************************************************************************
1052  Do an mget operation on one file.
1053 ****************************************************************************/
1054
1055 static void do_mget(file_info *finfo)
1056 {
1057         pstring rname;
1058         pstring quest;
1059         pstring saved_curdir;
1060         pstring mget_mask;
1061
1062         if (strequal(finfo->name,".") || strequal(finfo->name,".."))
1063                 return;
1064
1065         if (abort_mget) {
1066                 d_printf("mget aborted\n");
1067                 return;
1068         }
1069
1070         if (finfo->mode & aDIR)
1071                 slprintf(quest,sizeof(pstring)-1,
1072                          "Get directory %s? ",finfo->name);
1073         else
1074                 slprintf(quest,sizeof(pstring)-1,
1075                          "Get file %s? ",finfo->name);
1076
1077         if (prompt && !yesno(quest))
1078                 return;
1079
1080         if (!(finfo->mode & aDIR)) {
1081                 pstrcpy(rname,cur_dir);
1082                 pstrcat(rname,finfo->name);
1083                 do_get(rname, finfo->name, False);
1084                 return;
1085         }
1086
1087         /* handle directories */
1088         pstrcpy(saved_curdir,cur_dir);
1089
1090         pstrcat(cur_dir,finfo->name);
1091         pstrcat(cur_dir,"\\");
1092
1093         unix_format(finfo->name);
1094         if (lowercase)
1095                 strlower_m(finfo->name);
1096         
1097         if (!directory_exist(finfo->name,NULL) && 
1098             mkdir(finfo->name,0777) != 0) {
1099                 d_printf("failed to create directory %s\n",finfo->name);
1100                 pstrcpy(cur_dir,saved_curdir);
1101                 return;
1102         }
1103         
1104         if (chdir(finfo->name) != 0) {
1105                 d_printf("failed to chdir to directory %s\n",finfo->name);
1106                 pstrcpy(cur_dir,saved_curdir);
1107                 return;
1108         }
1109
1110         pstrcpy(mget_mask,cur_dir);
1111         pstrcat(mget_mask,"*");
1112         
1113         do_list(mget_mask, aSYSTEM | aHIDDEN | aDIR,do_mget,False, True);
1114         chdir("..");
1115         pstrcpy(cur_dir,saved_curdir);
1116 }
1117
1118 /****************************************************************************
1119  View the file using the pager.
1120 ****************************************************************************/
1121
1122 static int cmd_more(void)
1123 {
1124         pstring rname,lname,pager_cmd;
1125         char *pager;
1126         int fd;
1127         int rc = 0;
1128
1129         pstrcpy(rname,cur_dir);
1130         pstrcat(rname,"\\");
1131         
1132         slprintf(lname,sizeof(lname)-1, "%s/smbmore.XXXXXX",tmpdir());
1133         fd = smb_mkstemp(lname);
1134         if (fd == -1) {
1135                 d_printf("failed to create temporary file for more\n");
1136                 return 1;
1137         }
1138         close(fd);
1139
1140         if (!next_token_nr(NULL,rname+strlen(rname),NULL,sizeof(rname)-strlen(rname))) {
1141                 d_printf("more <filename>\n");
1142                 unlink(lname);
1143                 return 1;
1144         }
1145         dos_clean_name(rname);
1146
1147         rc = do_get(rname, lname, False);
1148
1149         pager=getenv("PAGER");
1150
1151         slprintf(pager_cmd,sizeof(pager_cmd)-1,
1152                  "%s %s",(pager? pager:PAGER), lname);
1153         system(pager_cmd);
1154         unlink(lname);
1155         
1156         return rc;
1157 }
1158
1159 /****************************************************************************
1160  Do a mget command.
1161 ****************************************************************************/
1162
1163 static int cmd_mget(void)
1164 {
1165         uint16 attribute = aSYSTEM | aHIDDEN;
1166         pstring mget_mask;
1167         pstring buf;
1168         char *p=buf;
1169
1170         *mget_mask = 0;
1171
1172         if (recurse)
1173                 attribute |= aDIR;
1174         
1175         abort_mget = False;
1176
1177         while (next_token_nr(NULL,p,NULL,sizeof(buf))) {
1178                 pstrcpy(mget_mask,cur_dir);
1179                 if(mget_mask[strlen(mget_mask)-1]!='\\')
1180                         pstrcat(mget_mask,"\\");
1181                 
1182                 if (*p == '\\')
1183                         pstrcpy(mget_mask,p);
1184                 else
1185                         pstrcat(mget_mask,p);
1186                 do_list(mget_mask, attribute,do_mget,False,True);
1187         }
1188
1189         if (!*mget_mask) {
1190                 pstrcpy(mget_mask,cur_dir);
1191                 if(mget_mask[strlen(mget_mask)-1]!='\\')
1192                         pstrcat(mget_mask,"\\");
1193                 pstrcat(mget_mask,"*");
1194                 do_list(mget_mask, attribute,do_mget,False,True);
1195         }
1196         
1197         return 0;
1198 }
1199
1200 /****************************************************************************
1201  Make a directory of name "name".
1202 ****************************************************************************/
1203
1204 static BOOL do_mkdir(char *name)
1205 {
1206         if (!cli_mkdir(cli, name)) {
1207                 d_printf("%s making remote directory %s\n",
1208                          cli_errstr(cli),name);
1209                 return(False);
1210         }
1211
1212         return(True);
1213 }
1214
1215 /****************************************************************************
1216  Show 8.3 name of a file.
1217 ****************************************************************************/
1218
1219 static BOOL do_altname(char *name)
1220 {
1221         pstring altname;
1222         if (!NT_STATUS_IS_OK(cli_qpathinfo_alt_name(cli, name, altname))) {
1223                 d_printf("%s getting alt name for %s\n",
1224                          cli_errstr(cli),name);
1225                 return(False);
1226         }
1227         d_printf("%s\n", altname);
1228
1229         return(True);
1230 }
1231
1232 /****************************************************************************
1233  Exit client.
1234 ****************************************************************************/
1235
1236 static int cmd_quit(void)
1237 {
1238         cli_shutdown(cli);
1239         exit(0);
1240         /* NOTREACHED */
1241         return 0;
1242 }
1243
1244 /****************************************************************************
1245  Make a directory.
1246 ****************************************************************************/
1247
1248 static int cmd_mkdir(void)
1249 {
1250         pstring mask;
1251         pstring buf;
1252         char *p=buf;
1253   
1254         pstrcpy(mask,cur_dir);
1255
1256         if (!next_token_nr(NULL,p,NULL,sizeof(buf))) {
1257                 if (!recurse)
1258                         d_printf("mkdir <dirname>\n");
1259                 return 1;
1260         }
1261         pstrcat(mask,p);
1262
1263         if (recurse) {
1264                 pstring ddir;
1265                 pstring ddir2;
1266                 *ddir2 = 0;
1267                 
1268                 pstrcpy(ddir,mask);
1269                 trim_char(ddir,'.','\0');
1270                 p = strtok(ddir,"/\\");
1271                 while (p) {
1272                         pstrcat(ddir2,p);
1273                         if (!cli_chkpath(cli, ddir2)) { 
1274                                 do_mkdir(ddir2);
1275                         }
1276                         pstrcat(ddir2,"\\");
1277                         p = strtok(NULL,"/\\");
1278                 }        
1279         } else {
1280                 do_mkdir(mask);
1281         }
1282         
1283         return 0;
1284 }
1285
1286 /****************************************************************************
1287  Show alt name.
1288 ****************************************************************************/
1289
1290 static int cmd_altname(void)
1291 {
1292         pstring name;
1293         pstring buf;
1294         char *p=buf;
1295   
1296         pstrcpy(name,cur_dir);
1297
1298         if (!next_token_nr(NULL,p,NULL,sizeof(buf))) {
1299                 d_printf("altname <file>\n");
1300                 return 1;
1301         }
1302         pstrcat(name,p);
1303
1304         do_altname(name);
1305
1306         return 0;
1307 }
1308
1309 /****************************************************************************
1310  Put a single file.
1311 ****************************************************************************/
1312
1313 static int do_put(char *rname, char *lname, BOOL reput)
1314 {
1315         int fnum;
1316         XFILE *f;
1317         size_t start = 0;
1318         off_t nread = 0;
1319         char *buf = NULL;
1320         int maxwrite = io_bufsize;
1321         int rc = 0;
1322         
1323         struct timeval tp_start;
1324         GetTimeOfDay(&tp_start);
1325
1326         if (reput) {
1327                 fnum = cli_open(cli, rname, O_RDWR|O_CREAT, DENY_NONE);
1328                 if (fnum >= 0) {
1329                         if (!cli_qfileinfo(cli, fnum, NULL, &start, NULL, NULL, NULL, NULL, NULL) &&
1330                             !cli_getattrE(cli, fnum, NULL, &start, NULL, NULL, NULL)) {
1331                                 d_printf("getattrib: %s\n",cli_errstr(cli));
1332                                 return 1;
1333                         }
1334                 }
1335         } else {
1336                 fnum = cli_open(cli, rname, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE);
1337         }
1338   
1339         if (fnum == -1) {
1340                 d_printf("%s opening remote file %s\n",cli_errstr(cli),rname);
1341                 return 1;
1342         }
1343
1344         /* allow files to be piped into smbclient
1345            jdblair 24.jun.98
1346
1347            Note that in this case this function will exit(0) rather
1348            than returning. */
1349         if (!strcmp(lname, "-")) {
1350                 f = x_stdin;
1351                 /* size of file is not known */
1352         } else {
1353                 f = x_fopen(lname,O_RDONLY, 0);
1354                 if (f && reput) {
1355                         if (x_tseek(f, start, SEEK_SET) == -1) {
1356                                 d_printf("Error seeking local file\n");
1357                                 return 1;
1358                         }
1359                 }
1360         }
1361
1362         if (!f) {
1363                 d_printf("Error opening local file %s\n",lname);
1364                 return 1;
1365         }
1366   
1367         DEBUG(1,("putting file %s as %s ",lname,
1368                  rname));
1369   
1370         buf = (char *)SMB_MALLOC(maxwrite);
1371         if (!buf) {
1372                 d_printf("ERROR: Not enough memory!\n");
1373                 return 1;
1374         }
1375         while (!x_feof(f)) {
1376                 int n = maxwrite;
1377                 int ret;
1378
1379                 if ((n = readfile(buf,n,f)) < 1) {
1380                         if((n == 0) && x_feof(f))
1381                                 break; /* Empty local file. */
1382
1383                         d_printf("Error reading local file: %s\n", strerror(errno));
1384                         rc = 1;
1385                         break;
1386                 }
1387
1388                 ret = cli_write(cli, fnum, 0, buf, nread + start, n);
1389
1390                 if (n != ret) {
1391                         d_printf("Error writing file: %s\n", cli_errstr(cli));
1392                         rc = 1;
1393                         break;
1394                 } 
1395
1396                 nread += n;
1397         }
1398
1399         if (!cli_close(cli, fnum)) {
1400                 d_printf("%s closing remote file %s\n",cli_errstr(cli),rname);
1401                 x_fclose(f);
1402                 SAFE_FREE(buf);
1403                 return 1;
1404         }
1405
1406         
1407         if (f != x_stdin) {
1408                 x_fclose(f);
1409         }
1410
1411         SAFE_FREE(buf);
1412
1413         {
1414                 struct timeval tp_end;
1415                 int this_time;
1416                 
1417                 GetTimeOfDay(&tp_end);
1418                 this_time = 
1419                         (tp_end.tv_sec - tp_start.tv_sec)*1000 +
1420                         (tp_end.tv_usec - tp_start.tv_usec)/1000;
1421                 put_total_time_ms += this_time;
1422                 put_total_size += nread;
1423                 
1424                 DEBUG(1,("(%3.1f kb/s) (average %3.1f kb/s)\n",
1425                          nread / (1.024*this_time + 1.0e-4),
1426                          put_total_size / (1.024*put_total_time_ms)));
1427         }
1428
1429         if (f == x_stdin) {
1430                 cli_shutdown(cli);
1431                 exit(0);
1432         }
1433         
1434         return rc;
1435 }
1436
1437 /****************************************************************************
1438  Put a file.
1439 ****************************************************************************/
1440
1441 static int cmd_put(void)
1442 {
1443         pstring lname;
1444         pstring rname;
1445         pstring buf;
1446         char *p=buf;
1447         
1448         pstrcpy(rname,cur_dir);
1449         pstrcat(rname,"\\");
1450   
1451         if (!next_token_nr(NULL,p,NULL,sizeof(buf))) {
1452                 d_printf("put <filename>\n");
1453                 return 1;
1454         }
1455         pstrcpy(lname,p);
1456   
1457         if (next_token_nr(NULL,p,NULL,sizeof(buf)))
1458                 pstrcat(rname,p);      
1459         else
1460                 pstrcat(rname,lname);
1461         
1462         dos_clean_name(rname);
1463
1464         {
1465                 SMB_STRUCT_STAT st;
1466                 /* allow '-' to represent stdin
1467                    jdblair, 24.jun.98 */
1468                 if (!file_exist(lname,&st) &&
1469                     (strcmp(lname,"-"))) {
1470                         d_printf("%s does not exist\n",lname);
1471                         return 1;
1472                 }
1473         }
1474
1475         return do_put(rname, lname, False);
1476 }
1477
1478 /*************************************
1479  File list structure.
1480 *************************************/
1481
1482 static struct file_list {
1483         struct file_list *prev, *next;
1484         char *file_path;
1485         BOOL isdir;
1486 } *file_list;
1487
1488 /****************************************************************************
1489  Free a file_list structure.
1490 ****************************************************************************/
1491
1492 static void free_file_list (struct file_list * list)
1493 {
1494         struct file_list *tmp;
1495         
1496         while (list) {
1497                 tmp = list;
1498                 DLIST_REMOVE(list, list);
1499                 SAFE_FREE(tmp->file_path);
1500                 SAFE_FREE(tmp);
1501         }
1502 }
1503
1504 /****************************************************************************
1505  Seek in a directory/file list until you get something that doesn't start with
1506  the specified name.
1507 ****************************************************************************/
1508
1509 static BOOL seek_list(struct file_list *list, char *name)
1510 {
1511         while (list) {
1512                 trim_string(list->file_path,"./","\n");
1513                 if (strncmp(list->file_path, name, strlen(name)) != 0) {
1514                         return(True);
1515                 }
1516                 list = list->next;
1517         }
1518       
1519         return(False);
1520 }
1521
1522 /****************************************************************************
1523  Set the file selection mask.
1524 ****************************************************************************/
1525
1526 static int cmd_select(void)
1527 {
1528         pstrcpy(fileselection,"");
1529         next_token_nr(NULL,fileselection,NULL,sizeof(fileselection));
1530
1531         return 0;
1532 }
1533
1534 /****************************************************************************
1535   Recursive file matching function act as find
1536   match must be always set to True when calling this function
1537 ****************************************************************************/
1538
1539 static int file_find(struct file_list **list, const char *directory, 
1540                       const char *expression, BOOL match)
1541 {
1542         DIR *dir;
1543         struct file_list *entry;
1544         struct stat statbuf;
1545         int ret;
1546         char *path;
1547         BOOL isdir;
1548         const char *dname;
1549
1550         dir = opendir(directory);
1551         if (!dir)
1552                 return -1;
1553         
1554         while ((dname = readdirname(dir))) {
1555                 if (!strcmp("..", dname))
1556                         continue;
1557                 if (!strcmp(".", dname))
1558                         continue;
1559                 
1560                 if (asprintf(&path, "%s/%s", directory, dname) <= 0) {
1561                         continue;
1562                 }
1563
1564                 isdir = False;
1565                 if (!match || !gen_fnmatch(expression, dname)) {
1566                         if (recurse) {
1567                                 ret = stat(path, &statbuf);
1568                                 if (ret == 0) {
1569                                         if (S_ISDIR(statbuf.st_mode)) {
1570                                                 isdir = True;
1571                                                 ret = file_find(list, path, expression, False);
1572                                         }
1573                                 } else {
1574                                         d_printf("file_find: cannot stat file %s\n", path);
1575                                 }
1576                                 
1577                                 if (ret == -1) {
1578                                         SAFE_FREE(path);
1579                                         closedir(dir);
1580                                         return -1;
1581                                 }
1582                         }
1583                         entry = SMB_MALLOC_P(struct file_list);
1584                         if (!entry) {
1585                                 d_printf("Out of memory in file_find\n");
1586                                 closedir(dir);
1587                                 return -1;
1588                         }
1589                         entry->file_path = path;
1590                         entry->isdir = isdir;
1591                         DLIST_ADD(*list, entry);
1592                 } else {
1593                         SAFE_FREE(path);
1594                 }
1595         }
1596
1597         closedir(dir);
1598         return 0;
1599 }
1600
1601 /****************************************************************************
1602  mput some files.
1603 ****************************************************************************/
1604
1605 static int cmd_mput(void)
1606 {
1607         pstring buf;
1608         char *p=buf;
1609         
1610         while (next_token_nr(NULL,p,NULL,sizeof(buf))) {
1611                 int ret;
1612                 struct file_list *temp_list;
1613                 char *quest, *lname, *rname;
1614         
1615                 file_list = NULL;
1616
1617                 ret = file_find(&file_list, ".", p, True);
1618                 if (ret) {
1619                         free_file_list(file_list);
1620                         continue;
1621                 }
1622                 
1623                 quest = NULL;
1624                 lname = NULL;
1625                 rname = NULL;
1626                                 
1627                 for (temp_list = file_list; temp_list; 
1628                      temp_list = temp_list->next) {
1629
1630                         SAFE_FREE(lname);
1631                         if (asprintf(&lname, "%s/", temp_list->file_path) <= 0)
1632                                 continue;
1633                         trim_string(lname, "./", "/");
1634                         
1635                         /* check if it's a directory */
1636                         if (temp_list->isdir) {
1637                                 /* if (!recurse) continue; */
1638                                 
1639                                 SAFE_FREE(quest);
1640                                 if (asprintf(&quest, "Put directory %s? ", lname) < 0) break;
1641                                 if (prompt && !yesno(quest)) { /* No */
1642                                         /* Skip the directory */
1643                                         lname[strlen(lname)-1] = '/';
1644                                         if (!seek_list(temp_list, lname))
1645                                                 break;              
1646                                 } else { /* Yes */
1647                                         SAFE_FREE(rname);
1648                                         if(asprintf(&rname, "%s%s", cur_dir, lname) < 0) break;
1649                                         dos_format(rname);
1650                                         if (!cli_chkpath(cli, rname) && 
1651                                             !do_mkdir(rname)) {
1652                                                 DEBUG (0, ("Unable to make dir, skipping..."));
1653                                                 /* Skip the directory */
1654                                                 lname[strlen(lname)-1] = '/';
1655                                                 if (!seek_list(temp_list, lname))
1656                                                         break;
1657                                         }
1658                                 }
1659                                 continue;
1660                         } else {
1661                                 SAFE_FREE(quest);
1662                                 if (asprintf(&quest,"Put file %s? ", lname) < 0) break;
1663                                 if (prompt && !yesno(quest)) /* No */
1664                                         continue;
1665                                 
1666                                 /* Yes */
1667                                 SAFE_FREE(rname);
1668                                 if (asprintf(&rname, "%s%s", cur_dir, lname) < 0) break;
1669                         }
1670
1671                         dos_format(rname);
1672
1673                         do_put(rname, lname, False);
1674                 }
1675                 free_file_list(file_list);
1676                 SAFE_FREE(quest);
1677                 SAFE_FREE(lname);
1678                 SAFE_FREE(rname);
1679         }
1680
1681         return 0;
1682 }
1683
1684 /****************************************************************************
1685  Cancel a print job.
1686 ****************************************************************************/
1687
1688 static int do_cancel(int job)
1689 {
1690         if (cli_printjob_del(cli, job)) {
1691                 d_printf("Job %d cancelled\n",job);
1692                 return 0;
1693         } else {
1694                 d_printf("Error cancelling job %d : %s\n",job,cli_errstr(cli));
1695                 return 1;
1696         }
1697 }
1698
1699 /****************************************************************************
1700  Cancel a print job.
1701 ****************************************************************************/
1702
1703 static int cmd_cancel(void)
1704 {
1705         pstring buf;
1706         int job; 
1707
1708         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1709                 d_printf("cancel <jobid> ...\n");
1710                 return 1;
1711         }
1712         do {
1713                 job = atoi(buf);
1714                 do_cancel(job);
1715         } while (next_token_nr(NULL,buf,NULL,sizeof(buf)));
1716         
1717         return 0;
1718 }
1719
1720 /****************************************************************************
1721  Print a file.
1722 ****************************************************************************/
1723
1724 static int cmd_print(void)
1725 {
1726         pstring lname;
1727         pstring rname;
1728         char *p;
1729
1730         if (!next_token_nr(NULL,lname,NULL, sizeof(lname))) {
1731                 d_printf("print <filename>\n");
1732                 return 1;
1733         }
1734
1735         pstrcpy(rname,lname);
1736         p = strrchr_m(rname,'/');
1737         if (p) {
1738                 slprintf(rname, sizeof(rname)-1, "%s-%d", p+1, (int)sys_getpid());
1739         }
1740
1741         if (strequal(lname,"-")) {
1742                 slprintf(rname, sizeof(rname)-1, "stdin-%d", (int)sys_getpid());
1743         }
1744
1745         return do_put(rname, lname, False);
1746 }
1747
1748 /****************************************************************************
1749  Show a print queue entry.
1750 ****************************************************************************/
1751
1752 static void queue_fn(struct print_job_info *p)
1753 {
1754         d_printf("%-6d   %-9d    %s\n", (int)p->id, (int)p->size, p->name);
1755 }
1756
1757 /****************************************************************************
1758  Show a print queue.
1759 ****************************************************************************/
1760
1761 static int cmd_queue(void)
1762 {
1763         cli_print_queue(cli, queue_fn);
1764         
1765         return 0;
1766 }
1767
1768 /****************************************************************************
1769  Delete some files.
1770 ****************************************************************************/
1771
1772 static void do_del(file_info *finfo)
1773 {
1774         pstring mask;
1775
1776         pstrcpy(mask,cur_dir);
1777         pstrcat(mask,finfo->name);
1778
1779         if (finfo->mode & aDIR) 
1780                 return;
1781
1782         if (!cli_unlink(cli, mask)) {
1783                 d_printf("%s deleting remote file %s\n",cli_errstr(cli),mask);
1784         }
1785 }
1786
1787 /****************************************************************************
1788  Delete some files.
1789 ****************************************************************************/
1790
1791 static int cmd_del(void)
1792 {
1793         pstring mask;
1794         pstring buf;
1795         uint16 attribute = aSYSTEM | aHIDDEN;
1796
1797         if (recurse)
1798                 attribute |= aDIR;
1799         
1800         pstrcpy(mask,cur_dir);
1801         
1802         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1803                 d_printf("del <filename>\n");
1804                 return 1;
1805         }
1806         pstrcat(mask,buf);
1807
1808         do_list(mask, attribute,do_del,False,False);
1809         
1810         return 0;
1811 }
1812
1813 /****************************************************************************
1814 ****************************************************************************/
1815
1816 static int cmd_open(void)
1817 {
1818         pstring mask;
1819         pstring buf;
1820         
1821         pstrcpy(mask,cur_dir);
1822         
1823         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1824                 d_printf("open <filename>\n");
1825                 return 1;
1826         }
1827         pstrcat(mask,buf);
1828
1829         cli_nt_create(cli, mask, FILE_READ_DATA);
1830
1831         return 0;
1832 }
1833
1834
1835 /****************************************************************************
1836  Remove a directory.
1837 ****************************************************************************/
1838
1839 static int cmd_rmdir(void)
1840 {
1841         pstring mask;
1842         pstring buf;
1843   
1844         pstrcpy(mask,cur_dir);
1845         
1846         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1847                 d_printf("rmdir <dirname>\n");
1848                 return 1;
1849         }
1850         pstrcat(mask,buf);
1851
1852         if (!cli_rmdir(cli, mask)) {
1853                 d_printf("%s removing remote directory file %s\n",
1854                          cli_errstr(cli),mask);
1855         }
1856         
1857         return 0;
1858 }
1859
1860 /****************************************************************************
1861  UNIX hardlink.
1862 ****************************************************************************/
1863
1864 static int cmd_link(void)
1865 {
1866         pstring oldname,newname;
1867         pstring buf,buf2;
1868   
1869         if (!SERVER_HAS_UNIX_CIFS(cli)) {
1870                 d_printf("Server doesn't support UNIX CIFS calls.\n");
1871                 return 1;
1872         }
1873
1874         pstrcpy(oldname,cur_dir);
1875         pstrcpy(newname,cur_dir);
1876   
1877         if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) || 
1878             !next_token_nr(NULL,buf2,NULL, sizeof(buf2))) {
1879                 d_printf("link <oldname> <newname>\n");
1880                 return 1;
1881         }
1882
1883         pstrcat(oldname,buf);
1884         pstrcat(newname,buf2);
1885
1886         if (!cli_unix_hardlink(cli, oldname, newname)) {
1887                 d_printf("%s linking files (%s -> %s)\n", cli_errstr(cli), newname, oldname);
1888                 return 1;
1889         }  
1890
1891         return 0;
1892 }
1893
1894 /****************************************************************************
1895  UNIX symlink.
1896 ****************************************************************************/
1897
1898 static int cmd_symlink(void)
1899 {
1900         pstring oldname,newname;
1901         pstring buf,buf2;
1902   
1903         if (!SERVER_HAS_UNIX_CIFS(cli)) {
1904                 d_printf("Server doesn't support UNIX CIFS calls.\n");
1905                 return 1;
1906         }
1907
1908         pstrcpy(newname,cur_dir);
1909         
1910         if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) || 
1911             !next_token_nr(NULL,buf2,NULL, sizeof(buf2))) {
1912                 d_printf("symlink <oldname> <newname>\n");
1913                 return 1;
1914         }
1915
1916         pstrcpy(oldname,buf);
1917         pstrcat(newname,buf2);
1918
1919         if (!cli_unix_symlink(cli, oldname, newname)) {
1920                 d_printf("%s symlinking files (%s -> %s)\n",
1921                         cli_errstr(cli), newname, oldname);
1922                 return 1;
1923         } 
1924
1925         return 0;
1926 }
1927
1928 /****************************************************************************
1929  UNIX chmod.
1930 ****************************************************************************/
1931
1932 static int cmd_chmod(void)
1933 {
1934         pstring src;
1935         mode_t mode;
1936         pstring buf, buf2;
1937   
1938         if (!SERVER_HAS_UNIX_CIFS(cli)) {
1939                 d_printf("Server doesn't support UNIX CIFS calls.\n");
1940                 return 1;
1941         }
1942
1943         pstrcpy(src,cur_dir);
1944         
1945         if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) || 
1946             !next_token_nr(NULL,buf2,NULL, sizeof(buf2))) {
1947                 d_printf("chmod mode file\n");
1948                 return 1;
1949         }
1950
1951         mode = (mode_t)strtol(buf, NULL, 8);
1952         pstrcat(src,buf2);
1953
1954         if (!cli_unix_chmod(cli, src, mode)) {
1955                 d_printf("%s chmod file %s 0%o\n",
1956                         cli_errstr(cli), src, (unsigned int)mode);
1957                 return 1;
1958         } 
1959
1960         return 0;
1961 }
1962
1963 static const char *filetype_to_str(mode_t mode)
1964 {
1965         if (S_ISREG(mode)) {
1966                 return "regular file";
1967         } else if (S_ISDIR(mode)) {
1968                 return "directory";
1969         } else 
1970 #ifdef S_ISCHR
1971         if (S_ISCHR(mode)) {
1972                 return "character device";
1973         } else
1974 #endif
1975 #ifdef S_ISBLK
1976         if (S_ISBLK(mode)) {
1977                 return "block device";
1978         } else
1979 #endif
1980 #ifdef S_ISFIFO
1981         if (S_ISFIFO(mode)) {
1982                 return "fifo";
1983         } else
1984 #endif
1985 #ifdef S_ISLNK
1986         if (S_ISLNK(mode)) {
1987                 return "symbolic link";
1988         } else
1989 #endif
1990 #ifdef S_ISSOCK
1991         if (S_ISSOCK(mode)) {
1992                 return "socket";
1993         } else
1994 #endif
1995         return "";
1996 }
1997
1998 static char rwx_to_str(mode_t m, mode_t bt, char ret)
1999 {
2000         if (m & bt) {
2001                 return ret;
2002         } else {
2003                 return '-';
2004         }
2005 }
2006
2007 static char *unix_mode_to_str(char *s, mode_t m)
2008 {
2009         char *p = s;
2010         const char *str = filetype_to_str(m);
2011
2012         switch(str[0]) {
2013                 case 'd':
2014                         *p++ = 'd';
2015                         break;
2016                 case 'c':
2017                         *p++ = 'c';
2018                         break;
2019                 case 'b':
2020                         *p++ = 'b';
2021                         break;
2022                 case 'f':
2023                         *p++ = 'p';
2024                         break;
2025                 case 's':
2026                         *p++ = str[1] == 'y' ? 'l' : 's';
2027                         break;
2028                 case 'r':
2029                 default:
2030                         *p++ = '-';
2031                         break;
2032         }
2033         *p++ = rwx_to_str(m, S_IRUSR, 'r');
2034         *p++ = rwx_to_str(m, S_IWUSR, 'w');
2035         *p++ = rwx_to_str(m, S_IXUSR, 'x');
2036         *p++ = rwx_to_str(m, S_IRGRP, 'r');
2037         *p++ = rwx_to_str(m, S_IWGRP, 'w');
2038         *p++ = rwx_to_str(m, S_IXGRP, 'x');
2039         *p++ = rwx_to_str(m, S_IROTH, 'r');
2040         *p++ = rwx_to_str(m, S_IWOTH, 'w');
2041         *p++ = rwx_to_str(m, S_IXOTH, 'x');
2042         *p++ = '\0';
2043         return s;
2044 }
2045
2046 /****************************************************************************
2047  Utility function for UNIX getfacl.
2048 ****************************************************************************/
2049
2050 static char *perms_to_string(fstring permstr, unsigned char perms)
2051 {
2052         fstrcpy(permstr, "---");
2053         if (perms & SMB_POSIX_ACL_READ) {
2054                 permstr[0] = 'r';
2055         }
2056         if (perms & SMB_POSIX_ACL_WRITE) {
2057                 permstr[1] = 'w';
2058         }
2059         if (perms & SMB_POSIX_ACL_EXECUTE) {
2060                 permstr[2] = 'x';
2061         }
2062         return permstr;
2063 }
2064
2065 /****************************************************************************
2066  UNIX getfacl.
2067 ****************************************************************************/
2068
2069 static int cmd_getfacl(void)
2070 {
2071         pstring src, name;
2072         uint16 major, minor;
2073         uint32 caplow, caphigh;
2074         char *retbuf = NULL;
2075         size_t rb_size = 0;
2076         SMB_STRUCT_STAT sbuf;
2077         uint16 num_file_acls = 0;
2078         uint16 num_dir_acls = 0;
2079         uint16 i;
2080  
2081         if (!SERVER_HAS_UNIX_CIFS(cli)) {
2082                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2083                 return 1;
2084         }
2085
2086         if (!cli_unix_extensions_version(cli, &major, &minor, &caplow, &caphigh)) {
2087                 d_printf("Can't get UNIX CIFS version from server.\n");
2088                 return 1;
2089         }
2090
2091         if (!(caplow & CIFS_UNIX_POSIX_ACLS_CAP)) {
2092                 d_printf("This server supports UNIX extensions but doesn't support POSIX ACLs.\n");
2093                 return 1;
2094         }
2095
2096         pstrcpy(src,cur_dir);
2097         
2098         if (!next_token_nr(NULL,name,NULL,sizeof(name))) {
2099                 d_printf("stat file\n");
2100                 return 1;
2101         }
2102
2103         pstrcat(src,name);
2104
2105         if (!cli_unix_stat(cli, src, &sbuf)) {
2106                 d_printf("%s getfacl doing a stat on file %s\n",
2107                         cli_errstr(cli), src);
2108                 return 1;
2109         } 
2110
2111         if (!cli_unix_getfacl(cli, src, &rb_size, &retbuf)) {
2112                 d_printf("%s getfacl file %s\n",
2113                         cli_errstr(cli), src);
2114                 return 1;
2115         } 
2116
2117         /* ToDo : Print out the ACL values. */
2118         if (SVAL(retbuf,0) != SMB_POSIX_ACL_VERSION || rb_size < 6) {
2119                 d_printf("getfacl file %s, unknown POSIX acl version %u.\n",
2120                         src, (unsigned int)CVAL(retbuf,0) );
2121                 SAFE_FREE(retbuf);
2122                 return 1;
2123         }
2124
2125         num_file_acls = SVAL(retbuf,2);
2126         num_dir_acls = SVAL(retbuf,4);
2127         if (rb_size != SMB_POSIX_ACL_HEADER_SIZE + SMB_POSIX_ACL_ENTRY_SIZE*(num_file_acls+num_dir_acls)) {
2128                 d_printf("getfacl file %s, incorrect POSIX acl buffer size (should be %u, was %u).\n",
2129                         src,
2130                         (unsigned int)(SMB_POSIX_ACL_HEADER_SIZE + SMB_POSIX_ACL_ENTRY_SIZE*(num_file_acls+num_dir_acls)),
2131                         (unsigned int)rb_size);
2132
2133                 SAFE_FREE(retbuf);
2134                 return 1;
2135         }
2136
2137         d_printf("# file: %s\n", src);
2138         d_printf("# owner: %u\n# group: %u\n", (unsigned int)sbuf.st_uid, (unsigned int)sbuf.st_gid);
2139
2140         if (num_file_acls == 0 && num_dir_acls == 0) {
2141                 d_printf("No acls found.\n");
2142         }
2143
2144         for (i = 0; i < num_file_acls; i++) {
2145                 uint32 uorg;
2146                 fstring permstring;
2147                 unsigned char tagtype = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE));
2148                 unsigned char perms = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+1);
2149
2150                 switch(tagtype) {
2151                         case SMB_POSIX_ACL_USER_OBJ:
2152                                 d_printf("user::");
2153                                 break;
2154                         case SMB_POSIX_ACL_USER:
2155                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
2156                                 d_printf("user:%u:", uorg);
2157                                 break;
2158                         case SMB_POSIX_ACL_GROUP_OBJ:
2159                                 d_printf("group::");
2160                                 break;
2161                         case SMB_POSIX_ACL_GROUP:
2162                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
2163                                 d_printf("group:%u", uorg);
2164                                 break;
2165                         case SMB_POSIX_ACL_MASK:
2166                                 d_printf("mask::");
2167                                 break;
2168                         case SMB_POSIX_ACL_OTHER:
2169                                 d_printf("other::");
2170                                 break;
2171                         default:
2172                                 d_printf("getfacl file %s, incorrect POSIX acl tagtype (%u).\n",
2173                                         src, (unsigned int)tagtype );
2174                                 SAFE_FREE(retbuf);
2175                                 return 1;
2176                 }
2177
2178                 d_printf("%s\n", perms_to_string(permstring, perms));
2179         }
2180
2181         for (i = 0; i < num_dir_acls; i++) {
2182                 uint32 uorg;
2183                 fstring permstring;
2184                 unsigned char tagtype = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE));
2185                 unsigned char perms = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+1);
2186
2187                 switch(tagtype) {
2188                         case SMB_POSIX_ACL_USER_OBJ:
2189                                 d_printf("default:user::");
2190                                 break;
2191                         case SMB_POSIX_ACL_USER:
2192                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+2);
2193                                 d_printf("default:user:%u:", uorg);
2194                                 break;
2195                         case SMB_POSIX_ACL_GROUP_OBJ:
2196                                 d_printf("default:group::");
2197                                 break;
2198                         case SMB_POSIX_ACL_GROUP:
2199                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+2);
2200                                 d_printf("default:group:%u", uorg);
2201                                 break;
2202                         case SMB_POSIX_ACL_MASK:
2203                                 d_printf("default:mask::");
2204                                 break;
2205                         case SMB_POSIX_ACL_OTHER:
2206                                 d_printf("default:other::");
2207                                 break;
2208                         default:
2209                                 d_printf("getfacl file %s, incorrect POSIX acl tagtype (%u).\n",
2210                                         src, (unsigned int)tagtype );
2211                                 SAFE_FREE(retbuf);
2212                                 return 1;
2213                 }
2214
2215                 d_printf("%s\n", perms_to_string(permstring, perms));
2216         }
2217
2218         SAFE_FREE(retbuf);
2219         return 0;
2220 }
2221
2222 /****************************************************************************
2223  UNIX stat.
2224 ****************************************************************************/
2225
2226 static int cmd_stat(void)
2227 {
2228         pstring src, name;
2229         fstring mode_str;
2230         SMB_STRUCT_STAT sbuf;
2231  
2232         if (!SERVER_HAS_UNIX_CIFS(cli)) {
2233                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2234                 return 1;
2235         }
2236
2237         pstrcpy(src,cur_dir);
2238         
2239         if (!next_token_nr(NULL,name,NULL,sizeof(name))) {
2240                 d_printf("stat file\n");
2241                 return 1;
2242         }
2243
2244         pstrcat(src,name);
2245
2246         if (!cli_unix_stat(cli, src, &sbuf)) {
2247                 d_printf("%s stat file %s\n",
2248                         cli_errstr(cli), src);
2249                 return 1;
2250         } 
2251
2252         /* Print out the stat values. */
2253         d_printf("File: %s\n", src);
2254         d_printf("Size: %-12.0f\tBlocks: %u\t%s\n",
2255                 (double)sbuf.st_size,
2256                 (unsigned int)sbuf.st_blocks,
2257                 filetype_to_str(sbuf.st_mode));
2258
2259 #if defined(S_ISCHR) && defined(S_ISBLK)
2260         if (S_ISCHR(sbuf.st_mode) || S_ISBLK(sbuf.st_mode)) {
2261                 d_printf("Inode: %.0f\tLinks: %u\tDevice type: %u,%u\n",
2262                         (double)sbuf.st_ino,
2263                         (unsigned int)sbuf.st_nlink,
2264                         unix_dev_major(sbuf.st_rdev),
2265                         unix_dev_minor(sbuf.st_rdev));
2266         } else 
2267 #endif
2268                 d_printf("Inode: %.0f\tLinks: %u\n",
2269                         (double)sbuf.st_ino,
2270                         (unsigned int)sbuf.st_nlink);
2271
2272         d_printf("Access: (0%03o/%s)\tUid: %u\tGid: %u\n",
2273                 ((int)sbuf.st_mode & 0777),
2274                 unix_mode_to_str(mode_str, sbuf.st_mode),
2275                 (unsigned int)sbuf.st_uid, 
2276                 (unsigned int)sbuf.st_gid);
2277
2278         strftime(mode_str, sizeof(mode_str), "%F %T %z", localtime(&sbuf.st_atime));
2279         d_printf("Access: %s\n", mode_str);
2280
2281         strftime(mode_str, sizeof(mode_str), "%F %T %z", localtime(&sbuf.st_mtime));
2282         d_printf("Modify: %s\n", mode_str);
2283
2284         strftime(mode_str, sizeof(mode_str), "%F %T %z", localtime(&sbuf.st_ctime));
2285         d_printf("Change: %s\n", mode_str);
2286         
2287         return 0;
2288 }
2289
2290
2291 /****************************************************************************
2292  UNIX chown.
2293 ****************************************************************************/
2294
2295 static int cmd_chown(void)
2296 {
2297         pstring src;
2298         uid_t uid;
2299         gid_t gid;
2300         pstring buf, buf2, buf3;
2301   
2302         if (!SERVER_HAS_UNIX_CIFS(cli)) {
2303                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2304                 return 1;
2305         }
2306
2307         pstrcpy(src,cur_dir);
2308         
2309         if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) || 
2310             !next_token_nr(NULL,buf2,NULL, sizeof(buf2)) ||
2311             !next_token_nr(NULL,buf3,NULL, sizeof(buf3))) {
2312                 d_printf("chown uid gid file\n");
2313                 return 1;
2314         }
2315
2316         uid = (uid_t)atoi(buf);
2317         gid = (gid_t)atoi(buf2);
2318         pstrcat(src,buf3);
2319
2320         if (!cli_unix_chown(cli, src, uid, gid)) {
2321                 d_printf("%s chown file %s uid=%d, gid=%d\n",
2322                         cli_errstr(cli), src, (int)uid, (int)gid);
2323                 return 1;
2324         } 
2325
2326         return 0;
2327 }
2328
2329 /****************************************************************************
2330  Rename some file.
2331 ****************************************************************************/
2332
2333 static int cmd_rename(void)
2334 {
2335         pstring src,dest;
2336         pstring buf,buf2;
2337   
2338         pstrcpy(src,cur_dir);
2339         pstrcpy(dest,cur_dir);
2340         
2341         if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) || 
2342             !next_token_nr(NULL,buf2,NULL, sizeof(buf2))) {
2343                 d_printf("rename <src> <dest>\n");
2344                 return 1;
2345         }
2346
2347         pstrcat(src,buf);
2348         pstrcat(dest,buf2);
2349
2350         if (!cli_rename(cli, src, dest)) {
2351                 d_printf("%s renaming files\n",cli_errstr(cli));
2352                 return 1;
2353         }
2354         
2355         return 0;
2356 }
2357
2358 /****************************************************************************
2359  Hard link files using the NT call.
2360 ****************************************************************************/
2361
2362 static int cmd_hardlink(void)
2363 {
2364         pstring src,dest;
2365         pstring buf,buf2;
2366   
2367         pstrcpy(src,cur_dir);
2368         pstrcpy(dest,cur_dir);
2369         
2370         if (!next_token_nr(NULL,buf,NULL,sizeof(buf)) || 
2371             !next_token_nr(NULL,buf2,NULL, sizeof(buf2))) {
2372                 d_printf("hardlink <src> <dest>\n");
2373                 return 1;
2374         }
2375
2376         pstrcat(src,buf);
2377         pstrcat(dest,buf2);
2378
2379         if (!cli_nt_hardlink(cli, src, dest)) {
2380                 d_printf("%s doing an NT hard link of files\n",cli_errstr(cli));
2381                 return 1;
2382         }
2383         
2384         return 0;
2385 }
2386
2387 /****************************************************************************
2388  Toggle the prompt flag.
2389 ****************************************************************************/
2390
2391 static int cmd_prompt(void)
2392 {
2393         prompt = !prompt;
2394         DEBUG(2,("prompting is now %s\n",prompt?"on":"off"));
2395         
2396         return 1;
2397 }
2398
2399 /****************************************************************************
2400  Set the newer than time.
2401 ****************************************************************************/
2402
2403 static int cmd_newer(void)
2404 {
2405         pstring buf;
2406         BOOL ok;
2407         SMB_STRUCT_STAT sbuf;
2408
2409         ok = next_token_nr(NULL,buf,NULL,sizeof(buf));
2410         if (ok && (sys_stat(buf,&sbuf) == 0)) {
2411                 newer_than = sbuf.st_mtime;
2412                 DEBUG(1,("Getting files newer than %s",
2413                          asctime(LocalTime(&newer_than))));
2414         } else {
2415                 newer_than = 0;
2416         }
2417
2418         if (ok && newer_than == 0) {
2419                 d_printf("Error setting newer-than time\n");
2420                 return 1;
2421         }
2422
2423         return 0;
2424 }
2425
2426 /****************************************************************************
2427  Set the archive level.
2428 ****************************************************************************/
2429
2430 static int cmd_archive(void)
2431 {
2432         pstring buf;
2433
2434         if (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
2435                 archive_level = atoi(buf);
2436         } else
2437                 d_printf("Archive level is %d\n",archive_level);
2438
2439         return 0;
2440 }
2441
2442 /****************************************************************************
2443  Toggle the lowercaseflag.
2444 ****************************************************************************/
2445
2446 static int cmd_lowercase(void)
2447 {
2448         lowercase = !lowercase;
2449         DEBUG(2,("filename lowercasing is now %s\n",lowercase?"on":"off"));
2450
2451         return 0;
2452 }
2453
2454 /****************************************************************************
2455  Toggle the case sensitive flag.
2456 ****************************************************************************/
2457
2458 static int cmd_setcase(void)
2459 {
2460         BOOL orig_case_sensitive = cli_set_case_sensitive(cli, False);
2461
2462         cli_set_case_sensitive(cli, !orig_case_sensitive);
2463         DEBUG(2,("filename case sensitivity is now %s\n",!orig_case_sensitive ?
2464                 "on":"off"));
2465
2466         return 0;
2467 }
2468
2469 /****************************************************************************
2470  Toggle the recurse flag.
2471 ****************************************************************************/
2472
2473 static int cmd_recurse(void)
2474 {
2475         recurse = !recurse;
2476         DEBUG(2,("directory recursion is now %s\n",recurse?"on":"off"));
2477
2478         return 0;
2479 }
2480
2481 /****************************************************************************
2482  Toggle the translate flag.
2483 ****************************************************************************/
2484
2485 static int cmd_translate(void)
2486 {
2487         translation = !translation;
2488         DEBUG(2,("CR/LF<->LF and print text translation now %s\n",
2489                  translation?"on":"off"));
2490
2491         return 0;
2492 }
2493
2494 /****************************************************************************
2495  Do a printmode command.
2496 ****************************************************************************/
2497
2498 static int cmd_printmode(void)
2499 {
2500         fstring buf;
2501         fstring mode;
2502
2503         if (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
2504                 if (strequal(buf,"text")) {
2505                         printmode = 0;      
2506                 } else {
2507                         if (strequal(buf,"graphics"))
2508                                 printmode = 1;
2509                         else
2510                                 printmode = atoi(buf);
2511                 }
2512         }
2513
2514         switch(printmode) {
2515                 case 0: 
2516                         fstrcpy(mode,"text");
2517                         break;
2518                 case 1: 
2519                         fstrcpy(mode,"graphics");
2520                         break;
2521                 default: 
2522                         slprintf(mode,sizeof(mode)-1,"%d",printmode);
2523                         break;
2524         }
2525         
2526         DEBUG(2,("the printmode is now %s\n",mode));
2527
2528         return 0;
2529 }
2530
2531 /****************************************************************************
2532  Do the lcd command.
2533  ****************************************************************************/
2534
2535 static int cmd_lcd(void)
2536 {
2537         pstring buf;
2538         pstring d;
2539         
2540         if (next_token_nr(NULL,buf,NULL,sizeof(buf)))
2541                 chdir(buf);
2542         DEBUG(2,("the local directory is now %s\n",sys_getwd(d)));
2543
2544         return 0;
2545 }
2546
2547 /****************************************************************************
2548  Get a file restarting at end of local file.
2549  ****************************************************************************/
2550
2551 static int cmd_reget(void)
2552 {
2553         pstring local_name;
2554         pstring remote_name;
2555         char *p;
2556
2557         pstrcpy(remote_name, cur_dir);
2558         pstrcat(remote_name, "\\");
2559         
2560         p = remote_name + strlen(remote_name);
2561         
2562         if (!next_token_nr(NULL, p, NULL, sizeof(remote_name) - strlen(remote_name))) {
2563                 d_printf("reget <filename>\n");
2564                 return 1;
2565         }
2566         pstrcpy(local_name, p);
2567         dos_clean_name(remote_name);
2568         
2569         next_token_nr(NULL, local_name, NULL, sizeof(local_name));
2570         
2571         return do_get(remote_name, local_name, True);
2572 }
2573
2574 /****************************************************************************
2575  Put a file restarting at end of local file.
2576  ****************************************************************************/
2577
2578 static int cmd_reput(void)
2579 {
2580         pstring local_name;
2581         pstring remote_name;
2582         pstring buf;
2583         char *p = buf;
2584         SMB_STRUCT_STAT st;
2585         
2586         pstrcpy(remote_name, cur_dir);
2587         pstrcat(remote_name, "\\");
2588   
2589         if (!next_token_nr(NULL, p, NULL, sizeof(buf))) {
2590                 d_printf("reput <filename>\n");
2591                 return 1;
2592         }
2593         pstrcpy(local_name, p);
2594   
2595         if (!file_exist(local_name, &st)) {
2596                 d_printf("%s does not exist\n", local_name);
2597                 return 1;
2598         }
2599
2600         if (next_token_nr(NULL, p, NULL, sizeof(buf)))
2601                 pstrcat(remote_name, p);
2602         else
2603                 pstrcat(remote_name, local_name);
2604         
2605         dos_clean_name(remote_name);
2606
2607         return do_put(remote_name, local_name, True);
2608 }
2609
2610 /****************************************************************************
2611  List a share name.
2612  ****************************************************************************/
2613
2614 static void browse_fn(const char *name, uint32 m, 
2615                       const char *comment, void *state)
2616 {
2617         fstring typestr;
2618
2619         *typestr=0;
2620
2621         switch (m)
2622         {
2623           case STYPE_DISKTREE:
2624             fstrcpy(typestr,"Disk"); break;
2625           case STYPE_PRINTQ:
2626             fstrcpy(typestr,"Printer"); break;
2627           case STYPE_DEVICE:
2628             fstrcpy(typestr,"Device"); break;
2629           case STYPE_IPC:
2630             fstrcpy(typestr,"IPC"); break;
2631         }
2632         /* FIXME: If the remote machine returns non-ascii characters
2633            in any of these fields, they can corrupt the output.  We
2634            should remove them. */
2635         if (!grepable) {
2636                 d_printf("\t%-15s %-10.10s%s\n",
2637                         name,typestr,comment);
2638         } else {
2639                 d_printf ("%s|%s|%s\n",typestr,name,comment);
2640         }
2641 }
2642
2643 /****************************************************************************
2644  Try and browse available connections on a host.
2645 ****************************************************************************/
2646
2647 static BOOL browse_host(BOOL sort)
2648 {
2649         int ret;
2650         if (!grepable) {
2651                 d_printf("\n\tSharename       Type      Comment\n");
2652                 d_printf("\t---------       ----      -------\n");
2653         }
2654
2655         if((ret = cli_RNetShareEnum(cli, browse_fn, NULL)) == -1)
2656                 d_printf("Error returning browse list: %s\n", cli_errstr(cli));
2657
2658         return (ret != -1);
2659 }
2660
2661 /****************************************************************************
2662  List a server name.
2663 ****************************************************************************/
2664
2665 static void server_fn(const char *name, uint32 m, 
2666                       const char *comment, void *state)
2667 {
2668         
2669         if (!grepable){
2670                 d_printf("\t%-16s     %s\n", name, comment);
2671         } else {
2672                 d_printf("%s|%s|%s\n",(char *)state, name, comment);
2673         }
2674 }
2675
2676 /****************************************************************************
2677  Try and browse available connections on a host.
2678 ****************************************************************************/
2679
2680 static BOOL list_servers(const char *wk_grp)
2681 {
2682         fstring state;
2683
2684         if (!cli->server_domain)
2685                 return False;
2686
2687         if (!grepable) {
2688                 d_printf("\n\tServer               Comment\n");
2689                 d_printf("\t---------            -------\n");
2690         };
2691         fstrcpy( state, "Server" );
2692         cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_ALL, server_fn,
2693                           state);
2694
2695         if (!grepable) {
2696                 d_printf("\n\tWorkgroup            Master\n");
2697                 d_printf("\t---------            -------\n");
2698         }; 
2699
2700         fstrcpy( state, "Workgroup" );
2701         cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_DOMAIN_ENUM,
2702                           server_fn, state);
2703         return True;
2704 }
2705
2706 /****************************************************************************
2707  Print or set current VUID
2708 ****************************************************************************/
2709
2710 static int cmd_vuid(void)
2711 {
2712         fstring buf;
2713         
2714         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
2715                 d_printf("Current VUID is %d\n", cli->vuid);
2716                 return 0;
2717         }
2718
2719         cli->vuid = atoi(buf);
2720         return 0;
2721 }
2722
2723 /****************************************************************************
2724  Setup a new VUID, by issuing a session setup
2725 ****************************************************************************/
2726
2727 static int cmd_logon(void)
2728 {
2729         pstring l_username, l_password;
2730         pstring buf,buf2;
2731   
2732         if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
2733                 d_printf("logon <username> [<password>]\n");
2734                 return 0;
2735         }
2736
2737         pstrcpy(l_username, buf);
2738
2739         if (!next_token_nr(NULL,buf2,NULL,sizeof(buf))) {
2740                 char *pass = getpass("Password: ");
2741                 if (pass) {
2742                         pstrcpy(l_password, pass);
2743                         got_pass = 1;
2744                 }
2745         } else {
2746                 pstrcpy(l_password, buf2);
2747         }
2748
2749         if (!cli_session_setup(cli, l_username, 
2750                                l_password, strlen(l_password),
2751                                l_password, strlen(l_password),
2752                                lp_workgroup())) {
2753                 d_printf("session setup failed: %s\n", cli_errstr(cli));
2754                 return -1;
2755         }
2756
2757         d_printf("Current VUID is %d\n", cli->vuid);
2758         return 0;
2759 }
2760
2761
2762 /****************************************************************************
2763  list active connections
2764 ****************************************************************************/
2765
2766 static int cmd_list_connect(void)
2767 {
2768         struct client_connection *p;
2769         int i;
2770
2771         for ( p=connections,i=0; p; p=p->next,i++ ) {
2772                 d_printf("%d:\tserver=%s, share=%s\n", 
2773                         i, p->cli->desthost, p->cli->share );
2774         }
2775
2776         return 0;
2777 }
2778
2779 /****************************************************************************
2780  display the current active client connection
2781 ****************************************************************************/
2782
2783 static int cmd_show_connect( void )
2784 {
2785         struct cli_state *targetcli;
2786         pstring targetpath;
2787         
2788         if ( !cli_resolve_path( cli, cur_dir, &targetcli, targetpath ) ) {
2789                 d_printf("showconnect %s: %s\n", cur_dir, cli_errstr(cli));
2790                 return 1;
2791         }
2792         
2793         d_printf("//%s/%s\n", targetcli->desthost, targetcli->share);
2794         return 0;
2795 }
2796
2797 /* Some constants for completing filename arguments */
2798
2799 #define COMPL_NONE        0          /* No completions */
2800 #define COMPL_REMOTE      1          /* Complete remote filename */
2801 #define COMPL_LOCAL       2          /* Complete local filename */
2802
2803 /* This defines the commands supported by this client.
2804  * NOTE: The "!" must be the last one in the list because it's fn pointer
2805  *       field is NULL, and NULL in that field is used in process_tok()
2806  *       (below) to indicate the end of the list.  crh
2807  */
2808 static struct
2809 {
2810   const char *name;
2811   int (*fn)(void);
2812   const char *description;
2813   char compl_args[2];      /* Completion argument info */
2814 } commands[] = {
2815   {"?",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
2816   {"altname",cmd_altname,"<file> show alt name",{COMPL_NONE,COMPL_NONE}},
2817   {"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}},
2818   {"blocksize",cmd_block,"blocksize <number> (default 20)",{COMPL_NONE,COMPL_NONE}},
2819   {"cancel",cmd_cancel,"<jobid> cancel a print queue entry",{COMPL_NONE,COMPL_NONE}},
2820   {"case_sensitive",cmd_setcase,"toggle the case sensitive flag to server",{COMPL_NONE,COMPL_NONE}},
2821   {"cd",cmd_cd,"[directory] change/report the remote directory",{COMPL_REMOTE,COMPL_NONE}},
2822   {"chmod",cmd_chmod,"<src> <mode> chmod a file using UNIX permission",{COMPL_REMOTE,COMPL_REMOTE}},
2823   {"chown",cmd_chown,"<src> <uid> <gid> chown a file using UNIX uids and gids",{COMPL_REMOTE,COMPL_REMOTE}},
2824   {"del",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
2825   {"dir",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
2826   {"du",cmd_du,"<mask> computes the total size of the current directory",{COMPL_REMOTE,COMPL_NONE}},
2827   {"exit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
2828   {"get",cmd_get,"<remote name> [local name] get a file",{COMPL_REMOTE,COMPL_LOCAL}},
2829   {"getfacl",cmd_getfacl,"<file name> get the POSIX ACL on a file (UNIX extensions only)",{COMPL_REMOTE,COMPL_LOCAL}},
2830   {"hardlink",cmd_hardlink,"<src> <dest> create a Windows hard link",{COMPL_REMOTE,COMPL_REMOTE}},
2831   {"help",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
2832   {"history",cmd_history,"displays the command history",{COMPL_NONE,COMPL_NONE}},
2833   {"lcd",cmd_lcd,"[directory] change/report the local current working directory",{COMPL_LOCAL,COMPL_NONE}},
2834   {"link",cmd_link,"<oldname> <newname> create a UNIX hard link",{COMPL_REMOTE,COMPL_REMOTE}},
2835   {"lowercase",cmd_lowercase,"toggle lowercasing of filenames for get",{COMPL_NONE,COMPL_NONE}},  
2836   {"ls",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
2837   {"mask",cmd_select,"<mask> mask all filenames against this",{COMPL_REMOTE,COMPL_NONE}},
2838   {"md",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
2839   {"mget",cmd_mget,"<mask> get all the matching files",{COMPL_REMOTE,COMPL_NONE}},
2840   {"mkdir",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
2841   {"more",cmd_more,"<remote name> view a remote file with your pager",{COMPL_REMOTE,COMPL_NONE}},  
2842   {"mput",cmd_mput,"<mask> put all matching files",{COMPL_REMOTE,COMPL_NONE}},
2843   {"newer",cmd_newer,"<file> only mget files newer than the specified local file",{COMPL_LOCAL,COMPL_NONE}},
2844   {"open",cmd_open,"<mask> open a file",{COMPL_REMOTE,COMPL_NONE}},
2845   {"print",cmd_print,"<file name> print a file",{COMPL_NONE,COMPL_NONE}},
2846   {"printmode",cmd_printmode,"<graphics or text> set the print mode",{COMPL_NONE,COMPL_NONE}},
2847   {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput",{COMPL_NONE,COMPL_NONE}},  
2848   {"put",cmd_put,"<local name> [remote name] put a file",{COMPL_LOCAL,COMPL_REMOTE}},
2849   {"pwd",cmd_pwd,"show current remote directory (same as 'cd' with no args)",{COMPL_NONE,COMPL_NONE}},
2850   {"q",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
2851   {"queue",cmd_queue,"show the print queue",{COMPL_NONE,COMPL_NONE}},
2852   {"quit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
2853   {"rd",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
2854   {"recurse",cmd_recurse,"toggle directory recursion for mget and mput",{COMPL_NONE,COMPL_NONE}},  
2855   {"reget",cmd_reget,"<remote name> [local name] get a file restarting at end of local file",{COMPL_REMOTE,COMPL_LOCAL}},
2856   {"rename",cmd_rename,"<src> <dest> rename some files",{COMPL_REMOTE,COMPL_REMOTE}},
2857   {"reput",cmd_reput,"<local name> [remote name] put a file restarting at end of remote file",{COMPL_LOCAL,COMPL_REMOTE}},
2858   {"rm",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
2859   {"rmdir",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
2860   {"setmode",cmd_setmode,"filename <setmode string> change modes of file",{COMPL_REMOTE,COMPL_NONE}},
2861   {"stat",cmd_stat,"filename Do a UNIX extensions stat call on a file",{COMPL_REMOTE,COMPL_REMOTE}},
2862   {"symlink",cmd_symlink,"<oldname> <newname> create a UNIX symlink",{COMPL_REMOTE,COMPL_REMOTE}},
2863   {"tar",cmd_tar,"tar <c|x>[IXFqbgNan] current directory to/from <file name>",{COMPL_NONE,COMPL_NONE}},
2864   {"tarmode",cmd_tarmode,"<full|inc|reset|noreset> tar's behaviour towards archive bits",{COMPL_NONE,COMPL_NONE}},
2865   {"translate",cmd_translate,"toggle text translation for printing",{COMPL_NONE,COMPL_NONE}},
2866   {"vuid",cmd_vuid,"change current vuid",{COMPL_NONE,COMPL_NONE}},
2867   {"logon",cmd_logon,"establish new logon",{COMPL_NONE,COMPL_NONE}},
2868   {"listconnect",cmd_list_connect,"list open connections",{COMPL_NONE,COMPL_NONE}},
2869   {"showconnect",cmd_show_connect,"display the current active connection",{COMPL_NONE,COMPL_NONE}},
2870   
2871   /* Yes, this must be here, see crh's comment above. */
2872   {"!",NULL,"run a shell command on the local system",{COMPL_NONE,COMPL_NONE}},
2873   {NULL,NULL,NULL,{COMPL_NONE,COMPL_NONE}}
2874 };
2875
2876 /*******************************************************************
2877  Lookup a command string in the list of commands, including 
2878  abbreviations.
2879 ******************************************************************/
2880
2881 static int process_tok(pstring tok)
2882 {
2883         int i = 0, matches = 0;
2884         int cmd=0;
2885         int tok_len = strlen(tok);
2886         
2887         while (commands[i].fn != NULL) {
2888                 if (strequal(commands[i].name,tok)) {
2889                         matches = 1;
2890                         cmd = i;
2891                         break;
2892                 } else if (strnequal(commands[i].name, tok, tok_len)) {
2893                         matches++;
2894                         cmd = i;
2895                 }
2896                 i++;
2897         }
2898   
2899         if (matches == 0)
2900                 return(-1);
2901         else if (matches == 1)
2902                 return(cmd);
2903         else
2904                 return(-2);
2905 }
2906
2907 /****************************************************************************
2908  Help.
2909 ****************************************************************************/
2910
2911 static int cmd_help(void)
2912 {
2913         int i=0,j;
2914         pstring buf;
2915         
2916         if (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
2917                 if ((i = process_tok(buf)) >= 0)
2918                         d_printf("HELP %s:\n\t%s\n\n",commands[i].name,commands[i].description);
2919         } else {
2920                 while (commands[i].description) {
2921                         for (j=0; commands[i].description && (j<5); j++) {
2922                                 d_printf("%-15s",commands[i].name);
2923                                 i++;
2924                         }
2925                         d_printf("\n");
2926                 }
2927         }
2928         return 0;
2929 }
2930
2931 /****************************************************************************
2932  Process a -c command string.
2933 ****************************************************************************/
2934
2935 static int process_command_string(char *cmd)
2936 {
2937         pstring line;
2938         const char *ptr;
2939         int rc = 0;
2940
2941         /* establish the connection if not already */
2942         
2943         if (!cli) {
2944                 cli = cli_cm_connect(desthost, service, True);
2945                 if (!cli)
2946                         return 0;
2947         }
2948         
2949         while (cmd[0] != '\0')    {
2950                 char *p;
2951                 pstring tok;
2952                 int i;
2953                 
2954                 if ((p = strchr_m(cmd, ';')) == 0) {
2955                         strncpy(line, cmd, 999);
2956                         line[1000] = '\0';
2957                         cmd += strlen(cmd);
2958                 } else {
2959                         if (p - cmd > 999)
2960                                 p = cmd + 999;
2961                         strncpy(line, cmd, p - cmd);
2962                         line[p - cmd] = '\0';
2963                         cmd = p + 1;
2964                 }
2965                 
2966                 /* and get the first part of the command */
2967                 ptr = line;
2968                 if (!next_token_nr(&ptr,tok,NULL,sizeof(tok))) continue;
2969                 
2970                 if ((i = process_tok(tok)) >= 0) {
2971                         rc = commands[i].fn();
2972                 } else if (i == -2) {
2973                         d_printf("%s: command abbreviation ambiguous\n",tok);
2974                 } else {
2975                         d_printf("%s: command not found\n",tok);
2976                 }
2977         }
2978         
2979         return rc;
2980 }       
2981
2982 #define MAX_COMPLETIONS 100
2983
2984 typedef struct {
2985         pstring dirmask;
2986         char **matches;
2987         int count, samelen;
2988         const char *text;
2989         int len;
2990 } completion_remote_t;
2991
2992 static void completion_remote_filter(file_info *f, const char *mask, void *state)
2993 {
2994         completion_remote_t *info = (completion_remote_t *)state;
2995
2996         if ((info->count < MAX_COMPLETIONS - 1) && (strncmp(info->text, f->name, info->len) == 0) && (strcmp(f->name, ".") != 0) && (strcmp(f->name, "..") != 0)) {
2997                 if ((info->dirmask[0] == 0) && !(f->mode & aDIR))
2998                         info->matches[info->count] = SMB_STRDUP(f->name);
2999                 else {
3000                         pstring tmp;
3001
3002                         if (info->dirmask[0] != 0)
3003                                 pstrcpy(tmp, info->dirmask);
3004                         else
3005                                 tmp[0] = 0;
3006                         pstrcat(tmp, f->name);
3007                         if (f->mode & aDIR)
3008                                 pstrcat(tmp, "/");
3009                         info->matches[info->count] = SMB_STRDUP(tmp);
3010                 }
3011                 if (info->matches[info->count] == NULL)
3012                         return;
3013                 if (f->mode & aDIR)
3014                         smb_readline_ca_char(0);
3015
3016                 if (info->count == 1)
3017                         info->samelen = strlen(info->matches[info->count]);
3018                 else
3019                         while (strncmp(info->matches[info->count], info->matches[info->count-1], info->samelen) != 0)
3020                                 info->samelen--;
3021                 info->count++;
3022         }
3023 }
3024
3025 static char **remote_completion(const char *text, int len)
3026 {
3027         pstring dirmask;
3028         int i;
3029         completion_remote_t info = { "", NULL, 1, 0, NULL, 0 };
3030
3031         /* can't have non-static intialisation on Sun CC, so do it
3032            at run time here */
3033         info.samelen = len;
3034         info.text = text;
3035         info.len = len;
3036                 
3037         if (len >= PATH_MAX)
3038                 return(NULL);
3039
3040         info.matches = SMB_MALLOC_ARRAY(char *,MAX_COMPLETIONS);
3041         if (!info.matches) return NULL;
3042         info.matches[0] = NULL;
3043
3044         for (i = len-1; i >= 0; i--)
3045                 if ((text[i] == '/') || (text[i] == '\\'))
3046                         break;
3047         info.text = text+i+1;
3048         info.samelen = info.len = len-i-1;
3049
3050         if (i > 0) {
3051                 strncpy(info.dirmask, text, i+1);
3052                 info.dirmask[i+1] = 0;
3053                 pstr_sprintf(dirmask, "%s%*s*", cur_dir, i-1, text);
3054         } else
3055                 pstr_sprintf(dirmask, "%s*", cur_dir);
3056
3057         if (cli_list(cli, dirmask, aDIR | aSYSTEM | aHIDDEN, completion_remote_filter, &info) < 0)
3058                 goto cleanup;
3059
3060         if (info.count == 2)
3061                 info.matches[0] = SMB_STRDUP(info.matches[1]);
3062         else {
3063                 info.matches[0] = SMB_MALLOC(info.samelen+1);
3064                 if (!info.matches[0])
3065                         goto cleanup;
3066                 strncpy(info.matches[0], info.matches[1], info.samelen);
3067                 info.matches[0][info.samelen] = 0;
3068         }
3069         info.matches[info.count] = NULL;
3070         return info.matches;
3071
3072 cleanup:
3073         for (i = 0; i < info.count; i++)
3074                 free(info.matches[i]);
3075         free(info.matches);
3076         return NULL;
3077 }
3078
3079 static char **completion_fn(const char *text, int start, int end)
3080 {
3081         smb_readline_ca_char(' ');
3082
3083         if (start) {
3084                 const char *buf, *sp;
3085                 int i;
3086                 char compl_type;
3087
3088                 buf = smb_readline_get_line_buffer();
3089                 if (buf == NULL)
3090                         return NULL;
3091                 
3092                 sp = strchr(buf, ' ');
3093                 if (sp == NULL)
3094                         return NULL;
3095                 
3096                 for (i = 0; commands[i].name; i++)
3097                         if ((strncmp(commands[i].name, text, sp - buf) == 0) && (commands[i].name[sp - buf] == 0))
3098                                 break;
3099                 if (commands[i].name == NULL)
3100                         return NULL;
3101
3102                 while (*sp == ' ')
3103                         sp++;
3104
3105                 if (sp == (buf + start))
3106                         compl_type = commands[i].compl_args[0];
3107                 else
3108                         compl_type = commands[i].compl_args[1];
3109
3110                 if (compl_type == COMPL_REMOTE)
3111                         return remote_completion(text, end - start);
3112                 else /* fall back to local filename completion */
3113                         return NULL;
3114         } else {
3115                 char **matches;
3116                 int i, len, samelen = 0, count=1;
3117
3118                 matches = SMB_MALLOC_ARRAY(char *, MAX_COMPLETIONS);
3119                 if (!matches) {
3120                         return NULL;
3121                 }
3122                 matches[0] = NULL;
3123
3124                 len = strlen(text);
3125                 for (i=0;commands[i].fn && count < MAX_COMPLETIONS-1;i++) {
3126                         if (strncmp(text, commands[i].name, len) == 0) {
3127                                 matches[count] = SMB_STRDUP(commands[i].name);
3128                                 if (!matches[count])
3129                                         goto cleanup;
3130                                 if (count == 1)
3131                                         samelen = strlen(matches[count]);
3132                                 else
3133                                         while (strncmp(matches[count], matches[count-1], samelen) != 0)
3134                                                 samelen--;
3135                                 count++;
3136                         }
3137                 }
3138
3139                 switch (count) {
3140                 case 0: /* should never happen */
3141                 case 1:
3142                         goto cleanup;
3143                 case 2:
3144                         matches[0] = SMB_STRDUP(matches[1]);
3145                         break;
3146                 default:
3147                         matches[0] = SMB_MALLOC(samelen+1);
3148                         if (!matches[0])
3149                                 goto cleanup;
3150                         strncpy(matches[0], matches[1], samelen);
3151                         matches[0][samelen] = 0;
3152                 }
3153                 matches[count] = NULL;
3154                 return matches;
3155
3156 cleanup:
3157                 for (i = 0; i < count; i++)
3158                         free(matches[i]);
3159
3160                 free(matches);
3161                 return NULL;
3162         }
3163 }
3164
3165 /****************************************************************************
3166  Make sure we swallow keepalives during idle time.
3167 ****************************************************************************/
3168
3169 static void readline_callback(void)
3170 {
3171         fd_set fds;
3172         struct timeval timeout;
3173         static time_t last_t;
3174         time_t t;
3175
3176         t = time(NULL);
3177
3178         if (t - last_t < 5)
3179                 return;
3180
3181         last_t = t;
3182
3183  again:
3184
3185         if (cli->fd == -1)
3186                 return;
3187
3188         FD_ZERO(&fds);
3189         FD_SET(cli->fd,&fds);
3190
3191         timeout.tv_sec = 0;
3192         timeout.tv_usec = 0;
3193         sys_select_intr(cli->fd+1,&fds,NULL,NULL,&timeout);
3194                 
3195         /* We deliberately use receive_smb instead of
3196            client_receive_smb as we want to receive
3197            session keepalives and then drop them here.
3198         */
3199         if (FD_ISSET(cli->fd,&fds)) {
3200                 receive_smb(cli->fd,cli->inbuf,0);
3201                 goto again;
3202         }
3203       
3204         cli_chkpath(cli, "\\");
3205 }
3206
3207 /****************************************************************************
3208  Process commands on stdin.
3209 ****************************************************************************/
3210
3211 static int process_stdin(void)
3212 {
3213         const char *ptr;
3214         int rc = 0;
3215
3216         while (1) {
3217                 pstring tok;
3218                 pstring the_prompt;
3219                 char *cline;
3220                 pstring line;
3221                 int i;
3222                 
3223                 /* display a prompt */
3224                 slprintf(the_prompt, sizeof(the_prompt)-1, "smb: %s> ", cur_dir);
3225                 cline = smb_readline(the_prompt, readline_callback, completion_fn);
3226                         
3227                 if (!cline) break;
3228                 
3229                 pstrcpy(line, cline);
3230
3231                 /* special case - first char is ! */
3232                 if (*line == '!') {
3233                         system(line + 1);
3234                         continue;
3235                 }
3236       
3237                 /* and get the first part of the command */
3238                 ptr = line;
3239                 if (!next_token_nr(&ptr,tok,NULL,sizeof(tok))) continue;
3240
3241                 if ((i = process_tok(tok)) >= 0) {
3242                         rc = commands[i].fn();
3243                 } else if (i == -2) {
3244                         d_printf("%s: command abbreviation ambiguous\n",tok);
3245                 } else {
3246                         d_printf("%s: command not found\n",tok);
3247                 }
3248         }
3249         return rc;
3250 }
3251
3252 /****************************************************************************
3253  Process commands from the client.
3254 ****************************************************************************/
3255
3256 static int process(char *base_directory)
3257 {
3258         int rc = 0;
3259
3260         cli = cli_cm_connect(desthost, service, True);
3261         if (!cli) {
3262                 return 1;
3263         }
3264
3265         if (*base_directory) do_cd(base_directory);
3266         
3267         if (cmdstr) {
3268                 rc = process_command_string(cmdstr);
3269         } else {
3270                 process_stdin();
3271         }
3272   
3273         cli_shutdown(cli);
3274         return rc;
3275 }
3276
3277 /****************************************************************************
3278  Handle a -L query.
3279 ****************************************************************************/
3280
3281 static int do_host_query(char *query_host)
3282 {
3283         cli = cli_cm_connect(query_host, "IPC$", True);
3284         if (!cli)
3285                 return 1;
3286
3287         browse_host(True);
3288
3289         if (port != 139) {
3290
3291                 /* Workgroups simply don't make sense over anything
3292                    else but port 139... */
3293
3294                 cli_shutdown(cli);
3295                 port = 139;
3296                 cli = cli_cm_connect(query_host, "IPC$", True);
3297         }
3298
3299         if (cli == NULL) {
3300                 d_printf("NetBIOS over TCP disabled -- no workgroup available\n");
3301                 return 1;
3302         }
3303
3304         list_servers(lp_workgroup());
3305
3306         cli_shutdown(cli);
3307         
3308         return(0);
3309 }
3310
3311 /****************************************************************************
3312  Handle a tar operation.
3313 ****************************************************************************/
3314
3315 static int do_tar_op(char *base_directory)
3316 {
3317         int ret;
3318
3319         /* do we already have a connection? */
3320         if (!cli) {
3321                 cli = cli_cm_connect(desthost, service, True);
3322                 if (!cli)
3323                         return 1;
3324         }
3325
3326         recurse=True;
3327
3328         if (*base_directory) do_cd(base_directory);
3329         
3330         ret=process_tar();
3331
3332         cli_shutdown(cli);
3333
3334         return(ret);
3335 }
3336
3337 /****************************************************************************
3338  Handle a message operation.
3339 ****************************************************************************/
3340
3341 static int do_message_op(void)
3342 {
3343         struct in_addr ip;
3344         struct nmb_name called, calling;
3345         fstring server_name;
3346         char name_type_hex[10];
3347
3348         make_nmb_name(&calling, global_myname(), 0x0);
3349         make_nmb_name(&called , desthost, name_type);
3350
3351         fstrcpy(server_name, desthost);
3352         snprintf(name_type_hex, sizeof(name_type_hex), "#%X", name_type);
3353         fstrcat(server_name, name_type_hex);
3354
3355         zero_ip(&ip);
3356         if (have_ip) ip = dest_ip;
3357
3358         if (!(cli=cli_initialise(NULL)) || (cli_set_port(cli, port) != port) ||
3359             !cli_connect(cli, server_name, &ip)) {
3360                 d_printf("Connection to %s failed\n", desthost);
3361                 return 1;
3362         }
3363
3364         if (!cli_session_request(cli, &calling, &called)) {
3365                 d_printf("session request failed\n");
3366                 cli_shutdown(cli);
3367                 return 1;
3368         }
3369
3370         send_message();
3371         cli_shutdown(cli);
3372
3373         return 0;
3374 }
3375
3376
3377 /****************************************************************************
3378   main program
3379 ****************************************************************************/
3380
3381  int main(int argc,char *argv[])
3382 {
3383         extern BOOL AllowDebugChange;
3384         extern BOOL override_logfile;
3385         pstring base_directory;
3386         int opt;
3387         pstring query_host;
3388         BOOL message = False;
3389         extern char tar_type;
3390         pstring term_code;
3391         static const char *new_name_resolve_order = NULL;
3392         poptContext pc;
3393         char *p;
3394         int rc = 0;
3395         fstring new_workgroup;
3396         struct poptOption long_options[] = {
3397                 POPT_AUTOHELP
3398
3399                 { "name-resolve", 'R', POPT_ARG_STRING, &new_name_resolve_order, 'R', "Use these name resolution services only", "NAME-RESOLVE-ORDER" },
3400                 { "message", 'M', POPT_ARG_STRING, NULL, 'M', "Send message", "HOST" },
3401                 { "ip-address", 'I', POPT_ARG_STRING, NULL, 'I', "Use this IP to connect to", "IP" },
3402                 { "stderr", 'E', POPT_ARG_NONE, NULL, 'E', "Write messages to stderr instead of stdout" },
3403                 { "list", 'L', POPT_ARG_STRING, NULL, 'L', "Get a list of shares available on a host", "HOST" },
3404                 { "terminal", 't', POPT_ARG_STRING, NULL, 't', "Terminal I/O code {sjis|euc|jis7|jis8|junet|hex}", "CODE" },
3405                 { "max-protocol", 'm', POPT_ARG_STRING, NULL, 'm', "Set the max protocol level", "LEVEL" },
3406                 { "tar", 'T', POPT_ARG_STRING, NULL, 'T', "Command line tar", "<c|x>IXFqgbNan" },
3407                 { "directory", 'D', POPT_ARG_STRING, NULL, 'D', "Start from directory", "DIR" },
3408                 { "command", 'c', POPT_ARG_STRING, &cmdstr, 'c', "Execute semicolon separated commands" }, 
3409                 { "send-buffer", 'b', POPT_ARG_INT, &io_bufsize, 'b', "Changes the transmit/send buffer", "BYTES" },
3410                 { "port", 'p', POPT_ARG_INT, &port, 'p', "Port to connect to", "PORT" },
3411                 { "grepable", 'g', POPT_ARG_NONE, NULL, 'g', "Produce grepable output" },
3412                 POPT_COMMON_SAMBA
3413                 POPT_COMMON_CONNECTION
3414                 POPT_COMMON_CREDENTIALS
3415                 POPT_TABLEEND
3416         };
3417         
3418
3419 #ifdef KANJI
3420         pstrcpy(term_code, KANJI);
3421 #else /* KANJI */
3422         *term_code = 0;
3423 #endif /* KANJI */
3424
3425         *query_host = 0;
3426         *base_directory = 0;
3427         
3428         /* initialize the workgroup name so we can determine whether or 
3429            not it was set by a command line option */
3430            
3431         set_global_myworkgroup( "" );
3432
3433         /* set default debug level to 0 regardless of what smb.conf sets */
3434         setup_logging( "smbclient", True );
3435         DEBUGLEVEL_CLASS[DBGC_ALL] = 1;
3436         dbf = x_stderr;
3437         x_setbuf( x_stderr, NULL );
3438
3439         pc = poptGetContext("smbclient", argc, (const char **) argv, long_options, 
3440                                 POPT_CONTEXT_KEEP_FIRST);
3441         poptSetOtherOptionHelp(pc, "service <password>");
3442
3443         in_client = True;   /* Make sure that we tell lp_load we are */
3444
3445         while ((opt = poptGetNextOpt(pc)) != -1) {
3446                 switch (opt) {
3447                 case 'M':
3448                         /* Messages are sent to NetBIOS name type 0x3
3449                          * (Messenger Service).  Make sure we default
3450                          * to port 139 instead of port 445. srl,crh
3451                          */
3452                         name_type = 0x03; 
3453                         pstrcpy(desthost,poptGetOptArg(pc));
3454                         if( 0 == port )
3455                                 port = 139;
3456                         message = True;
3457                         break;
3458                 case 'I':
3459                         {
3460                                 dest_ip = *interpret_addr2(poptGetOptArg(pc));
3461                                 if (is_zero_ip(dest_ip))
3462                                         exit(1);
3463                                 have_ip = True;
3464                         }
3465                         break;
3466                 case 'E':
3467                         dbf = x_stderr;
3468                         display_set_stderr();
3469                         break;
3470
3471                 case 'L':
3472                         pstrcpy(query_host, poptGetOptArg(pc));
3473                         break;
3474                 case 't':
3475                         pstrcpy(term_code, poptGetOptArg(pc));
3476                         break;
3477                 case 'm':
3478                         max_protocol = interpret_protocol(poptGetOptArg(pc), max_protocol);
3479                         break;
3480                 case 'T':
3481                         /* We must use old option processing for this. Find the
3482                          * position of the -T option in the raw argv[]. */
3483                         {
3484                                 int i, optnum;
3485                                 for (i = 1; i < argc; i++) {
3486                                         if (strncmp("-T", argv[i],2)==0)
3487                                                 break;
3488                                 }
3489                                 i++;
3490                                 if (!(optnum = tar_parseargs(argc, argv, poptGetOptArg(pc), i))) {
3491                                         poptPrintUsage(pc, stderr, 0);
3492                                         exit(1);
3493                                 }
3494                                 /* Now we must eat (optnum - i) options - they have
3495                                  * been processed by tar_parseargs().
3496                                  */
3497                                 optnum -= i;
3498                                 for (i = 0; i < optnum; i++)
3499                                         poptGetOptArg(pc);
3500                         }
3501                         break;
3502                 case 'D':
3503                         pstrcpy(base_directory,poptGetOptArg(pc));
3504                         break;
3505                 case 'g':
3506                         grepable=True;
3507                         break;
3508                 }
3509         }
3510
3511         poptGetArg(pc);
3512         
3513         /*
3514          * Don't load debug level from smb.conf. It should be
3515          * set by cmdline arg or remain default (0)
3516          */
3517         AllowDebugChange = False;
3518         
3519         /* save the workgroup...
3520         
3521            FIXME!! do we need to do this for other options as well 
3522            (or maybe a generic way to keep lp_load() from overwriting 
3523            everything)?  */
3524         
3525         fstrcpy( new_workgroup, lp_workgroup() );
3526         
3527         if ( override_logfile )
3528                 setup_logging( lp_logfile(), False );
3529         
3530         if (!lp_load(dyn_CONFIGFILE,True,False,False)) {
3531                 fprintf(stderr, "%s: Can't load %s - run testparm to debug it\n",
3532                         argv[0], dyn_CONFIGFILE);
3533         }
3534         
3535         load_interfaces();
3536         
3537         if ( strlen(new_workgroup) != 0 )
3538                 set_global_myworkgroup( new_workgroup );
3539
3540         if(poptPeekArg(pc)) {
3541                 pstrcpy(service,poptGetArg(pc));  
3542                 /* Convert any '/' characters in the service name to '\' characters */
3543                 string_replace(service, '/','\\');
3544
3545                 if (count_chars(service,'\\') < 3) {
3546                         d_printf("\n%s: Not enough '\\' characters in service\n",service);
3547                         poptPrintUsage(pc, stderr, 0);
3548                         exit(1);
3549                 }
3550         }
3551
3552         if (poptPeekArg(pc) && !cmdline_auth_info.got_pass) { 
3553                 cmdline_auth_info.got_pass = True;
3554                 pstrcpy(cmdline_auth_info.password,poptGetArg(pc));  
3555         }
3556
3557         init_names();
3558
3559         if(new_name_resolve_order)
3560                 lp_set_name_resolve_order(new_name_resolve_order);
3561
3562         if (!tar_type && !*query_host && !*service && !message) {
3563                 poptPrintUsage(pc, stderr, 0);
3564                 exit(1);
3565         }
3566
3567         poptFreeContext(pc);
3568
3569         pstrcpy(username, cmdline_auth_info.username);
3570         pstrcpy(password, cmdline_auth_info.password);
3571
3572         use_kerberos = cmdline_auth_info.use_kerberos;
3573         got_pass = cmdline_auth_info.got_pass;
3574
3575         DEBUG(3,("Client started (version %s).\n", SAMBA_VERSION_STRING));
3576
3577         if (tar_type) {
3578                 if (cmdstr)
3579                         process_command_string(cmdstr);
3580                 return do_tar_op(base_directory);
3581         }
3582
3583         if (*query_host) {
3584                 char *qhost = query_host;
3585                 char *slash;
3586
3587                 while (*qhost == '\\' || *qhost == '/')
3588                         qhost++;
3589
3590                 if ((slash = strchr_m(qhost, '/'))
3591                     || (slash = strchr_m(qhost, '\\'))) {
3592                         *slash = 0;
3593                 }
3594
3595                 if ((p=strchr_m(qhost, '#'))) {
3596                         *p = 0;
3597                         p++;
3598                         sscanf(p, "%x", &name_type);
3599                 }
3600   
3601                 return do_host_query(qhost);
3602         }
3603
3604         if (message) {
3605                 return do_message_op();
3606         }
3607         
3608         if (process(base_directory)) {
3609                 return 1;
3610         }
3611
3612         return rc;
3613 }