4abb812e89be91247679967e728d20966af776d3
[samba.git] / source3 / client / client.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    SMB client
5    Copyright (C) Andrew Tridgell 1994-1998
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #define NO_SYSLOG
23
24 #include "includes.h"
25
26 #ifndef REGISTER
27 #define REGISTER 0
28 #endif
29
30 struct cli_state *cli;
31 extern BOOL in_client;
32 pstring cur_dir = "\\";
33 pstring cd_path = "";
34 static pstring service;
35 static pstring desthost;
36 extern pstring global_myname;
37 extern pstring myhostname;
38 static pstring password;
39 static pstring username;
40 static pstring workgroup;
41 static char *cmdstr;
42 static BOOL got_pass;
43 extern struct in_addr ipzero;
44 extern pstring scope;
45
46 static int name_type = 0x20;
47
48 extern pstring user_socket_options;
49
50 static int process_tok(fstring tok);
51 static void cmd_help(void);
52
53 /* 30 second timeout on most commands */
54 #define CLIENT_TIMEOUT (30*1000)
55 #define SHORT_TIMEOUT (5*1000)
56
57 /* value for unused fid field in trans2 secondary request */
58 #define FID_UNUSED (0xFFFF)
59
60 time_t newer_than = 0;
61 int archive_level = 0;
62
63 extern pstring debugf;
64 extern int DEBUGLEVEL;
65
66 BOOL translation = False;
67
68 static BOOL have_ip;
69
70 /* clitar bits insert */
71 extern int blocksize;
72 extern BOOL tar_inc;
73 extern BOOL tar_reset;
74 /* clitar bits end */
75  
76
77 mode_t myumask = 0755;
78
79 BOOL prompt = True;
80
81 int printmode = 1;
82
83 static BOOL recurse = False;
84 BOOL lowercase = False;
85
86 struct in_addr dest_ip;
87
88 #define SEPARATORS " \t\n\r"
89
90 BOOL abort_mget = True;
91
92 pstring fileselection = "";
93
94 extern file_info def_finfo;
95
96 /* timing globals */
97 int get_total_size = 0;
98 int get_total_time_ms = 0;
99 int put_total_size = 0;
100 int put_total_time_ms = 0;
101
102 /* totals globals */
103 int dir_total = 0;
104
105 #define USENMB
106
107 #define CNV_LANG(s) dos_to_unix(s,False)
108 #define CNV_INPUT(s) unix_to_dos(s,True)
109
110
111 /****************************************************************************
112 write to a local file with CR/LF->LF translation if appropriate. return the 
113 number taken from the buffer. This may not equal the number written.
114 ****************************************************************************/
115 static int writefile(int f, char *b, int n)
116 {
117         int i;
118
119         if (!translation) {
120                 return write(f,b,n);
121         }
122
123         i = 0;
124         while (i < n) {
125                 if (*b == '\r' && (i<(n-1)) && *(b+1) == '\n') {
126                         b++;i++;
127                 }
128                 if (write(f, b, 1) != 1) {
129                         break;
130                 }
131                 b++;
132                 i++;
133         }
134   
135         return(i);
136 }
137
138 /****************************************************************************
139   read from a file with LF->CR/LF translation if appropriate. return the 
140   number read. read approx n bytes.
141 ****************************************************************************/
142 static int readfile(char *b, int size, int n, FILE *f)
143 {
144         int i;
145         int c;
146
147         if (!translation || (size != 1))
148                 return(fread(b,size,n,f));
149   
150         i = 0;
151         while (i < n) {
152                 if ((c = getc(f)) == EOF) {
153                         break;
154                 }
155       
156                 if (c == '\n') { /* change all LFs to CR/LF */
157                         b[i++] = '\r';
158                         n++;
159                 }
160       
161                 if(i < n)
162                         b[i++] = c;
163         }
164   
165         return(i);
166 }
167  
168
169 /****************************************************************************
170 send a message
171 ****************************************************************************/
172 static void send_message(void)
173 {
174         int total_len = 0;
175         int grp_id;
176
177         if (!cli_message_start(cli, desthost, username, &grp_id)) {
178                 DEBUG(0,("message start: %s\n", cli_errstr(cli)));
179                 return;
180         }
181
182
183         printf("Connected. Type your message, ending it with a Control-D\n");
184
185         while (!feof(stdin) && total_len < 1600) {
186                 int maxlen = MIN(1600 - total_len,127);
187                 pstring msg;
188                 int l=0;
189                 int c;
190
191                 ZERO_ARRAY(msg);
192
193                 for (l=0;l<maxlen && (c=fgetc(stdin))!=EOF;l++) {
194                         if (c == '\n')
195                                 msg[l++] = '\r';
196                         msg[l] = c;   
197                 }
198
199                 if (!cli_message_text(cli, msg, l, grp_id)) {
200                         printf("SMBsendtxt failed (%s)\n",cli_errstr(cli));
201                         return;
202                 }      
203                 
204                 total_len += l;
205         }
206
207         if (total_len >= 1600)
208                 printf("the message was truncated to 1600 bytes\n");
209         else
210                 printf("sent %d bytes\n",total_len);
211
212         if (!cli_message_end(cli, grp_id)) {
213                 printf("SMBsendend failed (%s)\n",cli_errstr(cli));
214                 return;
215         }      
216 }
217
218
219
220 /****************************************************************************
221 check the space on a device
222 ****************************************************************************/
223 static void do_dskattr(void)
224 {
225         int total, bsize, avail;
226
227         if (!cli_dskattr(cli, &bsize, &total, &avail)) {
228                 DEBUG(0,("Error in dskattr: %s\n",cli_errstr(cli))); 
229                 return;
230         }
231
232         DEBUG(0,("\n\t\t%d blocks of size %d. %d blocks available\n",
233                  total, bsize, avail));
234 }
235
236 /****************************************************************************
237 show cd/pwd
238 ****************************************************************************/
239 static void cmd_pwd(void)
240 {
241         DEBUG(0,("Current directory is %s",CNV_LANG(service)));
242         DEBUG(0,("%s\n",CNV_LANG(cur_dir)));
243 }
244
245
246 /****************************************************************************
247 change directory - inner section
248 ****************************************************************************/
249 static void do_cd(char *newdir)
250 {
251         char *p = newdir;
252         pstring saved_dir;
253         pstring dname;
254       
255         dos_format(newdir);
256
257         /* Save the current directory in case the
258            new directory is invalid */
259         pstrcpy(saved_dir, cur_dir);
260         if (*p == '\\')
261                 pstrcpy(cur_dir,p);
262         else
263                 pstrcat(cur_dir,p);
264         if (*(cur_dir+strlen(cur_dir)-1) != '\\') {
265                 pstrcat(cur_dir, "\\");
266         }
267         dos_clean_name(cur_dir);
268         pstrcpy(dname,cur_dir);
269         pstrcat(cur_dir,"\\");
270         dos_clean_name(cur_dir);
271         
272         if (!strequal(cur_dir,"\\")) {
273                 if (!cli_chkpath(cli, dname)) {
274                         DEBUG(0,("cd %s: %s\n", dname, cli_errstr(cli)));
275                         pstrcpy(cur_dir,saved_dir);
276                 }
277         }
278         
279         pstrcpy(cd_path,cur_dir);
280 }
281
282 /****************************************************************************
283 change directory
284 ****************************************************************************/
285 static void cmd_cd(void)
286 {
287         fstring buf;
288
289         if (next_token(NULL,buf,NULL,sizeof(buf)))
290                 do_cd(buf);
291         else
292                 DEBUG(0,("Current directory is %s\n",CNV_LANG(cur_dir)));
293 }
294
295
296 /*******************************************************************
297   decide if a file should be operated on
298   ********************************************************************/
299 static BOOL do_this_one(file_info *finfo)
300 {
301         if (finfo->mode & aDIR) return(True);
302
303         if (*fileselection && 
304             !mask_match(finfo->name,fileselection,False,False)) {
305                 DEBUG(3,("match_match %s failed\n", finfo->name));
306                 return False;
307         }
308
309         if (newer_than && finfo->mtime < newer_than) {
310                 DEBUG(3,("newer_than %s failed\n", finfo->name));
311                 return(False);
312         }
313
314         if ((archive_level==1 || archive_level==2) && !(finfo->mode & aARCH)) {
315                 DEBUG(3,("archive %s failed\n", finfo->name));
316                 return(False);
317         }
318         
319         return(True);
320 }
321
322 /****************************************************************************
323   display info about a file
324   ****************************************************************************/
325 static void display_finfo(file_info *finfo)
326 {
327         if (do_this_one(finfo)) {
328                 time_t t = finfo->mtime; /* the time is assumed to be passed as GMT */
329                 DEBUG(0,("  %-30s%7.7s%8.0f  %s",
330                          CNV_LANG(finfo->name),
331                          attrib_string(finfo->mode),
332                          (double)finfo->size,
333                          asctime(LocalTime(&t))));
334                 dir_total += finfo->size;
335         }
336 }
337
338
339 /****************************************************************************
340    accumulate size of a file
341   ****************************************************************************/
342 static void do_du(file_info *finfo)
343 {
344         if (do_this_one(finfo)) {
345                 dir_total += finfo->size;
346         }
347 }
348
349 static BOOL do_list_recurse;
350 static BOOL do_list_dirs;
351 static int do_list_attr;
352 static void (*do_list_fn)(file_info *);
353
354 /****************************************************************************
355 a helper for do_list
356   ****************************************************************************/
357 static void do_list_helper(file_info *f, const char *mask)
358 {
359         if (f->mode & aDIR) {
360                 if (do_list_dirs && do_this_one(f)) {
361                         do_list_fn(f);
362                 }
363                 if (do_list_recurse && 
364                     !strequal(f->name,".") && 
365                     !strequal(f->name,"..")) {
366                         pstring mask2;
367                         char *p;
368
369                         pstrcpy(mask2, mask);
370                         p = strrchr(mask2,'\\');
371                         if (!p) return;
372                         p[1] = 0;
373                         pstrcat(mask2, f->name);
374                         if (do_list_fn == display_finfo) {
375                                 DEBUG(0,("\n%s\n",CNV_LANG(mask2)));
376                         }
377                         pstrcat(mask2,"\\*");
378                         do_list(mask2, do_list_attr, do_list_fn, True, True);
379                 }
380                 return;
381         }
382
383         if (do_this_one(f)) {
384                 do_list_fn(f);
385         }
386 }
387
388
389 /****************************************************************************
390 a wrapper around cli_list that adds recursion
391   ****************************************************************************/
392 void do_list(const char *mask,uint16 attribute,void (*fn)(file_info *),BOOL rec, BOOL dirs)
393 {
394         do_list_recurse = rec;
395         do_list_dirs = dirs;
396         do_list_fn = fn;
397         do_list_attr = attribute;
398
399         cli_list(cli, mask, attribute, do_list_helper);
400 }
401
402 /****************************************************************************
403   get a directory listing
404   ****************************************************************************/
405 static void cmd_dir(void)
406 {
407         uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
408         pstring mask;
409         fstring buf;
410         char *p=buf;
411         
412         dir_total = 0;
413         pstrcpy(mask,cur_dir);
414         if(mask[strlen(mask)-1]!='\\')
415                 pstrcat(mask,"\\");
416         
417         if (next_token(NULL,buf,NULL,sizeof(buf))) {
418                 dos_format(p);
419                 if (*p == '\\')
420                         pstrcpy(mask,p);
421                 else
422                         pstrcat(mask,p);
423         }
424         else {
425                 pstrcat(mask,"*");
426         }
427
428         do_list(mask, attribute, display_finfo, recurse, True);
429
430         do_dskattr();
431
432         DEBUG(3, ("Total bytes listed: %d\n", dir_total));
433 }
434
435
436 /****************************************************************************
437   get a directory listing
438   ****************************************************************************/
439 static void cmd_du(void)
440 {
441         uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
442         pstring mask;
443         fstring buf;
444         char *p=buf;
445         
446         dir_total = 0;
447         pstrcpy(mask,cur_dir);
448         if(mask[strlen(mask)-1]!='\\')
449                 pstrcat(mask,"\\");
450         
451         if (next_token(NULL,buf,NULL,sizeof(buf))) {
452                 dos_format(p);
453                 if (*p == '\\')
454                         pstrcpy(mask,p);
455                 else
456                         pstrcat(mask,p);
457         } else {
458                 pstrcat(mask,"*");
459         }
460
461         do_list(mask, attribute, do_du, recurse, True);
462
463         do_dskattr();
464
465         DEBUG(0, ("Total number of bytes: %d\n", dir_total));
466 }
467
468
469 /****************************************************************************
470   get a file from rname to lname
471   ****************************************************************************/
472 static void do_get(char *rname,char *lname)
473 {  
474         int handle=0,fnum;
475         BOOL newhandle = False;
476         char *data;
477         struct timeval tp_start;
478         int read_size = 65520;
479         uint16 attr;
480         size_t size;
481         off_t nread = 0;
482
483         GetTimeOfDay(&tp_start);
484
485         if (lowercase) {
486                 strlower(lname);
487         }
488
489         fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
490
491         if (fnum == -1) {
492                 DEBUG(0,("%s opening remote file %s\n",cli_errstr(cli),CNV_LANG(rname)));
493                 return;
494         }
495
496         if(!strcmp(lname,"-")) {
497                 handle = fileno(stdout);
498         } else {
499                 handle = open(lname,O_WRONLY|O_CREAT|O_TRUNC,0644);
500                 newhandle = True;
501         }
502         if (handle < 0) {
503                 DEBUG(0,("Error opening local file %s\n",lname));
504                 return;
505         }
506
507
508         if (!cli_getattrE(cli, fnum, &attr, &size, NULL, NULL, NULL)) {
509                 DEBUG(0,("getattrE: %s\n",cli_errstr(cli)));
510                 return;
511         }
512
513
514         DEBUG(2,("getting file %s of size %.0f as %s ", 
515                  lname, (double)size, lname));
516
517         data = (char *)malloc(read_size);
518
519         while (1) {
520                 int n = cli_read(cli, fnum, data, nread, read_size);
521
522                 if (n <= 0) break;
523  
524                 if (writefile(handle,data, n) != n) {
525                         DEBUG(0,("Error writing local file\n"));
526                         break;
527                 }
528       
529                 nread += n;
530         }
531         
532         if (!cli_close(cli, fnum)) {
533                 DEBUG(0,("Error %s closing remote file\n",cli_errstr(cli)));
534         }
535
536         if (newhandle) {
537                 close(handle);
538         }
539
540         if (archive_level >= 2 && (attr & aARCH)) {
541                 cli_setatr(cli, rname, attr & ~(uint16)aARCH, 0);
542         }
543
544         {
545                 struct timeval tp_end;
546                 int this_time;
547                 
548                 GetTimeOfDay(&tp_end);
549                 this_time = 
550                         (tp_end.tv_sec - tp_start.tv_sec)*1000 +
551                         (tp_end.tv_usec - tp_start.tv_usec)/1000;
552                 get_total_time_ms += this_time;
553                 get_total_size += nread;
554                 
555                 DEBUG(2,("(%g kb/s) (average %g kb/s)\n",
556                          nread / (1.024*this_time + 1.0e-4),
557                          get_total_size / (1.024*get_total_time_ms)));
558         }
559 }
560
561
562 /****************************************************************************
563   get a file
564   ****************************************************************************/
565 static void cmd_get(void)
566 {
567         pstring lname;
568         pstring rname;
569         char *p;
570
571         pstrcpy(rname,cur_dir);
572         pstrcat(rname,"\\");
573         
574         p = rname + strlen(rname);
575         
576         if (!next_token(NULL,p,NULL,sizeof(rname)-strlen(rname))) {
577                 DEBUG(0,("get <filename>\n"));
578                 return;
579         }
580         pstrcpy(lname,p);
581         dos_clean_name(rname);
582         
583         next_token(NULL,lname,NULL,sizeof(lname));
584         
585         do_get(rname, lname);
586 }
587
588
589 /****************************************************************************
590   do a mget operation on one file
591   ****************************************************************************/
592 static void do_mget(file_info *finfo)
593 {
594         pstring rname;
595         pstring quest;
596         pstring saved_curdir;
597         pstring mget_mask;
598
599         if (strequal(finfo->name,".") || strequal(finfo->name,".."))
600                 return;
601
602         if (abort_mget) {
603                 DEBUG(0,("mget aborted\n"));
604                 return;
605         }
606
607         if (finfo->mode & aDIR)
608                 slprintf(quest,sizeof(pstring)-1,
609                          "Get directory %s? ",CNV_LANG(finfo->name));
610         else
611                 slprintf(quest,sizeof(pstring)-1,
612                          "Get file %s? ",CNV_LANG(finfo->name));
613
614         if (prompt && !yesno(quest)) return;
615
616         if (!(finfo->mode & aDIR)) {
617                 pstrcpy(rname,cur_dir);
618                 pstrcat(rname,finfo->name);
619                 do_get(rname,finfo->name);
620                 return;
621         }
622
623         /* handle directories */
624         pstrcpy(saved_curdir,cur_dir);
625
626         pstrcat(cur_dir,finfo->name);
627         pstrcat(cur_dir,"\\");
628
629         unix_format(finfo->name);
630         if (lowercase)
631                 strlower(finfo->name);
632         
633         if (!directory_exist(finfo->name,NULL) && 
634             dos_mkdir(finfo->name,0777) != 0) {
635                 DEBUG(0,("failed to create directory %s\n",CNV_LANG(finfo->name)));
636                 pstrcpy(cur_dir,saved_curdir);
637                 return;
638         }
639         
640         if (dos_chdir(finfo->name) != 0) {
641                 DEBUG(0,("failed to chdir to directory %s\n",CNV_LANG(finfo->name)));
642                 pstrcpy(cur_dir,saved_curdir);
643                 return;
644         }
645
646         pstrcpy(mget_mask,cur_dir);
647         pstrcat(mget_mask,"*");
648         
649         do_list(mget_mask, aSYSTEM | aHIDDEN | aDIR,do_mget,False, True);
650         chdir("..");
651         pstrcpy(cur_dir,saved_curdir);
652 }
653
654
655 /****************************************************************************
656 view the file using the pager
657 ****************************************************************************/
658 static void cmd_more(void)
659 {
660         fstring rname,lname,tmpname,pager_cmd;
661         char *pager;
662
663         fstrcpy(rname,cur_dir);
664         fstrcat(rname,"\\");
665         slprintf(tmpname,
666                  sizeof(fstring)-1,
667                  "%s/smbmore.%d",tmpdir(),(int)getpid());
668         fstrcpy(lname,tmpname);
669         
670         if (!next_token(NULL,rname+strlen(rname),NULL,sizeof(rname)-strlen(rname))) {
671                 DEBUG(0,("more <filename>\n"));
672                 return;
673         }
674         dos_clean_name(rname);
675
676         do_get(rname,lname);
677
678         pager=getenv("PAGER");
679
680         slprintf(pager_cmd,sizeof(pager_cmd)-1,
681                  "%s %s",(pager? pager:PAGER), tmpname);
682         system(pager_cmd);
683         unlink(tmpname);
684 }
685
686
687
688 /****************************************************************************
689 do a mget command
690 ****************************************************************************/
691 static void cmd_mget(void)
692 {
693         uint16 attribute = aSYSTEM | aHIDDEN;
694         pstring mget_mask;
695         fstring buf;
696         char *p=buf;
697
698         *mget_mask = 0;
699
700         if (recurse)
701                 attribute |= aDIR;
702         
703         abort_mget = False;
704
705         while (next_token(NULL,p,NULL,sizeof(buf))) {
706                 pstrcpy(mget_mask,cur_dir);
707                 if(mget_mask[strlen(mget_mask)-1]!='\\')
708                         pstrcat(mget_mask,"\\");
709                 
710                 if (*p == '\\')
711                         pstrcpy(mget_mask,p);
712                 else
713                         pstrcat(mget_mask,p);
714                 do_list(mget_mask, attribute,do_mget,False,True);
715         }
716
717         if (!*mget_mask) {
718                 pstrcpy(mget_mask,cur_dir);
719                 if(mget_mask[strlen(mget_mask)-1]!='\\')
720                         pstrcat(mget_mask,"\\");
721                 pstrcat(mget_mask,"*");
722                 do_list(mget_mask, attribute,do_mget,False,True);
723         }
724 }
725
726
727 /****************************************************************************
728 make a directory of name "name"
729 ****************************************************************************/
730 static BOOL do_mkdir(char *name)
731 {
732         if (!cli_mkdir(cli, name)) {
733                 DEBUG(0,("%s making remote directory %s\n",
734                          cli_errstr(cli),CNV_LANG(name)));
735                 return(False);
736         }
737
738         return(True);
739 }
740
741
742 /****************************************************************************
743 make a directory of name "name"
744 ****************************************************************************/
745 static void cmd_quit(void)
746 {
747         cli_shutdown(cli);
748         exit(0);
749 }
750
751
752 /****************************************************************************
753   make a directory
754   ****************************************************************************/
755 static void cmd_mkdir(void)
756 {
757         pstring mask;
758         fstring buf;
759         char *p=buf;
760   
761         pstrcpy(mask,cur_dir);
762
763         if (!next_token(NULL,p,NULL,sizeof(buf))) {
764                 if (!recurse)
765                         DEBUG(0,("mkdir <dirname>\n"));
766                 return;
767         }
768         pstrcat(mask,p);
769
770         if (recurse) {
771                 pstring ddir;
772                 pstring ddir2;
773                 *ddir2 = 0;
774                 
775                 pstrcpy(ddir,mask);
776                 trim_string(ddir,".",NULL);
777                 p = strtok(ddir,"/\\");
778                 while (p) {
779                         pstrcat(ddir2,p);
780                         if (!cli_chkpath(cli, ddir2)) { 
781                                 do_mkdir(ddir2);
782                         }
783                         pstrcat(ddir2,"\\");
784                         p = strtok(NULL,"/\\");
785                 }        
786         } else {
787                 do_mkdir(mask);
788         }
789 }
790
791
792 /****************************************************************************
793   put a single file
794   ****************************************************************************/
795 static void do_put(char *rname,char *lname)
796 {
797         int fnum;
798         FILE *f;
799         int nread=0;
800         char *buf=NULL;
801         int maxwrite=65520;
802         
803         struct timeval tp_start;
804         GetTimeOfDay(&tp_start);
805
806         fnum = cli_open(cli, rname, O_WRONLY|O_CREAT|O_TRUNC, DENY_NONE);
807   
808         if (fnum == -1) {
809                 DEBUG(0,("%s opening remote file %s\n",cli_errstr(cli),CNV_LANG(rname)));
810                 return;
811         }
812
813         /* allow files to be piped into smbclient
814            jdblair 24.jun.98 */
815         if (!strcmp(lname, "-")) {
816                 f = stdin;
817                 /* size of file is not known */
818         } else {
819                 f = fopen(lname,"r");
820         }
821
822         if (!f) {
823                 DEBUG(0,("Error opening local file %s\n",lname));
824                 return;
825         }
826
827   
828         DEBUG(1,("putting file %s as %s ",lname,
829                  CNV_LANG(rname)));
830   
831         buf = (char *)malloc(maxwrite);
832         while (!feof(f)) {
833                 int n = maxwrite;
834                 int ret;
835
836                 if ((n = readfile(buf,1,n,f)) < 1) {
837                         DEBUG(0,("Error reading local file\n"));
838                         break;
839                 }
840
841                 ret = cli_write(cli, fnum, 0, buf, nread, n);
842
843                 if (n != ret) {
844                         DEBUG(0,("Error writing file: %s\n", cli_errstr(cli)));
845                         break;
846                 } 
847
848                 nread += n;
849         }
850
851         if (!cli_close(cli, fnum)) {
852                 DEBUG(0,("%s closing remote file %s\n",cli_errstr(cli),CNV_LANG(rname)));
853                 fclose(f);
854                 if (buf) free(buf);
855                 return;
856         }
857
858         
859         fclose(f);
860         if (buf) free(buf);
861
862         {
863                 struct timeval tp_end;
864                 int this_time;
865                 
866                 GetTimeOfDay(&tp_end);
867                 this_time = 
868                         (tp_end.tv_sec - tp_start.tv_sec)*1000 +
869                         (tp_end.tv_usec - tp_start.tv_usec)/1000;
870                 put_total_time_ms += this_time;
871                 put_total_size += nread;
872                 
873                 DEBUG(1,("(%g kb/s) (average %g kb/s)\n",
874                          nread / (1.024*this_time + 1.0e-4),
875                          put_total_size / (1.024*put_total_time_ms)));
876         }
877
878         if (f == stdin) {
879                 cli_shutdown(cli);
880                 exit(0);
881         }
882 }
883
884  
885
886 /****************************************************************************
887   put a file
888   ****************************************************************************/
889 static void cmd_put(void)
890 {
891         pstring lname;
892         pstring rname;
893         fstring buf;
894         char *p=buf;
895         
896         pstrcpy(rname,cur_dir);
897         pstrcat(rname,"\\");
898   
899         if (!next_token(NULL,p,NULL,sizeof(buf))) {
900                 DEBUG(0,("put <filename>\n"));
901                 return;
902         }
903         pstrcpy(lname,p);
904   
905         if (next_token(NULL,p,NULL,sizeof(buf)))
906                 pstrcat(rname,p);      
907         else
908                 pstrcat(rname,lname);
909         
910         dos_clean_name(rname);
911
912         {
913                 SMB_STRUCT_STAT st;
914                 /* allow '-' to represent stdin
915                    jdblair, 24.jun.98 */
916                 if (!file_exist(lname,&st) &&
917                     (strcmp(lname,"-"))) {
918                         DEBUG(0,("%s does not exist\n",lname));
919                         return;
920                 }
921         }
922
923         do_put(rname,lname);
924 }
925
926
927 /****************************************************************************
928   seek in a directory/file list until you get something that doesn't start with
929   the specified name
930   ****************************************************************************/
931 static BOOL seek_list(FILE *f,char *name)
932 {
933         pstring s;
934         while (!feof(f)) {
935                 if (fscanf(f,"%s",s) != 1) return(False);
936                 trim_string(s,"./",NULL);
937                 if (strncmp(s,name,strlen(name)) != 0) {
938                         pstrcpy(name,s);
939                         return(True);
940                 }
941         }
942       
943         return(False);
944 }
945
946
947 /****************************************************************************
948   set the file selection mask
949   ****************************************************************************/
950 static void cmd_select(void)
951 {
952         pstrcpy(fileselection,"");
953         next_token(NULL,fileselection,NULL,sizeof(fileselection));
954 }
955
956
957 /****************************************************************************
958   mput some files
959   ****************************************************************************/
960 static void cmd_mput(void)
961 {
962         pstring lname;
963         pstring rname;
964         fstring buf;
965         char *p=buf;
966         
967         while (next_token(NULL,p,NULL,sizeof(buf))) {
968                 SMB_STRUCT_STAT st;
969                 pstring cmd;
970                 pstring tmpname;
971                 FILE *f;
972                 
973                 slprintf(tmpname,sizeof(pstring)-1,
974                          "%s/ls.smb.%d",tmpdir(),(int)getpid());
975                 if (recurse)
976                         slprintf(cmd,sizeof(pstring)-1,
977                                  "find . -name \"%s\" -print > %s",p,tmpname);
978                 else
979                         slprintf(cmd,sizeof(pstring)-1,
980                                  "/bin/ls %s > %s",p,tmpname);
981                 system(cmd);
982
983                 f = fopen(tmpname,"r");
984                 if (!f) continue;
985                 
986                 while (!feof(f)) {
987                         pstring quest;
988
989                         if (fscanf(f,"%s",lname) != 1) break;
990                         trim_string(lname,"./",NULL);
991                         
992                 again1:
993                         
994                         /* check if it's a directory */
995                         if (directory_exist(lname,&st)) {
996                                 if (!recurse) continue;
997                                 slprintf(quest,sizeof(pstring)-1,
998                                          "Put directory %s? ",lname);
999                                 if (prompt && !yesno(quest)) {
1000                                         pstrcat(lname,"/");
1001                                         if (!seek_list(f,lname))
1002                                                 break;
1003                                         goto again1;                
1004                                 }
1005               
1006                                 pstrcpy(rname,cur_dir);
1007                                 pstrcat(rname,lname);
1008                                 if (!cli_chkpath(cli, rname) && !do_mkdir(rname)) {
1009                                         pstrcat(lname,"/");
1010                                         if (!seek_list(f,lname))
1011                                                 break;
1012                                         goto again1;
1013                                 }
1014                                 continue;
1015                         } else {
1016                                 slprintf(quest,sizeof(quest)-1,
1017                                          "Put file %s? ",lname);
1018                                 if (prompt && !yesno(quest)) continue;
1019                                 
1020                                 pstrcpy(rname,cur_dir);
1021                                 pstrcat(rname,lname);
1022                         }
1023
1024                         dos_format(rname);
1025
1026                         do_put(rname,lname);
1027                 }
1028                 fclose(f);
1029                 unlink(tmpname);
1030         }
1031 }
1032
1033
1034 /****************************************************************************
1035   cancel a print job
1036   ****************************************************************************/
1037 static void do_cancel(int job)
1038 {
1039         if (cli_printjob_del(cli, job)) {
1040                 printf("Job %d cancelled\n",job);
1041         } else {
1042                 printf("Error calcelling job %d : %s\n",job,cli_errstr(cli));
1043         }
1044 }
1045
1046
1047 /****************************************************************************
1048   cancel a print job
1049   ****************************************************************************/
1050 static void cmd_cancel(void)
1051 {
1052         fstring buf;
1053         int job; 
1054
1055         if (!next_token(NULL,buf,NULL,sizeof(buf))) {
1056                 printf("cancel <jobid> ...\n");
1057                 return;
1058         }
1059         do {
1060                 job = atoi(buf);
1061                 do_cancel(job);
1062         } while (next_token(NULL,buf,NULL,sizeof(buf)));
1063 }
1064
1065
1066 /****************************************************************************
1067   print a file
1068   ****************************************************************************/
1069 static void cmd_print(void)
1070 {
1071         pstring lname;
1072         pstring rname;
1073         char *p;
1074
1075         if (!next_token(NULL,lname,NULL, sizeof(lname))) {
1076                 DEBUG(0,("print <filename>\n"));
1077                 return;
1078         }
1079
1080         pstrcpy(rname,lname);
1081         p = strrchr(rname,'/');
1082         if (p) {
1083                 slprintf(rname, sizeof(rname)-1, "%s-%d", p+1, (int)getpid());
1084         }
1085
1086         if (strequal(lname,"-")) {
1087                 slprintf(rname, sizeof(rname)-1, "stdin-%d", (int)getpid());
1088         }
1089
1090         do_put(rname, lname);
1091 }
1092
1093
1094 /****************************************************************************
1095  show a print queue entry
1096 ****************************************************************************/
1097 static void queue_fn(struct print_job_info *p)
1098 {
1099         DEBUG(0,("%-6d   %-9d    %s\n", (int)p->id, (int)p->size, p->name));
1100 }
1101
1102 /****************************************************************************
1103  show a print queue
1104 ****************************************************************************/
1105 static void cmd_queue(void)
1106 {
1107         cli_print_queue(cli, queue_fn);  
1108 }
1109
1110 /****************************************************************************
1111 delete some files
1112 ****************************************************************************/
1113 static void do_del(file_info *finfo)
1114 {
1115         pstring mask;
1116
1117         pstrcpy(mask,cur_dir);
1118         pstrcat(mask,finfo->name);
1119
1120         if (finfo->mode & aDIR) 
1121                 return;
1122
1123         if (!cli_unlink(cli, mask)) {
1124                 DEBUG(0,("%s deleting remote file %s\n",cli_errstr(cli),CNV_LANG(mask)));
1125         }
1126 }
1127
1128 /****************************************************************************
1129 delete some files
1130 ****************************************************************************/
1131 static void cmd_del(void)
1132 {
1133         pstring mask;
1134         fstring buf;
1135         uint16 attribute = aSYSTEM | aHIDDEN;
1136
1137         if (recurse)
1138                 attribute |= aDIR;
1139         
1140         pstrcpy(mask,cur_dir);
1141         
1142         if (!next_token(NULL,buf,NULL,sizeof(buf))) {
1143                 DEBUG(0,("del <filename>\n"));
1144                 return;
1145         }
1146         pstrcat(mask,buf);
1147
1148         do_list(mask, attribute,do_del,False,False);
1149 }
1150
1151
1152 /****************************************************************************
1153 remove a directory
1154 ****************************************************************************/
1155 static void cmd_rmdir(void)
1156 {
1157         pstring mask;
1158         fstring buf;
1159   
1160         pstrcpy(mask,cur_dir);
1161         
1162         if (!next_token(NULL,buf,NULL,sizeof(buf))) {
1163                 DEBUG(0,("rmdir <dirname>\n"));
1164                 return;
1165         }
1166         pstrcat(mask,buf);
1167
1168         if (!cli_rmdir(cli, mask)) {
1169                 DEBUG(0,("%s removing remote directory file %s\n",
1170                          cli_errstr(cli),CNV_LANG(mask)));
1171         }  
1172 }
1173
1174 /****************************************************************************
1175 rename some files
1176 ****************************************************************************/
1177 static void cmd_rename(void)
1178 {
1179         pstring src,dest;
1180         fstring buf,buf2;
1181   
1182         pstrcpy(src,cur_dir);
1183         pstrcpy(dest,cur_dir);
1184         
1185         if (!next_token(NULL,buf,NULL,sizeof(buf)) || 
1186             !next_token(NULL,buf2,NULL, sizeof(buf2))) {
1187                 DEBUG(0,("rename <src> <dest>\n"));
1188                 return;
1189         }
1190
1191         pstrcat(src,buf);
1192         pstrcat(dest,buf2);
1193
1194         if (!cli_rename(cli, src, dest)) {
1195                 DEBUG(0,("%s renaming files\n",cli_errstr(cli)));
1196                 return;
1197         }  
1198 }
1199
1200
1201 /****************************************************************************
1202 toggle the prompt flag
1203 ****************************************************************************/
1204 static void cmd_prompt(void)
1205 {
1206         prompt = !prompt;
1207         DEBUG(2,("prompting is now %s\n",prompt?"on":"off"));
1208 }
1209
1210
1211 /****************************************************************************
1212 set the newer than time
1213 ****************************************************************************/
1214 static void cmd_newer(void)
1215 {
1216         fstring buf;
1217         BOOL ok;
1218         SMB_STRUCT_STAT sbuf;
1219
1220         ok = next_token(NULL,buf,NULL,sizeof(buf));
1221         if (ok && (dos_stat(buf,&sbuf) == 0)) {
1222                 newer_than = sbuf.st_mtime;
1223                 DEBUG(1,("Getting files newer than %s",
1224                          asctime(LocalTime(&newer_than))));
1225         } else {
1226                 newer_than = 0;
1227         }
1228
1229         if (ok && newer_than == 0)
1230                 DEBUG(0,("Error setting newer-than time\n"));
1231 }
1232
1233 /****************************************************************************
1234 set the archive level
1235 ****************************************************************************/
1236 static void cmd_archive(void)
1237 {
1238         fstring buf;
1239
1240         if (next_token(NULL,buf,NULL,sizeof(buf))) {
1241                 archive_level = atoi(buf);
1242         } else
1243                 DEBUG(0,("Archive level is %d\n",archive_level));
1244 }
1245
1246 /****************************************************************************
1247 toggle the lowercaseflag
1248 ****************************************************************************/
1249 static void cmd_lowercase(void)
1250 {
1251         lowercase = !lowercase;
1252         DEBUG(2,("filename lowercasing is now %s\n",lowercase?"on":"off"));
1253 }
1254
1255
1256
1257
1258 /****************************************************************************
1259 toggle the recurse flag
1260 ****************************************************************************/
1261 static void cmd_recurse(void)
1262 {
1263         recurse = !recurse;
1264         DEBUG(2,("directory recursion is now %s\n",recurse?"on":"off"));
1265 }
1266
1267 /****************************************************************************
1268 toggle the translate flag
1269 ****************************************************************************/
1270 static void cmd_translate(void)
1271 {
1272         translation = !translation;
1273         DEBUG(2,("CR/LF<->LF and print text translation now %s\n",
1274                  translation?"on":"off"));
1275 }
1276
1277
1278 /****************************************************************************
1279 do a printmode command
1280 ****************************************************************************/
1281 static void cmd_printmode(void)
1282 {
1283         fstring buf;
1284         fstring mode;
1285
1286         if (next_token(NULL,buf,NULL,sizeof(buf))) {
1287                 if (strequal(buf,"text")) {
1288                         printmode = 0;      
1289                 } else {
1290                         if (strequal(buf,"graphics"))
1291                                 printmode = 1;
1292                         else
1293                                 printmode = atoi(buf);
1294                 }
1295         }
1296
1297         switch(printmode)
1298                 {
1299                 case 0: 
1300                         fstrcpy(mode,"text");
1301                         break;
1302                 case 1: 
1303                         fstrcpy(mode,"graphics");
1304                         break;
1305                 default: 
1306                         slprintf(mode,sizeof(mode)-1,"%d",printmode);
1307                         break;
1308                 }
1309         
1310         DEBUG(2,("the printmode is now %s\n",mode));
1311 }
1312
1313 /****************************************************************************
1314 do the lcd command
1315 ****************************************************************************/
1316 static void cmd_lcd(void)
1317 {
1318         fstring buf;
1319         pstring d;
1320         
1321         if (next_token(NULL,buf,NULL,sizeof(buf)))
1322                 dos_chdir(buf);
1323         DEBUG(2,("the local directory is now %s\n",GetWd(d)));
1324 }
1325
1326 /****************************************************************************
1327 list a share name
1328 ****************************************************************************/
1329 static void browse_fn(const char *name, uint32 m, const char *comment)
1330 {
1331         fstring typestr;
1332         *typestr=0;
1333
1334         switch (m)
1335         {
1336           case STYPE_DISKTREE:
1337             fstrcpy(typestr,"Disk"); break;
1338           case STYPE_PRINTQ:
1339             fstrcpy(typestr,"Printer"); break;
1340           case STYPE_DEVICE:
1341             fstrcpy(typestr,"Device"); break;
1342           case STYPE_IPC:
1343             fstrcpy(typestr,"IPC"); break;
1344         }
1345
1346         printf("\t%-15.15s%-10.10s%s\n",
1347                name, typestr,comment);
1348 }
1349
1350
1351 /****************************************************************************
1352 try and browse available connections on a host
1353 ****************************************************************************/
1354 static BOOL browse_host(BOOL sort)
1355 {
1356         printf("\n\tSharename      Type      Comment\n");
1357         printf("\t---------      ----      -------\n");
1358
1359         return cli_RNetShareEnum(cli, browse_fn);
1360 }
1361
1362 /****************************************************************************
1363 list a server name
1364 ****************************************************************************/
1365 static void server_fn(const char *name, uint32 m, const char *comment)
1366 {
1367         printf("\t%-16.16s     %s\n", name, comment);
1368 }
1369
1370 /****************************************************************************
1371 try and browse available connections on a host
1372 ****************************************************************************/
1373 static BOOL list_servers(char *wk_grp)
1374 {
1375         printf("\n\tServer               Comment\n");
1376         printf("\t---------            -------\n");
1377
1378         cli_NetServerEnum(cli, workgroup, SV_TYPE_ALL, server_fn);
1379
1380         printf("\n\tWorkgroup            Master\n");
1381         printf("\t---------            -------\n");
1382
1383         cli_NetServerEnum(cli, workgroup, SV_TYPE_DOMAIN_ENUM, server_fn);
1384         return True;
1385 }
1386
1387
1388 /* Some constants for completing filename arguments */
1389
1390 #define COMPL_NONE        0          /* No completions */
1391 #define COMPL_REMOTE      1          /* Complete remote filename */
1392 #define COMPL_LOCAL       2          /* Complete local filename */
1393
1394 /* This defines the commands supported by this client */
1395 struct
1396 {
1397   char *name;
1398   void (*fn)(void);
1399   char *description;
1400   char compl_args[2];      /* Completion argument info */
1401 } commands[] = 
1402 {
1403   {"ls",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
1404   {"dir",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
1405   {"du",cmd_du,"<mask> computes the total size of the current directory",{COMPL_REMOTE,COMPL_NONE}},
1406   {"lcd",cmd_lcd,"[directory] change/report the local current working directory",{COMPL_LOCAL,COMPL_NONE}},
1407   {"cd",cmd_cd,"[directory] change/report the remote directory",{COMPL_REMOTE,COMPL_NONE}},
1408   {"pwd",cmd_pwd,"show current remote directory (same as 'cd' with no args)",{COMPL_NONE,COMPL_NONE}},
1409   {"get",cmd_get,"<remote name> [local name] get a file",{COMPL_REMOTE,COMPL_LOCAL}},
1410   {"mget",cmd_mget,"<mask> get all the matching files",{COMPL_REMOTE,COMPL_NONE}},
1411   {"put",cmd_put,"<local name> [remote name] put a file",{COMPL_LOCAL,COMPL_REMOTE}},
1412   {"mput",cmd_mput,"<mask> put all matching files",{COMPL_REMOTE,COMPL_NONE}},
1413   {"rename",cmd_rename,"<src> <dest> rename some files",{COMPL_REMOTE,COMPL_REMOTE}},
1414   {"more",cmd_more,"<remote name> view a remote file with your pager",{COMPL_REMOTE,COMPL_NONE}},  
1415   {"mask",cmd_select,"<mask> mask all filenames against this",{COMPL_REMOTE,COMPL_NONE}},
1416   {"del",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
1417   {"rm",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
1418   {"mkdir",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
1419   {"md",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
1420   {"rmdir",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
1421   {"rd",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
1422   {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput",{COMPL_NONE,COMPL_NONE}},  
1423   {"recurse",cmd_recurse,"toggle directory recursion for mget and mput",{COMPL_NONE,COMPL_NONE}},  
1424   {"translate",cmd_translate,"toggle text translation for printing",{COMPL_NONE,COMPL_NONE}},  
1425   {"lowercase",cmd_lowercase,"toggle lowercasing of filenames for get",{COMPL_NONE,COMPL_NONE}},  
1426   {"print",cmd_print,"<file name> print a file",{COMPL_NONE,COMPL_NONE}},
1427   {"printmode",cmd_printmode,"<graphics or text> set the print mode",{COMPL_NONE,COMPL_NONE}},
1428   {"queue",cmd_queue,"show the print queue",{COMPL_NONE,COMPL_NONE}},
1429   {"cancel",cmd_cancel,"<jobid> cancel a print queue entry",{COMPL_NONE,COMPL_NONE}},
1430   {"quit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
1431   {"q",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
1432   {"exit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
1433   {"newer",cmd_newer,"<file> only mget files newer than the specified local file",{COMPL_LOCAL,COMPL_NONE}},
1434   {"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}},
1435   {"tar",cmd_tar,"tar <c|x>[IXFqbgNan] current directory to/from <file name>",{COMPL_NONE,COMPL_NONE}},
1436   {"blocksize",cmd_block,"blocksize <number> (default 20)",{COMPL_NONE,COMPL_NONE}},
1437   {"tarmode",cmd_tarmode,
1438      "<full|inc|reset|noreset> tar's behaviour towards archive bits",{COMPL_NONE,COMPL_NONE}},
1439   {"setmode",cmd_setmode,"filename <setmode string> change modes of file",{COMPL_REMOTE,COMPL_NONE}},
1440   {"help",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
1441   {"?",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
1442   {"!",NULL,"run a shell command on the local system",{COMPL_NONE,COMPL_NONE}},
1443   {"",NULL,NULL,{COMPL_NONE,COMPL_NONE}}
1444 };
1445
1446
1447 /*******************************************************************
1448   lookup a command string in the list of commands, including 
1449   abbreviations
1450   ******************************************************************/
1451 static int process_tok(fstring tok)
1452 {
1453         int i = 0, matches = 0;
1454         int cmd=0;
1455         int tok_len = strlen(tok);
1456         
1457         while (commands[i].fn != NULL) {
1458                 if (strequal(commands[i].name,tok)) {
1459                         matches = 1;
1460                         cmd = i;
1461                         break;
1462                 } else if (strnequal(commands[i].name, tok, tok_len)) {
1463                         matches++;
1464                         cmd = i;
1465                 }
1466                 i++;
1467         }
1468   
1469         if (matches == 0)
1470                 return(-1);
1471         else if (matches == 1)
1472                 return(cmd);
1473         else
1474                 return(-2);
1475 }
1476
1477 /****************************************************************************
1478 help
1479 ****************************************************************************/
1480 static void cmd_help(void)
1481 {
1482         int i=0,j;
1483         fstring buf;
1484         
1485         if (next_token(NULL,buf,NULL,sizeof(buf))) {
1486                 if ((i = process_tok(buf)) >= 0)
1487                         DEBUG(0,("HELP %s:\n\t%s\n\n",commands[i].name,commands[i].description));                   
1488         } else {
1489                 while (commands[i].description) {
1490                         for (j=0; commands[i].description && (j<5); j++) {
1491                                 DEBUG(0,("%-15s",commands[i].name));
1492                                 i++;
1493                         }
1494                         DEBUG(0,("\n"));
1495                 }
1496         }
1497 }
1498
1499 /****************************************************************************
1500 wait for keyboard activity, swallowing network packets
1501 ****************************************************************************/
1502 static void wait_keyboard(void)
1503 {
1504         fd_set fds;
1505         struct timeval timeout;
1506   
1507         while (1) {
1508                 FD_ZERO(&fds);
1509                 FD_SET(cli->fd,&fds);
1510                 FD_SET(fileno(stdin),&fds);
1511
1512                 timeout.tv_sec = 20;
1513                 timeout.tv_usec = 0;
1514                 sys_select(MAX(cli->fd,fileno(stdin))+1,&fds,&timeout);
1515       
1516                 if (FD_ISSET(fileno(stdin),&fds))
1517                         return;
1518
1519                 /* We deliberately use receive_smb instead of
1520                    client_receive_smb as we want to receive
1521                    session keepalives and then drop them here.
1522                 */
1523                 if (FD_ISSET(cli->fd,&fds))
1524                         receive_smb(cli->fd,cli->inbuf,0);
1525       
1526                 cli_chkpath(cli, "\\");
1527         }  
1528 }
1529
1530 /****************************************************************************
1531 process a -c command string
1532 ****************************************************************************/
1533 static void process_command_string(char *cmd)
1534 {
1535         pstring line;
1536         char *ptr;
1537
1538         while (cmd[0] != '\0')    {
1539                 char *p;
1540                 fstring tok;
1541                 int i;
1542                 
1543                 if ((p = strchr(cmd, ';')) == 0) {
1544                         strncpy(line, cmd, 999);
1545                         line[1000] = '\0';
1546                         cmd += strlen(cmd);
1547                 } else {
1548                         if (p - cmd > 999) p = cmd + 999;
1549                         strncpy(line, cmd, p - cmd);
1550                         line[p - cmd] = '\0';
1551                         cmd = p + 1;
1552                 }
1553                 
1554                 /* input language code to internal one */
1555                 CNV_INPUT (line);
1556                 
1557                 /* and get the first part of the command */
1558                 ptr = line;
1559                 if (!next_token(&ptr,tok,NULL,sizeof(tok))) continue;
1560                 
1561                 if ((i = process_tok(tok)) >= 0) {
1562                         commands[i].fn();
1563                 } else if (i == -2) {
1564                         DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok)));
1565                 } else {
1566                         DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
1567                 }
1568         }
1569 }       
1570
1571 /****************************************************************************
1572 process commands on stdin
1573 ****************************************************************************/
1574 static void process_stdin(void)
1575 {
1576         pstring line;
1577         char *ptr;
1578
1579         while (!feof(stdin)) {
1580                 fstring tok;
1581                 int i;
1582
1583                 /* display a prompt */
1584                 DEBUG(0,("smb: %s> ", CNV_LANG(cur_dir)));
1585                 dbgflush( );
1586                 
1587                 wait_keyboard();
1588                 
1589                 /* and get a response */
1590                 if (!fgets(line,1000,stdin))
1591                         break;
1592
1593                 /* input language code to internal one */
1594                 CNV_INPUT (line);
1595                 
1596                 /* special case - first char is ! */
1597                 if (*line == '!') {
1598                         system(line + 1);
1599                         continue;
1600                 }
1601       
1602                 /* and get the first part of the command */
1603                 ptr = line;
1604                 if (!next_token(&ptr,tok,NULL,sizeof(tok))) continue;
1605
1606                 if ((i = process_tok(tok)) >= 0) {
1607                         commands[i].fn();
1608                 } else if (i == -2) {
1609                         DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok)));
1610                 } else {
1611                         DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
1612                 }
1613         }
1614 }
1615
1616
1617 /***************************************************** 
1618 return a connection to a server
1619 *******************************************************/
1620 struct cli_state *do_connect(char *server, char *share)
1621 {
1622         struct cli_state *c;
1623         struct nmb_name called, calling;
1624         char *server_n;
1625         struct in_addr ip;
1626         extern struct in_addr ipzero;
1627
1628         if (*share == '\\') {
1629                 server = share+2;
1630                 share = strchr(server,'\\');
1631                 if (!share) return NULL;
1632                 *share = 0;
1633                 share++;
1634         }
1635
1636         server_n = server;
1637         
1638         ip = ipzero;
1639
1640         strupper(server);
1641
1642         make_nmb_name(&calling, global_myname, 0x0, "");
1643         make_nmb_name(&called , server, name_type, "");
1644
1645  again:
1646         ip = ipzero;
1647         if (have_ip) ip = dest_ip;
1648
1649         /* have to open a new connection */
1650         if (!(c=cli_initialise(NULL)) || !cli_connect(c, server_n, &ip)) {
1651                 DEBUG(0,("Connection to %s failed\n", server_n));
1652                 return NULL;
1653         }
1654
1655         if (!cli_session_request(c, &calling, &called)) {
1656                 DEBUG(0,("session request to %s failed\n", called.name));
1657                 cli_shutdown(c);
1658                 if (strcmp(called.name, "*SMBSERVER")) {
1659                         make_nmb_name(&called , "*SMBSERVER", 0x20, "");
1660                         goto again;
1661                 }
1662                 return NULL;
1663         }
1664
1665         DEBUG(4,(" session request ok\n"));
1666
1667         if (!cli_negprot(c)) {
1668                 DEBUG(0,("protocol negotiation failed\n"));
1669                 cli_shutdown(c);
1670                 return NULL;
1671         }
1672
1673         if (!got_pass) {
1674                 char *pass = getpass("Password: ");
1675                 if (pass) {
1676                         pstrcpy(password, pass);
1677                 }
1678         }
1679
1680         if (!cli_session_setup(c, username, 
1681                                password, strlen(password),
1682                                password, strlen(password),
1683                                workgroup)) {
1684                 DEBUG(0,("session setup failed: %s\n", cli_errstr(c)));
1685                 return NULL;
1686         }
1687
1688         /*
1689          * These next two lines are needed to emulate
1690          * old client behaviour for people who have
1691          * scripts based on client output.
1692          * QUESTION ? Do we want to have a 'client compatibility
1693          * mode to turn these on/off ? JRA.
1694          */
1695
1696         if (*c->server_domain || *c->server_os || *c->server_type)
1697                 DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",
1698                         c->server_domain,c->server_os,c->server_type));
1699         
1700         DEBUG(4,(" session setup ok\n"));
1701
1702         if (!cli_send_tconX(c, share, "?????",
1703                             password, strlen(password)+1)) {
1704                 DEBUG(0,("tree connect failed: %s\n", cli_errstr(c)));
1705                 cli_shutdown(c);
1706                 return NULL;
1707         }
1708
1709         DEBUG(4,(" tconx ok\n"));
1710
1711         return c;
1712 }
1713
1714
1715 /****************************************************************************
1716   process commands from the client
1717 ****************************************************************************/
1718 static BOOL process(char *base_directory)
1719 {
1720         cli = do_connect(desthost, service);
1721         
1722         if (!cli) {
1723                 return(False);
1724         }
1725
1726         if (*base_directory) do_cd(base_directory);
1727         
1728         if (cmdstr) {
1729                 process_command_string(cmdstr);
1730         } else {
1731                 process_stdin();
1732         }
1733   
1734         cli_shutdown(cli);
1735         return(True);
1736 }
1737
1738 /****************************************************************************
1739 usage on the program
1740 ****************************************************************************/
1741 static void usage(char *pname)
1742 {
1743   DEBUG(0,("Usage: %s service <password> ", pname));
1744
1745   DEBUG(0,("\nVersion %s\n",VERSION));
1746   DEBUG(0,("\t-s smb.conf           pathname to smb.conf file\n"));
1747   DEBUG(0,("\t-B IP addr            broadcast IP address to use\n"));
1748   DEBUG(0,("\t-O socket_options     socket options to use\n"));
1749   DEBUG(0,("\t-R name resolve order use these name resolution services only\n"));
1750   DEBUG(0,("\t-M host               send a winpopup message to the host\n"));
1751   DEBUG(0,("\t-i scope              use this NetBIOS scope\n"));
1752   DEBUG(0,("\t-N                    don't ask for a password\n"));
1753   DEBUG(0,("\t-n netbios name.      Use this name as my netbios name\n"));
1754   DEBUG(0,("\t-d debuglevel         set the debuglevel\n"));
1755   DEBUG(0,("\t-P                    connect to service as a printer\n"));
1756   DEBUG(0,("\t-p port               connect to the specified port\n"));
1757   DEBUG(0,("\t-l log basename.      Basename for log/debug files\n"));
1758   DEBUG(0,("\t-h                    Print this help message.\n"));
1759   DEBUG(0,("\t-I dest IP            use this IP to connect to\n"));
1760   DEBUG(0,("\t-E                    write messages to stderr instead of stdout\n"));
1761   DEBUG(0,("\t-U username           set the network username\n"));
1762   DEBUG(0,("\t-L host               get a list of shares available on a host\n"));
1763   DEBUG(0,("\t-t terminal code      terminal i/o code {sjis|euc|jis7|jis8|junet|hex}\n"));
1764   DEBUG(0,("\t-m max protocol       set the max protocol level\n"));
1765   DEBUG(0,("\t-W workgroup          set the workgroup name\n"));
1766   DEBUG(0,("\t-T<c|x>IXFqgbNan      command line tar\n"));
1767   DEBUG(0,("\t-D directory          start from directory\n"));
1768   DEBUG(0,("\t-c command string     execute semicolon separated commands\n"));
1769   DEBUG(0,("\n"));
1770 }
1771
1772
1773 /****************************************************************************
1774 get a password from a a file or file descriptor
1775 exit on failure
1776 ****************************************************************************/
1777 static void get_password_file(void)
1778 {
1779         int fd = -1;
1780         char *p;
1781         BOOL close_it = False;
1782         pstring spec;
1783         char pass[128];
1784                 
1785         if ((p = getenv("PASSWD_FD")) != NULL) {
1786                 pstrcpy(spec, "descriptor ");
1787                 pstrcat(spec, p);
1788                 sscanf(p, "%d", &fd);
1789                 close_it = False;
1790         } else if ((p = getenv("PASSWD_FILE")) != NULL) {
1791                 fd = open(p, O_RDONLY);
1792                 pstrcpy(spec, p);
1793                 if (fd < 0) {
1794                         fprintf(stderr, "Error opening PASSWD_FILE %s: %s\n",
1795                                 spec, strerror(errno));
1796                         exit(1);
1797                 }
1798                 close_it = True;
1799         }
1800
1801         for(p = pass, *p = '\0'; /* ensure that pass is null-terminated */
1802             p && p - pass < sizeof(pass);) {
1803                 switch (read(fd, p, 1)) {
1804                 case 1:
1805                         if (*p != '\n' && *p != '\0') {
1806                                 *++p = '\0'; /* advance p, and null-terminate pass */
1807                                 break;
1808                         }
1809                 case 0:
1810                         if (p - pass) {
1811                                 *p = '\0'; /* null-terminate it, just in case... */
1812                                 p = NULL; /* then force the loop condition to become false */
1813                                 break;
1814                         } else {
1815                                 fprintf(stderr, "Error reading password from file %s: %s\n",
1816                                         spec, "empty password\n");
1817                                 exit(1);
1818                         }
1819                         
1820                 default:
1821                         fprintf(stderr, "Error reading password from file %s: %s\n",
1822                                 spec, strerror(errno));
1823                         exit(1);
1824                 }
1825         }
1826         pstrcpy(password, pass);
1827         if (close_it)
1828                 close(fd);
1829 }       
1830
1831
1832
1833 /****************************************************************************
1834 handle a -L query
1835 ****************************************************************************/
1836 static int do_host_query(char *query_host, int port)
1837 {
1838         cli = do_connect(query_host, "IPC$");
1839         if (!cli) return 1;
1840
1841         browse_host(True);
1842         list_servers(workgroup);
1843
1844         cli_shutdown(cli);
1845         
1846         return(0);
1847 }
1848
1849
1850 /****************************************************************************
1851 handle a tar operation
1852 ****************************************************************************/
1853 static int do_tar_op(int port, char *base_directory)
1854 {
1855         int ret;
1856         cli = do_connect(desthost, service);
1857
1858         recurse=True;
1859
1860         if (*base_directory) do_cd(base_directory);
1861         
1862         ret=process_tar();
1863
1864         cli_shutdown(cli);
1865
1866         return(ret);
1867 }
1868
1869 /****************************************************************************
1870 handle a message operation
1871 ****************************************************************************/
1872 static int do_message_op(void)
1873 {
1874         struct in_addr ip;
1875         struct nmb_name called, calling;
1876
1877         ip = ipzero;
1878
1879         strupper(desthost);
1880
1881         make_nmb_name(&calling, global_myname, 0x0, "");
1882         make_nmb_name(&called , desthost, name_type, "");
1883
1884         ip = ipzero;
1885         if (have_ip) ip = dest_ip;
1886
1887         if (!(cli=cli_initialise(NULL)) || !cli_connect(cli, desthost, &ip)) {
1888                 DEBUG(0,("Connection to %s failed\n", desthost));
1889                 return 1;
1890         }
1891
1892         if (!cli_session_request(cli, &calling, &called)) {
1893                 DEBUG(0,("session request failed\n"));
1894                 cli_shutdown(cli);
1895                 return 1;
1896         }
1897
1898         send_message();
1899         cli_shutdown(cli);
1900
1901         return 0;
1902 }
1903
1904
1905 /****************************************************************************
1906   main program
1907 ****************************************************************************/
1908  int main(int argc,char *argv[])
1909 {
1910         fstring base_directory;
1911         char *pname = argv[0];
1912         int port = SMB_PORT;
1913         int opt;
1914         extern FILE *dbf;
1915         extern char *optarg;
1916         extern int optind;
1917         pstring query_host;
1918         BOOL message = False;
1919         BOOL explicit_user = False;
1920         extern char tar_type;
1921         static pstring servicesf = CONFIGFILE;
1922         pstring term_code;
1923         pstring new_name_resolve_order;
1924         char *p;
1925
1926 #ifdef KANJI
1927         pstrcpy(term_code, KANJI);
1928 #else /* KANJI */
1929         *term_code = 0;
1930 #endif /* KANJI */
1931
1932         *query_host = 0;
1933         *base_directory = 0;
1934
1935         *new_name_resolve_order = 0;
1936
1937         DEBUGLEVEL = 2;
1938
1939         setup_logging(pname,True);
1940
1941         TimeInit();
1942         charset_initialise();
1943
1944         if(!get_myname(myhostname,NULL)) {
1945                 DEBUG(0,("Failed to get my hostname.\n"));
1946         }
1947
1948         in_client = True;   /* Make sure that we tell lp_load we are */
1949
1950         if (!lp_load(servicesf,True,False,False)) {
1951                 fprintf(stderr, "Can't load %s - run testparm to debug it\n", servicesf);
1952         }
1953         
1954         codepage_initialise(lp_client_code_page());
1955
1956         interpret_coding_system(term_code);
1957
1958 #ifdef WITH_SSL
1959         sslutil_init(0);
1960 #endif
1961
1962         pstrcpy(workgroup,lp_workgroup());
1963
1964         load_interfaces();
1965         myumask = umask(0);
1966         umask(myumask);
1967
1968         if (getenv("USER")) {
1969                 pstrcpy(username,getenv("USER"));
1970
1971                 /* modification to support userid%passwd syntax in the USER var
1972                    25.Aug.97, jdblair@uab.edu */
1973
1974                 if ((p=strchr(username,'%'))) {
1975                         *p = 0;
1976                         pstrcpy(password,p+1);
1977                         got_pass = True;
1978                         memset(strchr(getenv("USER"),'%')+1,'X',strlen(password));
1979                 }
1980                 strupper(username);
1981         }
1982
1983         /* modification to support PASSWD environmental var
1984            25.Aug.97, jdblair@uab.edu */
1985         if (getenv("PASSWD")) {
1986                 pstrcpy(password,getenv("PASSWD"));
1987                 got_pass = True;
1988         }
1989
1990         if (getenv("PASSWD_FD") || getenv("PASSWD_FILE")) {
1991                 get_password_file();
1992                 got_pass = True;
1993         }
1994
1995         if (*username == 0 && getenv("LOGNAME")) {
1996                 pstrcpy(username,getenv("LOGNAME"));
1997                 strupper(username);
1998         }
1999
2000         if (*username == 0) {
2001                 pstrcpy(username,"GUEST");
2002         }
2003
2004         if (argc < 2) {
2005                 usage(pname);
2006                 exit(1);
2007         }
2008   
2009         if (*argv[1] != '-') {
2010                 pstrcpy(service,argv[1]);  
2011                 /* Convert any '/' characters in the service name to '\' characters */
2012                 string_replace( service, '/','\\');
2013                 argc--;
2014                 argv++;
2015                 
2016                 if (count_chars(service,'\\') < 3) {
2017                         usage(pname);
2018                         printf("\n%s: Not enough '\\' characters in service\n",service);
2019                         exit(1);
2020                 }
2021
2022                 if (argc > 1 && (*argv[1] != '-')) {
2023                         got_pass = True;
2024                         pstrcpy(password,argv[1]);  
2025                         memset(argv[1],'X',strlen(argv[1]));
2026                         argc--;
2027                         argv++;
2028                 }
2029         }
2030
2031         while ((opt = 
2032                 getopt(argc, argv,"s:B:O:R:M:i:Nn:d:Pp:l:hI:EU:L:t:m:W:T:D:c:")) != EOF) {
2033                 switch (opt) {
2034                 case 's':
2035                         pstrcpy(servicesf, optarg);
2036                         break;
2037                 case 'B':
2038                         iface_set_default(NULL,optarg,NULL);
2039                         break;
2040                 case 'O':
2041                         pstrcpy(user_socket_options,optarg);
2042                         break;  
2043                 case 'R':
2044                         pstrcpy(new_name_resolve_order, optarg);
2045                         break;
2046                 case 'M':
2047                         name_type = 0x03; /* messages are sent to NetBIOS name type 0x3 */
2048                         pstrcpy(desthost,optarg);
2049                         strupper(desthost);
2050                         message = True;
2051                         break;
2052                 case 'i':
2053                         pstrcpy(scope,optarg);
2054                         break;
2055                 case 'N':
2056                         got_pass = True;
2057                         break;
2058                 case 'n':
2059                         pstrcpy(global_myname,optarg);
2060                         break;
2061                 case 'd':
2062                         if (*optarg == 'A')
2063                                 DEBUGLEVEL = 10000;
2064                         else
2065                                 DEBUGLEVEL = atoi(optarg);
2066                         break;
2067                 case 'P':
2068                         /* not needed anymore */
2069                         break;
2070                 case 'p':
2071                         port = atoi(optarg);
2072                         break;
2073                 case 'l':
2074                         slprintf(debugf,sizeof(debugf)-1, "%s.client",optarg);
2075                         break;
2076                 case 'h':
2077                         usage(pname);
2078                         exit(0);
2079                         break;
2080                 case 'I':
2081                         {
2082                                 dest_ip = *interpret_addr2(optarg);
2083                                 if (zero_ip(dest_ip))
2084                                         exit(1);
2085                                 have_ip = True;
2086                         }
2087                         break;
2088                 case 'E':
2089                         dbf = stderr;
2090                         break;
2091                 case 'U':
2092                         {
2093                                 char *lp;
2094                                 explicit_user = True;
2095                                 pstrcpy(username,optarg);
2096                                 if ((lp=strchr(username,'%'))) {
2097                                         *lp = 0;
2098                                         pstrcpy(password,lp+1);
2099                                         got_pass = True;
2100                                         memset(strchr(optarg,'%')+1,'X',strlen(password));
2101                                 }
2102                         }
2103                         break;
2104                 case 'L':
2105                         pstrcpy(query_host,optarg);
2106                         if(!explicit_user)
2107                                 *username = '\0';
2108                         break;
2109                 case 't':
2110                         pstrcpy(term_code, optarg);
2111                         break;
2112                 case 'm':
2113                         /* no longer supported */
2114                         break;
2115                 case 'W':
2116                         pstrcpy(workgroup,optarg);
2117                         break;
2118                 case 'T':
2119                         if (!tar_parseargs(argc, argv, optarg, optind)) {
2120                                 usage(pname);
2121                                 exit(1);
2122                         }
2123                         break;
2124                 case 'D':
2125                         pstrcpy(base_directory,optarg);
2126                         break;
2127                 case 'c':
2128                         cmdstr = optarg;
2129                         got_pass = True;
2130                         break;
2131                 default:
2132                         usage(pname);
2133                         exit(1);
2134                 }
2135         }
2136
2137         get_myname((*global_myname)?NULL:global_myname,NULL);  
2138         strupper(global_myname);
2139
2140         if(*new_name_resolve_order)
2141                 lp_set_name_resolve_order(new_name_resolve_order);
2142
2143         if (!tar_type && !*query_host && !*service && !message) {
2144                 usage(pname);
2145                 exit(1);
2146         }
2147
2148         DEBUG( 3, ( "Client started (version %s).\n", VERSION ) );
2149
2150         if (tar_type) {
2151                 return do_tar_op(port, base_directory);
2152         }
2153
2154         if ((p=strchr(query_host,'#'))) {
2155                 *p = 0;
2156                 p++;
2157                 sscanf(p, "%x", &name_type);
2158         }
2159   
2160         if (*query_host) {
2161                 return do_host_query(query_host, port);
2162         }
2163
2164         if (message) {
2165                 return do_message_op();
2166         }
2167
2168         if (!process(base_directory)) {
2169                 close_sockets();
2170                 return(1);
2171         }
2172         close_sockets();
2173
2174         return(0);
2175 }