source: trunk/samba/source/client/client.c @ 30

Last change on this file since 30 was 30, checked in by Paul Smedley, 14 years ago

Code updated to Samba 3.0.25rc2 level

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