Tidied up option processing in smbclient - usage message now actually
[kai/samba-autobuild/.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 extern BOOL in_client;
31 pstring cur_dir = "\\";
32 pstring cd_path = "";
33 extern pstring service;
34 extern pstring desthost;
35 extern pstring global_myname;
36 extern pstring myhostname;
37 extern pstring password;
38 extern pstring username;
39 extern pstring workgroup;
40 char *cmdstr="";
41 extern BOOL got_pass;
42 extern BOOL no_pass;
43 extern BOOL connect_as_printer;
44 extern BOOL connect_as_ipc;
45 extern struct in_addr ipzero;
46
47 extern BOOL doencrypt;
48
49 extern pstring user_socket_options;
50
51 static int process_tok(fstring tok);
52 static void cmd_help(char *dum_in, char *dum_out);
53
54 /* 30 second timeout on most commands */
55 #define CLIENT_TIMEOUT (30*1000)
56 #define SHORT_TIMEOUT (5*1000)
57
58 /* value for unused fid field in trans2 secondary request */
59 #define FID_UNUSED (0xFFFF)
60
61 extern int name_type;
62
63 extern int max_protocol;
64
65
66 time_t newer_than = 0;
67 int archive_level = 0;
68
69 extern pstring debugf;
70 extern int DEBUGLEVEL;
71
72 BOOL translation = False;
73
74 extern uint16 cnum;
75 extern uint16 mid;
76 extern uint16 pid;
77 extern uint16 vuid;
78
79 extern BOOL have_ip;
80 extern int max_xmit;
81
82 static int interpret_long_filename(int level,char *p,file_info *finfo);
83 static void dir_action(char *inbuf,char *outbuf,int attribute,file_info *finfo,BOOL recurse_dir,void (*fn)(file_info *),BOOL longdir, BOOL dirstoo);
84 static int interpret_short_filename(char *p,file_info *finfo);
85 static BOOL do_this_one(file_info *finfo);
86
87 /* clitar bits insert */
88 extern int blocksize;
89 extern BOOL tar_inc;
90 extern BOOL tar_reset;
91 /* clitar bits end */
92  
93
94 mode_t myumask = 0755;
95
96 extern pstring scope;
97
98 BOOL prompt = True;
99
100 int printmode = 1;
101
102 BOOL recurse = False;
103 BOOL lowercase = False;
104
105 struct in_addr dest_ip;
106
107 #define SEPARATORS " \t\n\r"
108
109 BOOL abort_mget = True;
110
111 extern int Protocol;
112
113 extern BOOL readbraw_supported ;
114 extern BOOL writebraw_supported;
115
116 pstring fileselection = "";
117
118 extern file_info def_finfo;
119
120 /* timing globals */
121 int get_total_size = 0;
122 int get_total_time_ms = 0;
123 int put_total_size = 0;
124 int put_total_time_ms = 0;
125
126 /* totals globals */
127 int dir_total = 0;
128
129 extern int Client;
130
131 #define USENMB
132
133 #define CNV_LANG(s) dos_to_unix(s,False)
134 #define CNV_INPUT(s) unix_to_dos(s,True)
135
136 /****************************************************************************
137 send an SMBclose on an SMB file handle
138 ****************************************************************************/
139 static void cli_smb_close(char *inbuf, char *outbuf, int clnt_fd, int c_num, int f_num)
140 {
141   bzero(outbuf,smb_size);
142   set_message(outbuf,3,0,True);
143
144   CVAL (outbuf,smb_com) = SMBclose;
145   SSVAL(outbuf,smb_tid,c_num);
146   cli_setup_pkt(outbuf);
147   SSVAL (outbuf,smb_vwv0, f_num);
148   SIVALS(outbuf,smb_vwv1, -1);
149   
150   send_smb(clnt_fd, outbuf);
151   client_receive_smb(clnt_fd,inbuf,CLIENT_TIMEOUT);
152 }
153
154
155 /****************************************************************************
156 write to a local file with CR/LF->LF translation if appropriate. return the 
157 number taken from the buffer. This may not equal the number written.
158 ****************************************************************************/
159 static int writefile(int f, char *b, int n)
160 {
161   int i;
162
163   if (!translation)
164     return(write(f,b,n));
165   
166   i = 0;
167   while (i < n)
168     {
169       if (*b == '\r' && (i<(n-1)) && *(b+1) == '\n')
170         {
171           b++;i++;
172         }
173       if (write(f, b, 1) != 1)
174         {
175           break;
176         }
177       b++;
178       i++;
179     }
180   
181   return(i);
182 }
183
184 /****************************************************************************
185   read from a file with LF->CR/LF translation if appropriate. return the 
186   number read. read approx n bytes.
187 ****************************************************************************/
188 static int readfile(char *b, int size, int n, FILE *f)
189 {
190   int i;
191   int c;
192
193   if (!translation || (size != 1))
194     return(fread(b,size,n,f));
195   
196   i = 0;
197   while (i < n)
198     {
199       if ((c = getc(f)) == EOF)
200         {
201           break;
202         }
203       
204       if (c == '\n') /* change all LFs to CR/LF */
205         {
206           b[i++] = '\r';
207           n++;
208         }
209       
210       if(i < n)
211         b[i++] = c;
212     }
213   
214   return(i);
215 }
216  
217
218 /****************************************************************************
219 read from a file with print translation. return the number read. read approx n
220 bytes.
221 ****************************************************************************/
222 static int printread(FILE *f,char *b,int n)
223 {
224   int i;
225
226   i = readfile(b,1, n-1,f);
227 #if FORMFEED
228   if (feof(f) && i>0)
229     b[i++] = '\014';
230 #endif
231
232   return(i);
233 }
234
235 /****************************************************************************
236 check for existance of a dir
237 ****************************************************************************/
238 static BOOL chkpath(char *path,BOOL report)
239 {
240   fstring path2;
241   pstring inbuf,outbuf;
242   char *p;
243
244   fstrcpy(path2,path);
245   trim_string(path2,NULL,"\\");
246   if (!*path2) *path2 = '\\';
247
248   bzero(outbuf,smb_size);
249   set_message(outbuf,0,4 + strlen(path2),True);
250   SCVAL(outbuf,smb_com,SMBchkpth);
251   SSVAL(outbuf,smb_tid,cnum);
252   cli_setup_pkt(outbuf);
253
254   p = smb_buf(outbuf);
255   *p++ = 4;
256   fstrcpy(p,path2);
257
258 #if 0
259   {
260           /* this little bit of code can be used to extract NT error codes.
261              Just feed a bunch of "cd foo" commands to smbclient then watch
262              in netmon (tridge) */
263           static int code=0;
264           SIVAL(outbuf, smb_rcls, code | 0xC0000000);
265           SSVAL(outbuf, smb_flg2, SVAL(outbuf, smb_flg2) | (1<<14));
266           code++;
267   }
268 #endif
269
270   send_smb(Client,outbuf);
271   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
272
273   if (report && CVAL(inbuf,smb_rcls) != 0)
274     DEBUG(2,("chkpath: %s\n",smb_errstr(inbuf)));
275
276   return(CVAL(inbuf,smb_rcls) == 0);
277 }
278
279
280 /****************************************************************************
281 send a message
282 ****************************************************************************/
283 static void send_message(char *inbuf,char *outbuf)
284 {
285   int total_len = 0;
286
287   char *p;
288   int grp_id;
289
290   /* send a SMBsendstrt command */
291   bzero(outbuf,smb_size);
292   set_message(outbuf,0,0,True);
293   CVAL(outbuf,smb_com) = SMBsendstrt;
294   SSVAL(outbuf,smb_tid,cnum);
295
296   p = smb_buf(outbuf);
297   *p++ = 4;
298   pstrcpy(p,username);
299   p = skip_string(p,1);
300   *p++ = 4;
301   pstrcpy(p,desthost);
302   p = skip_string(p,1);
303
304   set_message(outbuf,0,PTR_DIFF(p,smb_buf(outbuf)),False);
305
306   send_smb(Client,outbuf);
307   
308
309   if (!client_receive_smb(Client,inbuf,SHORT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
310     {
311       printf("SMBsendstrt failed. (%s)\n",smb_errstr(inbuf));
312       return;
313     }
314
315   grp_id = SVAL(inbuf,smb_vwv0);
316
317   printf("Connected. Type your message, ending it with a Control-D\n");
318
319   while (!feof(stdin) && total_len < 1600)
320     {
321       int maxlen = MIN(1600 - total_len,127);
322       pstring msg;
323       int l=0;
324       int c;
325
326       bzero(msg,smb_size);
327
328       for (l=0;l<maxlen && (c=fgetc(stdin))!=EOF;l++)
329         {
330           if (c == '\n')
331             msg[l++] = '\r';
332           msg[l] = c;   
333         }
334
335       CVAL(outbuf,smb_com) = SMBsendtxt;
336
337       set_message(outbuf,1,l+3,True);
338
339       SSVAL(outbuf,smb_vwv0,grp_id);
340
341       p = smb_buf(outbuf);
342       *p = 1;
343       SSVAL(p,1,l);
344       memcpy(p+3,msg,l);
345
346       send_smb(Client,outbuf);
347       
348
349       if (!client_receive_smb(Client,inbuf,SHORT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
350         {
351           printf("SMBsendtxt failed (%s)\n",smb_errstr(inbuf));
352           return;
353         }      
354
355       total_len += l;
356     }
357
358   if (total_len >= 1600)
359     printf("the message was truncated to 1600 bytes ");
360   else
361     printf("sent %d bytes ",total_len);
362
363   printf("(status was %d-%d)\n",CVAL(inbuf,smb_rcls),SVAL(inbuf,smb_err));
364
365   CVAL(outbuf,smb_com) = SMBsendend;
366   set_message(outbuf,1,0,False);
367   SSVAL(outbuf,smb_vwv0,grp_id);
368
369   send_smb(Client,outbuf);
370   
371
372   if (!client_receive_smb(Client,inbuf,SHORT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
373     {
374       printf("SMBsendend failed (%s)\n",smb_errstr(inbuf));
375       return;
376     }      
377 }
378
379
380
381 /****************************************************************************
382 check the space on a device
383 ****************************************************************************/
384 static void do_dskattr(void)
385 {
386   pstring inbuf,outbuf;
387
388   bzero(outbuf,smb_size);
389   set_message(outbuf,0,0,True);
390   CVAL(outbuf,smb_com) = SMBdskattr;
391   SSVAL(outbuf,smb_tid,cnum);
392   cli_setup_pkt(outbuf);
393
394   send_smb(Client,outbuf);
395   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
396
397   if (CVAL(inbuf,smb_rcls) != 0) 
398     DEBUG(0,("Error in dskattr: %s\n",smb_errstr(inbuf)));      
399
400   DEBUG(0,("\n\t\t%d blocks of size %d. %d blocks available\n",
401         SVAL(inbuf,smb_vwv0),
402         SVAL(inbuf,smb_vwv1)*SVAL(inbuf,smb_vwv2),
403         SVAL(inbuf,smb_vwv3)));
404 }
405
406 /****************************************************************************
407 show cd/pwd
408 ****************************************************************************/
409 static void cmd_pwd(char *dum_in, char *dum_out)
410 {
411   DEBUG(0,("Current directory is %s",CNV_LANG(service)));
412   DEBUG(0,("%s\n",CNV_LANG(cur_dir)));
413 }
414
415
416 /****************************************************************************
417 change directory - inner section
418 ****************************************************************************/
419 static void do_cd(char *newdir)
420 {
421   char *p = newdir;
422   pstring saved_dir;
423   pstring dname;
424       
425   dos_format(newdir);
426
427   /* Save the current directory in case the
428      new directory is invalid */
429   pstrcpy(saved_dir, cur_dir);
430   if (*p == '\\')
431     pstrcpy(cur_dir,p);
432   else
433     pstrcat(cur_dir,p);
434   if (*(cur_dir+strlen(cur_dir)-1) != '\\') {
435     pstrcat(cur_dir, "\\");
436   }
437   dos_clean_name(cur_dir);
438   pstrcpy(dname,cur_dir);
439   pstrcat(cur_dir,"\\");
440   dos_clean_name(cur_dir);
441
442   if (!strequal(cur_dir,"\\"))
443     if (!chkpath(dname,True))
444       pstrcpy(cur_dir,saved_dir);
445
446   pstrcpy(cd_path,cur_dir);
447 }
448
449 /****************************************************************************
450 change directory
451 ****************************************************************************/
452 static void cmd_cd(char *inbuf,char *outbuf)
453 {
454   fstring buf;
455
456   if (next_token(NULL,buf,NULL,sizeof(buf)))
457     do_cd(buf);
458   else
459     DEBUG(0,("Current directory is %s\n",CNV_LANG(cur_dir)));
460 }
461
462
463 /****************************************************************************
464   display info about a file
465   ****************************************************************************/
466 static void display_finfo(file_info *finfo)
467 {
468   if (do_this_one(finfo)) {
469     time_t t = finfo->mtime; /* the time is assumed to be passed as GMT */
470     DEBUG(0,("  %-30s%7.7s%.0f  %s",
471        CNV_LANG(finfo->name),
472            attrib_string(finfo->mode),
473            (double)finfo->size,
474            asctime(LocalTime(&t))));
475     dir_total += finfo->size;
476   }
477 }
478
479
480 /****************************************************************************
481   calculate size of a file
482   ****************************************************************************/
483 static void do_du(file_info *finfo)
484 {
485   if (do_this_one(finfo)) {
486     dir_total += finfo->size;
487   }
488 }
489
490
491 /****************************************************************************
492   do a directory listing, calling fn on each file found. Use the TRANSACT2
493   call for long filenames
494   ****************************************************************************/
495 static int do_long_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(file_info *),BOOL recurse_dir, BOOL dirstoo)
496 {
497   int max_matches = 512;
498   int info_level = Protocol<PROTOCOL_NT1?1:260; /* NT uses 260, OS/2 uses 2. Both accept 1. */
499   char *p;
500   pstring mask;
501   file_info finfo;
502   int i;
503   char *dirlist = NULL;
504   int dirlist_len = 0;
505   int total_received = 0;
506   BOOL First = True;
507   char *resp_data=NULL;
508   char *resp_param=NULL;
509   int resp_data_len = 0;
510   int resp_param_len=0;
511
512   int ff_resume_key = 0;
513   int ff_searchcount=0;
514   int ff_eos=0;
515   int ff_lastname=0;
516   int ff_dir_handle=0;
517   int loop_count = 0;
518
519   uint16 setup;
520   pstring param;
521
522   pstrcpy(mask,Mask);
523
524   while (ff_eos == 0)
525     {
526       loop_count++;
527       if (loop_count > 200)
528         {
529           DEBUG(0,("Error: Looping in FIND_NEXT??\n"));
530           break;
531         }
532
533       if (First)
534         {
535           setup = TRANSACT2_FINDFIRST;
536           SSVAL(param,0,attribute); /* attribute */
537           SSVAL(param,2,max_matches); /* max count */
538           SSVAL(param,4,8+4+2); /* resume required + close on end + continue */
539           SSVAL(param,6,info_level); 
540           SIVAL(param,8,0);
541           pstrcpy(param+12,mask);
542         }
543       else
544         {
545           setup = TRANSACT2_FINDNEXT;
546           SSVAL(param,0,ff_dir_handle);
547           SSVAL(param,2,max_matches); /* max count */
548           SSVAL(param,4,info_level); 
549           SIVAL(param,6,ff_resume_key); /* ff_resume_key */
550           SSVAL(param,10,8+4+2);        /* resume required + close on end + continue */
551           pstrcpy(param+12,mask);
552
553           DEBUG(5,("hand=0x%X resume=%d ff_lastname=%d mask=%s\n",
554                    ff_dir_handle,ff_resume_key,ff_lastname,mask));
555         }
556       /* ??? original code added 1 pad byte after param */
557
558       cli_send_trans_request(outbuf,SMBtrans2,NULL,0,FID_UNUSED,0,
559                          NULL,param,&setup,
560                          0,12+strlen(mask)+1,1,
561                          BUFFER_SIZE,10,0);
562
563       if (!cli_receive_trans_response(inbuf,SMBtrans2,
564                               &resp_data_len,&resp_param_len,
565                                   &resp_data,&resp_param))
566         {
567           DEBUG(3,("FIND%s gave %s\n",First?"FIRST":"NEXT",smb_errstr(inbuf)));
568           break;
569         }
570
571       /* parse out some important return info */
572       p = resp_param;
573       if (First)
574         {
575           ff_dir_handle = SVAL(p,0);
576           ff_searchcount = SVAL(p,2);
577           ff_eos = SVAL(p,4);
578           ff_lastname = SVAL(p,8);
579         }
580       else
581         {
582           ff_searchcount = SVAL(p,0);
583           ff_eos = SVAL(p,2);
584           ff_lastname = SVAL(p,6);
585         }
586
587       if (ff_searchcount == 0) 
588         break;
589
590       /* point to the data bytes */
591       p = resp_data;
592
593       /* we might need the lastname for continuations */
594       if (ff_lastname > 0)
595         {
596           switch(info_level)
597             {
598             case 260:
599               ff_resume_key =0;
600               StrnCpy(mask,p+ff_lastname,resp_data_len-ff_lastname);
601               /* pstrcpy(mask,p+ff_lastname+94); */
602               break;
603             case 1:
604               pstrcpy(mask,p + ff_lastname + 1);
605               ff_resume_key = 0;
606               break;
607             }
608         }
609       else
610         pstrcpy(mask,"");
611   
612       /* and add them to the dirlist pool */
613       dirlist = Realloc(dirlist,dirlist_len + resp_data_len);
614
615       if (!dirlist)
616         {
617           DEBUG(0,("Failed to expand dirlist\n"));
618           break;
619         }
620
621       /* put in a length for the last entry, to ensure we can chain entries 
622          into the next packet */
623       {
624         char *p2;
625         for (p2=p,i=0;i<(ff_searchcount-1);i++)
626           p2 += interpret_long_filename(info_level,p2,NULL);
627         SSVAL(p2,0,resp_data_len - PTR_DIFF(p2,p));
628       }
629
630       /* grab the data for later use */
631       memcpy(dirlist+dirlist_len,p,resp_data_len);
632       dirlist_len += resp_data_len;
633
634       total_received += ff_searchcount;
635
636       if (resp_data) free(resp_data); resp_data = NULL;
637       if (resp_param) free(resp_param); resp_param = NULL;
638
639       DEBUG(3,("received %d entries (eos=%d resume=%d)\n",
640                ff_searchcount,ff_eos,ff_resume_key));
641
642       First = False;
643     }
644
645   if (!fn)
646     for (p=dirlist,i=0;i<total_received;i++)
647       {
648         p += interpret_long_filename(info_level,p,&finfo);
649         display_finfo(&finfo);
650       }
651
652   for (p=dirlist,i=0;i<total_received;i++)
653     {
654       p += interpret_long_filename(info_level,p,&finfo);
655       dir_action(inbuf,outbuf,attribute,&finfo,recurse_dir,fn,True, dirstoo);
656     }
657
658   /* free up the dirlist buffer */
659   if (dirlist) free(dirlist);
660   return(total_received);
661 }
662
663
664 /****************************************************************************
665   do a directory listing, calling fn on each file found
666   ****************************************************************************/
667 static int do_short_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(file_info *),BOOL recurse_dir, BOOL dirstoo)
668 {
669   char *p;
670   int received = 0;
671   BOOL first = True;
672   char status[21];
673   int num_asked = (max_xmit - 100)/DIR_STRUCT_SIZE;
674   int num_received = 0;
675   int i;
676   char *dirlist = NULL;
677   pstring mask;
678   file_info finfo;
679
680   finfo = def_finfo;
681
682   bzero(status,21);
683
684   pstrcpy(mask,Mask);
685   
686   while (1)
687     {
688       bzero(outbuf,smb_size);
689       if (first)        
690         set_message(outbuf,2,5 + strlen(mask),True);
691       else
692         set_message(outbuf,2,5 + 21,True);
693
694 #if FFIRST
695       if (Protocol >= PROTOCOL_LANMAN1)
696         CVAL(outbuf,smb_com) = SMBffirst;
697       else
698 #endif
699         CVAL(outbuf,smb_com) = SMBsearch;
700
701       SSVAL(outbuf,smb_tid,cnum);
702       cli_setup_pkt(outbuf);
703
704       SSVAL(outbuf,smb_vwv0,num_asked);
705       SSVAL(outbuf,smb_vwv1,attribute);
706   
707       p = smb_buf(outbuf);
708       *p++ = 4;
709       
710       if (first)
711         pstrcpy(p,mask);
712       else
713         pstrcpy(p,"");
714       p += strlen(p) + 1;
715       
716       *p++ = 5;
717       if (first)
718         SSVAL(p,0,0);
719       else
720         {
721           SSVAL(p,0,21);
722           p += 2;
723           memcpy(p,status,21);
724         }
725
726       send_smb(Client,outbuf);
727       client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
728
729       received = SVAL(inbuf,smb_vwv0);
730
731       DEBUG(5,("dir received %d\n",received));
732
733       DEBUG(6,("errstr=%s\n",smb_errstr(inbuf)));
734
735       if (received <= 0) break;
736
737       first = False;
738
739       dirlist = Realloc(dirlist,(num_received + received)*DIR_STRUCT_SIZE);
740
741       if (!dirlist) 
742         return 0;
743
744       p = smb_buf(inbuf) + 3;
745
746       memcpy(dirlist+num_received*DIR_STRUCT_SIZE,
747              p,received*DIR_STRUCT_SIZE);
748
749       memcpy(status,p + ((received-1)*DIR_STRUCT_SIZE),21);
750
751       num_received += received;
752
753       if (CVAL(inbuf,smb_rcls) != 0) break;
754     }
755
756 #if FFIRST
757   if (!first && Protocol >= PROTOCOL_LANMAN1)
758     {
759       bzero(outbuf,smb_size);
760       CVAL(outbuf,smb_com) = SMBfclose;
761
762       SSVAL(outbuf,smb_tid,cnum);
763       cli_setup_pkt(outbuf);
764
765       p = smb_buf(outbuf);
766       *p++ = 4;
767       
768       pstrcpy(p,"");
769       p += strlen(p) + 1;
770       
771       *p++ = 5;
772       SSVAL(p,0,21);
773       p += 2;
774       memcpy(p,status,21);
775
776       send_smb(Client,outbuf);
777       client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
778
779       if (CVAL(inbuf,smb_rcls) != 0) 
780         DEBUG(0,("Error closing search: %s\n",smb_errstr(inbuf)));      
781     }
782 #endif
783
784   if (!fn)
785     for (p=dirlist,i=0;i<num_received;i++)
786       {
787         p += interpret_short_filename(p,&finfo);
788         display_finfo(&finfo);
789       }
790
791   for (p=dirlist,i=0;i<num_received;i++)
792     {
793       p += interpret_short_filename(p,&finfo);
794       dir_action(inbuf,outbuf,attribute,&finfo,recurse_dir,fn,False,dirstoo);
795     }
796
797   if (dirlist) free(dirlist);
798   return(num_received);
799 }
800
801
802
803 /****************************************************************************
804   do a directory listing, calling fn on each file found
805   ****************************************************************************/
806 void do_dir(char *inbuf,char *outbuf,char *mask,int attribute,void (*fn)(file_info *),BOOL recurse_dir, BOOL dirstoo)
807 {
808   dos_format(mask);
809   DEBUG(5,("do_dir(%s,%x,%s)\n",mask,attribute,BOOLSTR(recurse_dir)));
810   if (Protocol >= PROTOCOL_LANMAN2)
811     {
812       if (do_long_dir(inbuf,outbuf,mask,attribute,fn,recurse_dir,dirstoo) > 0)
813         return;
814     }
815
816   expand_mask(mask,False);
817   do_short_dir(inbuf,outbuf,mask,attribute,fn,recurse_dir,dirstoo);
818   return;
819 }
820
821 /*******************************************************************
822   decide if a file should be operated on
823   ********************************************************************/
824 static BOOL do_this_one(file_info *finfo)
825 {
826   if (finfo->mode & aDIR) return(True);
827
828   if (newer_than && finfo->mtime < newer_than)
829     return(False);
830
831   if ((archive_level==1 || archive_level==2) && !(finfo->mode & aARCH))
832     return(False);
833
834   return(True);
835 }
836
837
838 /*****************************************************************************
839  Convert a character pointer in a cli_call_api() response to a form we can use.
840  This function contains code to prevent core dumps if the server returns 
841  invalid data.
842 *****************************************************************************/
843 static char *fix_char_ptr(unsigned int datap, unsigned int converter, char *rdata, int rdrcnt)
844 {
845   if( datap == 0 )              /* turn NULL pointers */
846   {                             /* into zero length strings */
847     return "";
848   }
849   else
850   {
851     unsigned int offset = datap - converter;
852
853     if( offset >= rdrcnt )
854     {
855       DEBUG(1,("bad char ptr: datap=%u, converter=%u, rdata=%lu, rdrcnt=%d>", datap, converter, (unsigned long)rdata, rdrcnt));
856       return "<ERROR>";
857     }
858     else
859     {
860       return &rdata[offset];
861     }
862   }
863 }
864
865 /****************************************************************************
866 interpret a short filename structure
867 The length of the structure is returned
868 ****************************************************************************/
869 static int interpret_short_filename(char *p,file_info *finfo)
870 {
871   finfo->mode = CVAL(p,21);
872
873   /* this date is converted to GMT by make_unix_date */
874   finfo->ctime = make_unix_date(p+22);
875   finfo->mtime = finfo->atime = finfo->ctime;
876   finfo->size = IVAL(p,26);
877   pstrcpy(finfo->name,p+30);
878   
879   return(DIR_STRUCT_SIZE);
880 }
881
882 /****************************************************************************
883 interpret a long filename structure - this is mostly guesses at the moment
884 The length of the structure is returned
885 The structure of a long filename depends on the info level. 260 is used
886 by NT and 2 is used by OS/2
887 ****************************************************************************/
888 static int interpret_long_filename(int level,char *p,file_info *finfo)
889 {
890   if (finfo)
891     memcpy(finfo,&def_finfo,sizeof(*finfo));
892
893   switch (level)
894     {
895     case 1: /* OS/2 understands this */
896       if (finfo)
897         {
898           /* these dates are converted to GMT by make_unix_date */
899           finfo->ctime = make_unix_date2(p+4);
900           finfo->atime = make_unix_date2(p+8);
901           finfo->mtime = make_unix_date2(p+12);
902           finfo->size = IVAL(p,16);
903           finfo->mode = CVAL(p,24);
904           pstrcpy(finfo->name,p+27);
905         }
906       return(28 + CVAL(p,26));
907
908     case 2: /* this is what OS/2 uses mostly */
909       if (finfo)
910         {
911           /* these dates are converted to GMT by make_unix_date */
912           finfo->ctime = make_unix_date2(p+4);
913           finfo->atime = make_unix_date2(p+8);
914           finfo->mtime = make_unix_date2(p+12);
915           finfo->size = IVAL(p,16);
916           finfo->mode = CVAL(p,24);
917           pstrcpy(finfo->name,p+31);
918         }
919       return(32 + CVAL(p,30));
920
921       /* levels 3 and 4 are untested */
922     case 3:
923       if (finfo)
924         {
925           /* these dates are probably like the other ones */
926           finfo->ctime = make_unix_date2(p+8);
927           finfo->atime = make_unix_date2(p+12);
928           finfo->mtime = make_unix_date2(p+16);
929           finfo->size = IVAL(p,20);
930           finfo->mode = CVAL(p,28);
931           pstrcpy(finfo->name,p+33);
932         }
933       return(SVAL(p,4)+4);
934
935     case 4:
936       if (finfo)
937         {
938           /* these dates are probably like the other ones */
939           finfo->ctime = make_unix_date2(p+8);
940           finfo->atime = make_unix_date2(p+12);
941           finfo->mtime = make_unix_date2(p+16);
942           finfo->size = IVAL(p,20);
943           finfo->mode = CVAL(p,28);
944           pstrcpy(finfo->name,p+37);
945         }
946       return(SVAL(p,4)+4);
947
948     case 260: /* NT uses this, but also accepts 2 */
949       if (finfo)
950         {
951           int ret = SVAL(p,0);
952           int namelen;
953           p += 4; /* next entry offset */
954           p += 4; /* fileindex */
955
956           /* these dates appear to arrive in a weird way. It seems to
957              be localtime plus the serverzone given in the initial
958              connect. This is GMT when DST is not in effect and one
959              hour from GMT otherwise. Can this really be right??
960
961              I suppose this could be called kludge-GMT. Is is the GMT
962              you get by using the current DST setting on a different
963              localtime. It will be cheap to calculate, I suppose, as
964              no DST tables will be needed */
965
966           finfo->ctime = interpret_long_date(p); p += 8;
967           finfo->atime = interpret_long_date(p); p += 8;
968           finfo->mtime = interpret_long_date(p); p += 8; p += 8;
969           finfo->size = IVAL(p,0); p += 8;
970           p += 8; /* alloc size */
971           finfo->mode = CVAL(p,0); p += 4;
972           namelen = IVAL(p,0); p += 4;
973           p += 4; /* EA size */
974           p += 2; /* short name len? */
975           p += 24; /* short name? */      
976           StrnCpy(finfo->name,p,namelen);
977           return(ret);
978         }
979       return(SVAL(p,0));
980     }
981
982   DEBUG(1,("Unknown long filename format %d\n",level));
983   return(SVAL(p,0));
984 }
985
986
987
988
989 /****************************************************************************
990   act on the files in a dir listing
991
992   RJS, 4-Apr-1998, dirstoo added to allow caller to indicate that directories
993                    should be processed as well.
994   ****************************************************************************/
995 static void dir_action(char *inbuf,char *outbuf,int attribute,file_info *finfo,BOOL recurse_dir,void (*fn)(file_info *),BOOL longdir, BOOL dirstoo)
996 {
997
998   if (!((finfo->mode & aDIR) == 0 && *fileselection && 
999         !mask_match(finfo->name,fileselection,False,False)) &&
1000       !(recurse_dir && (strequal(finfo->name,".") || 
1001                         strequal(finfo->name,".."))))
1002     {
1003       if (recurse_dir && (finfo->mode & aDIR))
1004         {
1005           pstring mask2;
1006           pstring sav_dir;
1007
1008           if (fn && dirstoo && do_this_one(finfo)) { /* Do dirs, RJS */
1009             fn(finfo);
1010           }
1011
1012           pstrcpy(sav_dir,cur_dir);
1013           pstrcat(cur_dir,finfo->name);
1014           pstrcat(cur_dir,"\\");
1015           pstrcpy(mask2,cur_dir);
1016
1017           if (!fn)
1018             DEBUG(0,("\n%s\n",CNV_LANG(cur_dir)));
1019
1020           pstrcat(mask2,"*");
1021
1022           if (longdir)
1023             do_long_dir(inbuf,outbuf,mask2,attribute,fn,True, dirstoo);      
1024           else
1025             do_dir(inbuf,outbuf,mask2,attribute,fn,True, dirstoo);
1026
1027           pstrcpy(cur_dir,sav_dir);
1028         }
1029       else
1030         {
1031           if (fn && do_this_one(finfo))
1032             fn(finfo);
1033         }
1034     }
1035 }
1036
1037
1038 /****************************************************************************
1039   get a directory listing
1040   ****************************************************************************/
1041 static void cmd_dir(char *inbuf,char *outbuf)
1042 {
1043   int attribute = aDIR | aSYSTEM | aHIDDEN;
1044   pstring mask;
1045   fstring buf;
1046   char *p=buf;
1047
1048   dir_total = 0;
1049   pstrcpy(mask,cur_dir);
1050   if(mask[strlen(mask)-1]!='\\')
1051     pstrcat(mask,"\\");
1052
1053   if (next_token(NULL,buf,NULL,sizeof(buf))) {
1054     dos_format(p);
1055     if (*p == '\\')
1056       pstrcpy(mask,p);
1057     else
1058       pstrcat(mask,p);
1059   }
1060   else {
1061     pstrcat(mask,"*");
1062   }
1063
1064   do_dir(inbuf,outbuf,mask,attribute,NULL,recurse,False);
1065
1066   do_dskattr();
1067
1068   DEBUG(3, ("Total bytes listed: %d\n", dir_total));
1069 }
1070
1071
1072 /****************************************************************************
1073   get a directory listing
1074   ****************************************************************************/
1075 static void cmd_du(char *inbuf,char *outbuf)
1076 {
1077   int attribute = aDIR | aSYSTEM | aHIDDEN;
1078   pstring mask;
1079   fstring buf;
1080   char *p=buf;
1081
1082   dir_total = 0;
1083   pstrcpy(mask,cur_dir);
1084   if(mask[strlen(mask)-1]!='\\')
1085     pstrcat(mask,"\\");
1086
1087   if (next_token(NULL,buf,NULL,sizeof(buf)))
1088   {
1089     dos_format(p);
1090     if (*p == '\\')
1091       pstrcpy(mask,p);
1092     else
1093       pstrcat(mask,p);
1094   }
1095   else {
1096     pstrcat(mask,"*");
1097   }
1098
1099   do_dir(inbuf,outbuf,mask,attribute,do_du,recurse,False);
1100
1101   do_dskattr();
1102
1103   DEBUG(0, ("Total number of bytes: %d\n", dir_total));
1104 }
1105
1106 /****************************************************************************
1107   get a file from rname to lname
1108   ****************************************************************************/
1109 static void do_get(char *rname,char *lname,file_info *finfo1)
1110 {  
1111   int handle=0,fnum;
1112   uint32 nread=0;
1113   char *p;
1114   BOOL newhandle = False;
1115   char *inbuf,*outbuf;
1116   file_info finfo;
1117   BOOL close_done = False;
1118   BOOL ignore_close_error = False;
1119   char *dataptr=NULL;
1120   int datalen=0;
1121
1122   struct timeval tp_start;
1123   GetTimeOfDay(&tp_start);
1124
1125   if (finfo1) 
1126     finfo = *finfo1;
1127   else
1128     finfo = def_finfo;
1129
1130   if (lowercase)
1131     strlower(lname);
1132
1133
1134   inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1135   outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1136
1137   if (!inbuf || !outbuf)
1138   {
1139     DEBUG(0,("out of memory\n"));
1140     return;
1141   }
1142
1143   bzero(outbuf,smb_size);
1144   set_message(outbuf,15,1 + strlen(rname),True);
1145
1146   CVAL(outbuf,smb_com) = SMBopenX;
1147   SSVAL(outbuf,smb_tid,cnum);
1148   cli_setup_pkt(outbuf);
1149
1150   SSVAL(outbuf,smb_vwv0,0xFF);
1151   SSVAL(outbuf,smb_vwv2,1); /* return additional info */
1152   SSVAL(outbuf,smb_vwv3,(DENY_NONE<<4));
1153   SSVAL(outbuf,smb_vwv4,aSYSTEM | aHIDDEN);
1154   SSVAL(outbuf,smb_vwv5,aSYSTEM | aHIDDEN);
1155   SSVAL(outbuf,smb_vwv8,1);
1156   SSVAL(outbuf,smb_vwv11,0xffff);
1157   SSVAL(outbuf,smb_vwv12,0xffff);
1158   
1159   p = smb_buf(outbuf);
1160   pstrcpy(p,rname);
1161   p = skip_string(p,1);
1162
1163   /* do a chained openX with a readX? */
1164 #if 1
1165   if (finfo.size > 0)
1166     {
1167       DEBUG(3,("Chaining readX wth openX\n"));
1168       SSVAL(outbuf,smb_vwv0,SMBreadX);
1169       SSVAL(outbuf,smb_vwv1,smb_offset(p,outbuf));
1170       bzero(p,200);
1171       p -= smb_wct;
1172       SCVAL(p,smb_wct,10);
1173       SSVAL(p,smb_vwv0,0xFF);
1174       SSVAL(p,smb_vwv5,MIN(max_xmit-500,finfo.size));
1175       SSVAL(p,smb_vwv9,MIN(BUFFER_SIZE,finfo.size));
1176       smb_setlen(outbuf,smb_len(outbuf)+11*2+1);  
1177     }
1178 #endif
1179
1180   if(!strcmp(lname,"-"))
1181     handle = fileno(stdout);
1182   else 
1183     {
1184       handle = creat(lname,0644);
1185       newhandle = True;
1186     }
1187   if (handle < 0)
1188     {
1189       DEBUG(0,("Error opening local file %s\n",lname));
1190       free(inbuf);free(outbuf);
1191       return;
1192     }
1193
1194   send_smb(Client,outbuf);
1195   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1196
1197   if (CVAL(inbuf,smb_rcls) != 0)
1198     {
1199       if (CVAL(inbuf,smb_rcls) == ERRSRV &&
1200           SVAL(inbuf,smb_err) == ERRnoresource &&
1201           cli_reopen_connection(inbuf,outbuf))
1202         {
1203           do_get(rname,lname,finfo1);
1204           return;
1205         }
1206       DEBUG(0,("%s opening remote file %s\n",smb_errstr(inbuf),CNV_LANG(rname)));
1207       if(newhandle)
1208         {
1209           close(handle);
1210           unlink(lname);
1211         }
1212       free(inbuf);free(outbuf);
1213       return;
1214     }
1215
1216   pstrcpy(finfo.name,rname);
1217
1218   if (!finfo1)
1219     {
1220       finfo.mode = SVAL(inbuf,smb_vwv3);
1221       /* these times arrive as LOCAL time, using the DST offset 
1222          corresponding to that time, we convert them to GMT */
1223       finfo.mtime = make_unix_date3(inbuf+smb_vwv4);
1224       finfo.atime = finfo.ctime = finfo.mtime;
1225       finfo.size = IVAL(inbuf,smb_vwv6);
1226     }
1227
1228   DEBUG(3,("file %s attrib 0x%X\n",CNV_LANG(finfo.name),finfo.mode));
1229
1230   fnum = SVAL(inbuf,smb_vwv2);
1231
1232   /* we might have got some data from a chained readX */
1233   if (SVAL(inbuf,smb_vwv0) == SMBreadX)
1234     {
1235       p = (smb_base(inbuf)+SVAL(inbuf,smb_vwv1)) - smb_wct;
1236       datalen = SVAL(p,smb_vwv5);
1237       dataptr = smb_base(inbuf) + SVAL(p,smb_vwv6);
1238     }
1239   else
1240     {
1241       dataptr = NULL;
1242       datalen = 0;
1243     }
1244
1245
1246   DEBUG(2,("getting file %s of size %.0f bytes as %s ",
1247            CNV_LANG(finfo.name),
1248            (double)finfo.size,
1249            lname));
1250
1251   while (nread < finfo.size && !close_done)
1252     {
1253       int method = -1;
1254       static BOOL can_chain_close = True;
1255
1256       p=NULL;
1257       
1258       DEBUG(3,("nread=%d max_xmit=%d fsize=%.0f\n",nread,max_xmit,(double)finfo.size));
1259
1260       /* 3 possible read types. readbraw if a large block is required.
1261          readX + close if not much left and read if neither is supported */
1262
1263       /* we might have already read some data from a chained readX */
1264       if (dataptr && datalen>0)
1265         method=3;
1266
1267       /* if we can finish now then readX+close */
1268       if (method<0 && can_chain_close && (Protocol >= PROTOCOL_LANMAN1) && 
1269           ((finfo.size - nread) < 
1270            (max_xmit - (2*smb_size + 13*SIZEOFWORD + 300))))
1271         method = 0;
1272
1273       /* if we support readraw then use that */
1274       if (method<0 && readbraw_supported)
1275         method = 1;
1276
1277       /* if we can then use readX */
1278       if (method<0 && (Protocol >= PROTOCOL_LANMAN1))
1279         method = 2;
1280
1281       switch (method)
1282         {
1283           /* use readX */
1284         case 0:
1285         case 2:
1286           if (method == 0)
1287             close_done = True;
1288             
1289           /* use readX + close */
1290           bzero(outbuf,smb_size);
1291           set_message(outbuf,10,0,True);
1292           CVAL(outbuf,smb_com) = SMBreadX;
1293           SSVAL(outbuf,smb_tid,cnum);
1294           cli_setup_pkt(outbuf);
1295           
1296           if (close_done)
1297             {
1298               CVAL(outbuf,smb_vwv0) = SMBclose;
1299               SSVAL(outbuf,smb_vwv1,smb_offset(smb_buf(outbuf),outbuf));
1300             }
1301           else
1302             CVAL(outbuf,smb_vwv0) = 0xFF;             
1303           
1304           SSVAL(outbuf,smb_vwv2,fnum);
1305           SIVAL(outbuf,smb_vwv3,nread);
1306           SSVAL(outbuf,smb_vwv5,MIN(max_xmit-200,finfo.size - nread));
1307           SSVAL(outbuf,smb_vwv6,0);
1308           SIVAL(outbuf,smb_vwv7,0);
1309           SSVAL(outbuf,smb_vwv9,MIN(BUFFER_SIZE,finfo.size-nread));
1310           
1311           if (close_done)
1312             {
1313               p = smb_buf(outbuf);
1314               bzero(p,9);
1315               
1316               CVAL(p,0) = 3;
1317               SSVAL(p,1,fnum);
1318               SIVALS(p,3,-1);
1319               
1320               /* now set the total packet length */
1321               smb_setlen(outbuf,smb_len(outbuf)+9);
1322             }
1323           
1324           send_smb(Client,outbuf);
1325           client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1326           
1327           if (CVAL(inbuf,smb_rcls) != 0)
1328             {
1329               DEBUG(0,("Error %s reading remote file\n",smb_errstr(inbuf)));
1330               break;
1331             }
1332           
1333           if (close_done &&
1334               SVAL(inbuf,smb_vwv0) != SMBclose)
1335             {
1336               /* NOTE: WfWg sometimes just ignores the chained
1337                  command! This seems to break the spec? */
1338               DEBUG(3,("Rejected chained close?\n"));
1339               close_done = False;
1340               can_chain_close = False;
1341               ignore_close_error = True;
1342             }
1343           
1344           datalen = SVAL(inbuf,smb_vwv5);
1345           dataptr = smb_base(inbuf) + SVAL(inbuf,smb_vwv6);
1346           break;
1347
1348           /* use readbraw */
1349         case 1:
1350           {
1351             static int readbraw_size = BUFFER_SIZE;
1352           
1353             extern int Client;
1354             bzero(outbuf,smb_size);
1355             set_message(outbuf,8,0,True);
1356             CVAL(outbuf,smb_com) = SMBreadbraw;
1357             SSVAL(outbuf,smb_tid,cnum);
1358             cli_setup_pkt(outbuf);
1359             SSVAL(outbuf,smb_vwv0,fnum);
1360             SIVAL(outbuf,smb_vwv1,nread);
1361             SSVAL(outbuf,smb_vwv3,MIN(finfo.size-nread,readbraw_size));
1362             SSVAL(outbuf,smb_vwv4,0);
1363             SIVALS(outbuf,smb_vwv5,-1);
1364             send_smb(Client,outbuf);
1365
1366             /* Now read the raw data into the buffer and write it */      
1367             if(read_smb_length(Client,inbuf,0) == -1) {
1368               DEBUG(0,("Failed to read length in readbraw\n"));     
1369               exit(1);
1370             }
1371             
1372             /* Even though this is not an smb message, smb_len
1373                returns the generic length of an smb message */
1374             datalen = smb_len(inbuf);
1375
1376             if (datalen == 0)
1377               {
1378                 /* we got a readbraw error */
1379                 DEBUG(4,("readbraw error - reducing size\n"));
1380                 readbraw_size = (readbraw_size * 9) / 10;
1381                 
1382                 if (readbraw_size < max_xmit)
1383                   {
1384                     DEBUG(0,("disabling readbraw\n"));
1385                     readbraw_supported = False;
1386                   }
1387                 
1388                 dataptr=NULL;
1389                 continue;
1390               }
1391
1392             if(read_data(Client,inbuf,datalen) != datalen) {
1393               DEBUG(0,("Failed to read data in readbraw\n"));
1394               exit(1);
1395             }
1396             dataptr = inbuf;
1397           }
1398           break;
1399
1400         case 3:
1401           /* we've already read some data with a chained readX */
1402           break;
1403
1404         default:
1405           /* use plain read */
1406           bzero(outbuf,smb_size);
1407           set_message(outbuf,5,0,True);
1408           CVAL(outbuf,smb_com) = SMBread;
1409           SSVAL(outbuf,smb_tid,cnum);
1410           cli_setup_pkt(outbuf);
1411
1412           SSVAL(outbuf,smb_vwv0,fnum);
1413           SSVAL(outbuf,smb_vwv1,MIN(max_xmit-200,finfo.size - nread));
1414           SIVAL(outbuf,smb_vwv2,nread);
1415           SSVAL(outbuf,smb_vwv4,finfo.size - nread);
1416
1417           send_smb(Client,outbuf);
1418           client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1419
1420           if (CVAL(inbuf,smb_rcls) != 0)
1421             {
1422               DEBUG(0,("Error %s reading remote file\n",smb_errstr(inbuf)));
1423               break;
1424             }
1425
1426           datalen = SVAL(inbuf,smb_vwv0);
1427           dataptr = smb_buf(inbuf) + 3;
1428           break;
1429         }
1430  
1431       if (writefile(handle,dataptr,datalen) != datalen)
1432         {
1433           DEBUG(0,("Error writing local file\n"));
1434           break;
1435         }
1436       
1437       nread += datalen;
1438       if (datalen == 0) 
1439         {
1440           DEBUG(0,("Error reading file %s. Got %d bytes\n",CNV_LANG(rname),nread));
1441           break;
1442         }
1443
1444       dataptr=NULL;
1445       datalen=0;
1446     }
1447
1448
1449
1450   if (!close_done)
1451     {
1452       cli_smb_close(inbuf, outbuf, Client, cnum, fnum);
1453       
1454       if (!ignore_close_error && CVAL(inbuf,smb_rcls) != 0)
1455         {
1456           DEBUG(0,("Error %s closing remote file\n",smb_errstr(inbuf)));
1457           if(newhandle)
1458             close(handle);
1459           free(inbuf);free(outbuf);
1460           return;
1461         }
1462     }
1463
1464   if(newhandle)
1465     close(handle);
1466
1467   if (archive_level >= 2 && (finfo.mode & aARCH)) {
1468     bzero(outbuf,smb_size);
1469     set_message(outbuf,8,strlen(rname)+4,True);
1470     CVAL(outbuf,smb_com) = SMBsetatr;
1471     SSVAL(outbuf,smb_tid,cnum);
1472     cli_setup_pkt(outbuf);
1473     SSVAL(outbuf,smb_vwv0,finfo.mode & ~(aARCH));
1474     SIVALS(outbuf,smb_vwv1,0);
1475     p = smb_buf(outbuf);
1476     *p++ = 4;
1477     pstrcpy(p,rname);
1478     p += strlen(p)+1;
1479     *p++ = 4;
1480     *p = 0;
1481     send_smb(Client,outbuf);
1482     client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1483   }
1484
1485   {
1486     struct timeval tp_end;
1487     int this_time;
1488
1489     GetTimeOfDay(&tp_end);
1490     this_time = 
1491       (tp_end.tv_sec - tp_start.tv_sec)*1000 +
1492         (tp_end.tv_usec - tp_start.tv_usec)/1000;
1493     get_total_time_ms += this_time;
1494     get_total_size += finfo.size;
1495
1496     DEBUG(1,("(%g kb/s) (average %g kb/s)\n",
1497              finfo.size / (1.024*this_time + 1.0e-4),
1498              get_total_size / (1.024*get_total_time_ms)));
1499   }
1500
1501   free(inbuf);free(outbuf);
1502 }
1503
1504
1505 /****************************************************************************
1506   get a file
1507   ****************************************************************************/
1508 static void cmd_get(char *dum_in, char *dum_out)
1509 {
1510   pstring lname;
1511   pstring rname;
1512   char *p;
1513
1514   pstrcpy(rname,cur_dir);
1515   pstrcat(rname,"\\");
1516
1517   p = rname + strlen(rname);
1518
1519   if (!next_token(NULL,p,NULL,sizeof(rname)-strlen(rname))) {
1520     DEBUG(0,("get <filename>\n"));
1521     return;
1522   }
1523   pstrcpy(lname,p);
1524   dos_clean_name(rname);
1525     
1526   next_token(NULL,lname,NULL,sizeof(lname));
1527
1528   do_get(rname,lname,NULL);
1529 }
1530
1531
1532 /****************************************************************************
1533   do a mget operation on one file
1534   ****************************************************************************/
1535 static void do_mget(file_info *finfo)
1536 {
1537   pstring rname;
1538   pstring quest;
1539
1540   if (strequal(finfo->name,".") || strequal(finfo->name,".."))
1541     return;
1542
1543   if (abort_mget)
1544     {
1545       DEBUG(0,("mget aborted\n"));
1546       return;
1547     }
1548
1549   if (finfo->mode & aDIR)
1550     slprintf(quest,sizeof(pstring)-1,
1551              "Get directory %s? ",CNV_LANG(finfo->name));
1552   else
1553     slprintf(quest,sizeof(pstring)-1,
1554              "Get file %s? ",CNV_LANG(finfo->name));
1555
1556   if (prompt && !yesno(quest)) return;
1557
1558   if (finfo->mode & aDIR)
1559     {
1560       pstring saved_curdir;
1561       pstring mget_mask;
1562       char *inbuf,*outbuf;
1563
1564       inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1565       outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1566
1567       if (!inbuf || !outbuf)
1568         {
1569           DEBUG(0,("out of memory\n"));
1570           return;
1571         }
1572
1573       pstrcpy(saved_curdir,cur_dir);
1574
1575       pstrcat(cur_dir,finfo->name);
1576       pstrcat(cur_dir,"\\");
1577
1578       unix_format(finfo->name);
1579       {
1580         if (lowercase)
1581           strlower(finfo->name);
1582
1583         if (!directory_exist(finfo->name,NULL) && 
1584             dos_mkdir(finfo->name,0777) != 0) 
1585           {
1586             DEBUG(0,("failed to create directory %s\n",CNV_LANG(finfo->name)));
1587             pstrcpy(cur_dir,saved_curdir);
1588             free(inbuf);free(outbuf);
1589             return;
1590           }
1591
1592         if (dos_chdir(finfo->name) != 0)
1593           {
1594             DEBUG(0,("failed to chdir to directory %s\n",CNV_LANG(finfo->name)));
1595             pstrcpy(cur_dir,saved_curdir);
1596             free(inbuf);free(outbuf);
1597             return;
1598           }
1599       }       
1600
1601       pstrcpy(mget_mask,cur_dir);
1602       pstrcat(mget_mask,"*");
1603       
1604       do_dir((char *)inbuf,(char *)outbuf,
1605              mget_mask,aSYSTEM | aHIDDEN | aDIR,do_mget,False, False);
1606       chdir("..");
1607       pstrcpy(cur_dir,saved_curdir);
1608       free(inbuf);free(outbuf);
1609     }
1610   else
1611     {
1612       pstrcpy(rname,cur_dir);
1613       pstrcat(rname,finfo->name);
1614       do_get(rname,finfo->name,finfo);
1615     }
1616 }
1617
1618 /****************************************************************************
1619 view the file using the pager
1620 ****************************************************************************/
1621 static void cmd_more(char *dum_in, char *dum_out)
1622 {
1623   fstring rname,lname,tmpname,pager_cmd;
1624   char *pager;
1625
1626   fstrcpy(rname,cur_dir);
1627   fstrcat(rname,"\\");
1628   slprintf(tmpname,
1629            sizeof(fstring)-1,
1630            "%s/smbmore.%d",tmpdir(),(int)getpid());
1631   fstrcpy(lname,tmpname);
1632
1633   if (!next_token(NULL,rname+strlen(rname),NULL,sizeof(rname)-strlen(rname))) {
1634     DEBUG(0,("more <filename>\n"));
1635     return;
1636   }
1637   dos_clean_name(rname);
1638
1639   do_get(rname,lname,NULL);
1640
1641   pager=getenv("PAGER");
1642
1643   slprintf(pager_cmd,sizeof(pager_cmd)-1,
1644            "%s %s",(pager? pager:PAGER), tmpname);
1645   system(pager_cmd);
1646   unlink(tmpname);
1647 }
1648
1649
1650
1651 /****************************************************************************
1652 do a mget command
1653 ****************************************************************************/
1654 static void cmd_mget(char *inbuf,char *outbuf)
1655 {
1656   int attribute = aSYSTEM | aHIDDEN;
1657   pstring mget_mask;
1658   fstring buf;
1659   char *p=buf;
1660
1661   *mget_mask = 0;
1662
1663   if (recurse)
1664     attribute |= aDIR;
1665
1666   abort_mget = False;
1667
1668   while (next_token(NULL,p,NULL,sizeof(buf)))
1669     {
1670       pstrcpy(mget_mask,cur_dir);
1671       if(mget_mask[strlen(mget_mask)-1]!='\\')
1672         pstrcat(mget_mask,"\\");
1673
1674       if (*p == '\\')
1675         pstrcpy(mget_mask,p);
1676       else
1677         pstrcat(mget_mask,p);
1678       do_dir((char *)inbuf,(char *)outbuf,mget_mask,attribute,do_mget,False,False);
1679     }
1680
1681   if (! *mget_mask)
1682     {
1683       pstrcpy(mget_mask,cur_dir);
1684       if(mget_mask[strlen(mget_mask)-1]!='\\')
1685         pstrcat(mget_mask,"\\");
1686       pstrcat(mget_mask,"*");
1687       do_dir((char *)inbuf,(char *)outbuf,mget_mask,attribute,do_mget,False,False);
1688     }
1689 }
1690
1691 /****************************************************************************
1692 make a directory of name "name"
1693 ****************************************************************************/
1694 static BOOL do_mkdir(char *name)
1695 {
1696   char *p;
1697   char *inbuf,*outbuf;
1698
1699   inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1700   outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1701
1702   if (!inbuf || !outbuf)
1703     {
1704       DEBUG(0,("out of memory\n"));
1705       return False;
1706     }
1707
1708   bzero(outbuf,smb_size);
1709   set_message(outbuf,0,2 + strlen(name),True);
1710   
1711   CVAL(outbuf,smb_com) = SMBmkdir;
1712   SSVAL(outbuf,smb_tid,cnum);
1713   cli_setup_pkt(outbuf);
1714
1715   
1716   p = smb_buf(outbuf);
1717   *p++ = 4;      
1718   pstrcpy(p,name);
1719   
1720   send_smb(Client,outbuf);
1721   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1722   
1723   if (CVAL(inbuf,smb_rcls) != 0)
1724     {
1725       DEBUG(0,("%s making remote directory %s\n",
1726                smb_errstr(inbuf),CNV_LANG(name)));
1727
1728       free(inbuf);free(outbuf);
1729       return(False);
1730     }
1731
1732   free(inbuf);free(outbuf);
1733   return(True);
1734 }
1735
1736
1737 /****************************************************************************
1738   make a directory
1739   ****************************************************************************/
1740 static void cmd_mkdir(char *inbuf,char *outbuf)
1741 {
1742   pstring mask;
1743   fstring buf;
1744   char *p=buf;
1745   
1746   pstrcpy(mask,cur_dir);
1747
1748   if (!next_token(NULL,p,NULL,sizeof(buf)))
1749     {
1750       if (!recurse)
1751         DEBUG(0,("mkdir <dirname>\n"));
1752       return;
1753     }
1754   pstrcat(mask,p);
1755
1756   if (recurse)
1757     {
1758       pstring ddir;
1759       pstring ddir2;
1760       *ddir2 = 0;
1761
1762       pstrcpy(ddir,mask);
1763       trim_string(ddir,".",NULL);
1764       p = strtok(ddir,"/\\");
1765       while (p)
1766         {
1767           pstrcat(ddir2,p);
1768           if (!chkpath(ddir2,False))
1769             {             
1770               do_mkdir(ddir2);
1771             }
1772           pstrcat(ddir2,"\\");
1773           p = strtok(NULL,"/\\");
1774         }        
1775     }
1776   else
1777     do_mkdir(mask);
1778 }
1779
1780
1781 /*******************************************************************
1782   write to a file using writebraw
1783   ********************************************************************/
1784 static int smb_writeraw(char *outbuf,int fnum,int pos,char *buf,int n)
1785 {
1786   extern int Client;
1787   pstring inbuf;
1788
1789   bzero(outbuf,smb_size);
1790   bzero(inbuf,smb_size);  
1791   set_message(outbuf,Protocol>PROTOCOL_COREPLUS?12:10,0,True);
1792
1793   CVAL(outbuf,smb_com) = SMBwritebraw;
1794   SSVAL(outbuf,smb_tid,cnum);
1795   cli_setup_pkt(outbuf);
1796
1797   SSVAL(outbuf,smb_vwv0,fnum);
1798   SSVAL(outbuf,smb_vwv1,n);
1799   SIVAL(outbuf,smb_vwv3,pos);
1800   SSVAL(outbuf,smb_vwv7,1);
1801
1802   send_smb(Client,outbuf);
1803   
1804   if (!client_receive_smb(Client,inbuf,CLIENT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
1805     return(0);
1806
1807   _smb_setlen(buf-4,n);         /* HACK! XXXX */
1808
1809   if (write_socket(Client,buf-4,n+4) != n+4)
1810     return(0);
1811
1812   if (!client_receive_smb(Client,inbuf,CLIENT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0) {
1813     DEBUG(0,("Error writing remote file (2)\n"));
1814     return(0);
1815   }
1816   return(SVAL(inbuf,smb_vwv0));
1817 }
1818       
1819
1820
1821 /*******************************************************************
1822   write to a file
1823   ********************************************************************/
1824 static int smb_writefile(char *outbuf,int fnum,int pos,char *buf,int n)
1825 {
1826   pstring inbuf;
1827
1828   if (writebraw_supported && n > (max_xmit-200)) 
1829     return(smb_writeraw(outbuf,fnum,pos,buf,n));
1830
1831   bzero(outbuf,smb_size);
1832   bzero(inbuf,smb_size);
1833   set_message(outbuf,5,n + 3,True);
1834
1835   CVAL(outbuf,smb_com) = SMBwrite;
1836   SSVAL(outbuf,smb_tid,cnum);
1837   cli_setup_pkt(outbuf);
1838
1839   SSVAL(outbuf,smb_vwv0,fnum);
1840   SSVAL(outbuf,smb_vwv1,n);
1841   SIVAL(outbuf,smb_vwv2,pos);
1842   SSVAL(outbuf,smb_vwv4,0);
1843   CVAL(smb_buf(outbuf),0) = 1;
1844   SSVAL(smb_buf(outbuf),1,n);
1845
1846   memcpy(smb_buf(outbuf)+3,buf,n);
1847
1848   send_smb(Client,outbuf);
1849   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1850
1851   if (CVAL(inbuf,smb_rcls) != 0) {
1852     DEBUG(0,("%s writing remote file\n",smb_errstr(inbuf)));
1853     return(0);
1854   }
1855   return(SVAL(inbuf,smb_vwv0));
1856 }
1857       
1858
1859
1860 /****************************************************************************
1861   put a single file
1862   ****************************************************************************/
1863 static void do_put(char *rname,char *lname,file_info *finfo)
1864 {
1865   int fnum;
1866   FILE *f;
1867   int nread=0;
1868   char *p;
1869   char *inbuf,*outbuf; 
1870   time_t close_time = finfo->mtime;
1871   char *buf=NULL;
1872   static int maxwrite=0;
1873
1874   struct timeval tp_start;
1875   GetTimeOfDay(&tp_start);
1876
1877   inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1878   outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1879
1880   if (!inbuf || !outbuf)
1881     {
1882       DEBUG(0,("out of memory\n"));
1883       return;
1884     }
1885
1886   bzero(outbuf,smb_size);
1887   set_message(outbuf,3,2 + strlen(rname),True);
1888
1889   if (finfo->mtime == 0 || finfo->mtime == -1)
1890     finfo->mtime = finfo->atime = finfo->ctime = time(NULL);
1891
1892   CVAL(outbuf,smb_com) = SMBcreate;
1893   SSVAL(outbuf,smb_tid,cnum);
1894   cli_setup_pkt(outbuf);
1895
1896   SSVAL(outbuf,smb_vwv0,finfo->mode);
1897   put_dos_date3(outbuf,smb_vwv1,finfo->mtime);
1898   
1899   p = smb_buf(outbuf);
1900   *p++ = 4;      
1901   pstrcpy(p,rname);
1902   
1903   send_smb(Client,outbuf);
1904   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1905   
1906   if (CVAL(inbuf,smb_rcls) != 0)
1907     {
1908       DEBUG(0,("%s opening remote file %s\n",smb_errstr(inbuf),CNV_LANG(rname)));
1909
1910       free(inbuf);free(outbuf);if (buf) free(buf);
1911       return;
1912     }
1913
1914   /* allow files to be piped into smbclient
1915      jdblair 24.jun.98 */
1916   if (!strcmp(lname, "-")) {
1917     f = stdin;
1918     /* size of file is not known */
1919     finfo->size = 0;
1920   } else {
1921     f = fopen(lname,"r");
1922   }
1923
1924   if (!f)
1925     {
1926       DEBUG(0,("Error opening local file %s\n",lname));
1927       free(inbuf);free(outbuf);
1928       return;
1929     }
1930
1931   
1932   fnum = SVAL(inbuf,smb_vwv0);
1933   if (finfo->size < 0)
1934     finfo->size = file_size(lname);
1935   
1936   DEBUG(1,("putting file %s of size %.0f bytes as %s ",lname,(double)finfo->size,CNV_LANG(rname)));
1937   
1938   if (!maxwrite)
1939     maxwrite = writebraw_supported?MAX(max_xmit,BUFFER_SIZE):(max_xmit-200);
1940
1941   /* This is a rewrite of the read/write loop that doesn't require the input
1942      file to be of a known length.  This allows the stream pointer 'f' to
1943      refer to stdin.
1944
1945      Rather than reallocing the read buffer every loop to keep it the min
1946      necessary length this look uses a fixed length buffer and just tests
1947      for eof on the file stream at the top of each loop.
1948      jdblair, 24.jun.98 */
1949
1950   buf = (char *)malloc(maxwrite+4);
1951   while (! feof(f) )
1952     {
1953       int n = maxwrite;
1954       int ret;
1955
1956       if ((n = readfile(buf+4,1,n,f)) < 1)
1957         {
1958           DEBUG(0,("Error reading local file\n"));
1959           break;
1960         }         
1961
1962       ret = smb_writefile(outbuf,fnum,nread,buf+4,n);
1963
1964       if (n != ret) {
1965               if (!maxwrite) {
1966                       DEBUG(0,("Error writing file\n"));
1967                       break;
1968               } else {
1969                       fseek(f,nread,SEEK_SET);
1970                       maxwrite /= 2;
1971                       continue;
1972               }
1973       }
1974
1975       nread += n;
1976     }
1977
1978   bzero(outbuf,smb_size);
1979   set_message(outbuf,3,0,True);
1980   CVAL(outbuf,smb_com) = SMBclose;
1981   SSVAL(outbuf,smb_tid,cnum);
1982   cli_setup_pkt(outbuf);
1983
1984   SSVAL(outbuf,smb_vwv0,fnum);  
1985   put_dos_date3(outbuf,smb_vwv1,close_time);
1986
1987   send_smb(Client,outbuf);
1988   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1989   
1990   if (CVAL(inbuf,smb_rcls) != 0)
1991     {
1992       DEBUG(0,("%s closing remote file %s\n",smb_errstr(inbuf),CNV_LANG(rname)));
1993       fclose(f);
1994       free(inbuf);free(outbuf);
1995       if (buf) free(buf);
1996       return;
1997     }
1998
1999   
2000   fclose(f);
2001   free(inbuf);free(outbuf);
2002   if (buf) free(buf);
2003
2004   {
2005     struct timeval tp_end;
2006     int this_time;
2007
2008     GetTimeOfDay(&tp_end);
2009     this_time = 
2010       (tp_end.tv_sec - tp_start.tv_sec)*1000 +
2011         (tp_end.tv_usec - tp_start.tv_usec)/1000;
2012     put_total_time_ms += this_time;
2013     put_total_size += finfo->size;
2014
2015     DEBUG(1,("(%g kb/s) (average %g kb/s)\n",
2016              finfo->size / (1.024*this_time + 1.0e-4),
2017              put_total_size / (1.024*put_total_time_ms)));
2018   }
2019 }
2020
2021  
2022
2023 /****************************************************************************
2024   put a file
2025   ****************************************************************************/
2026 static void cmd_put(char *dum_in, char *dum_out)
2027 {
2028   pstring lname;
2029   pstring rname;
2030   fstring buf;
2031   char *p=buf;
2032   file_info finfo;
2033   finfo = def_finfo;
2034   
2035   pstrcpy(rname,cur_dir);
2036   pstrcat(rname,"\\");
2037   
2038   
2039   if (!next_token(NULL,p,NULL,sizeof(buf)))
2040     {
2041       DEBUG(0,("put <filename>\n"));
2042       return;
2043     }
2044   pstrcpy(lname,p);
2045   
2046   if (next_token(NULL,p,NULL,sizeof(buf)))
2047     pstrcat(rname,p);      
2048   else
2049     pstrcat(rname,lname);
2050
2051   dos_clean_name(rname);
2052
2053   {
2054     SMB_STRUCT_STAT st;
2055     /* allow '-' to represent stdin
2056        jdblair, 24.jun.98 */
2057     if (!file_exist(lname,&st) &&
2058       (strcmp(lname,"-"))) {
2059       DEBUG(0,("%s does not exist\n",lname));
2060       return;
2061     }
2062     finfo.mtime = st.st_mtime;
2063   }
2064
2065   do_put(rname,lname,&finfo);
2066 }
2067
2068 /****************************************************************************
2069   seek in a directory/file list until you get something that doesn't start with
2070   the specified name
2071   ****************************************************************************/
2072 static BOOL seek_list(FILE *f,char *name)
2073 {
2074   pstring s;
2075   while (!feof(f))
2076     {
2077       if (fscanf(f,"%s",s) != 1) return(False);
2078       trim_string(s,"./",NULL);
2079       if (strncmp(s,name,strlen(name)) != 0)
2080         {
2081           pstrcpy(name,s);
2082           return(True);
2083         }
2084     }
2085       
2086   return(False);
2087 }
2088
2089
2090 /****************************************************************************
2091   set the file selection mask
2092   ****************************************************************************/
2093 static void cmd_select(char *dum_in, char *dum_out)
2094 {
2095   pstrcpy(fileselection,"");
2096   next_token(NULL,fileselection,NULL,sizeof(fileselection));
2097 }
2098
2099
2100 /****************************************************************************
2101   mput some files
2102   ****************************************************************************/
2103 static void cmd_mput(char *dum_in, char *dum_out)
2104 {
2105   pstring lname;
2106   pstring rname;
2107   file_info finfo;
2108   fstring buf;
2109   char *p=buf;
2110
2111   finfo = def_finfo;
2112
2113   
2114   while (next_token(NULL,p,NULL,sizeof(buf)))
2115     {
2116       SMB_STRUCT_STAT st;
2117       pstring cmd;
2118       pstring tmpname;
2119       FILE *f;
2120       
2121       slprintf(tmpname,sizeof(pstring)-1,
2122                "%s/ls.smb.%d",tmpdir(),(int)getpid());
2123       if (recurse)
2124         slprintf(cmd,sizeof(pstring)-1,
2125                 "find . -name \"%s\" -print > %s",p,tmpname);
2126       else
2127         slprintf(cmd,sizeof(pstring)-1,
2128                  "/bin/ls %s > %s",p,tmpname);
2129       system(cmd);
2130
2131       f = fopen(tmpname,"r");
2132       if (!f) continue;
2133
2134       while (!feof(f))
2135         {
2136           pstring quest;
2137
2138           if (fscanf(f,"%s",lname) != 1) break;
2139           trim_string(lname,"./",NULL);
2140
2141         again1:
2142
2143           /* check if it's a directory */
2144           if (directory_exist(lname,&st))
2145             {
2146               if (!recurse) continue;
2147               slprintf(quest,sizeof(pstring)-1,
2148                        "Put directory %s? ",lname);
2149               if (prompt && !yesno(quest)) 
2150                 {
2151                   pstrcat(lname,"/");
2152                   if (!seek_list(f,lname))
2153                     break;
2154                   goto again1;              
2155                 }
2156               
2157               pstrcpy(rname,cur_dir);
2158               pstrcat(rname,lname);
2159               if (!chkpath(rname,False) && !do_mkdir(rname)) {
2160                 pstrcat(lname,"/");
2161                 if (!seek_list(f,lname))
2162                   break;
2163                 goto again1;                              
2164               }
2165
2166               continue;
2167             }
2168           else
2169             {
2170               slprintf(quest,sizeof(quest)-1,
2171                        "Put file %s? ",lname);
2172               if (prompt && !yesno(quest)) continue;
2173
2174               pstrcpy(rname,cur_dir);
2175               pstrcat(rname,lname);
2176             }
2177           dos_format(rname);
2178
2179           /* null size so do_put knows to ignore it */
2180           finfo.size = -1;
2181
2182           /* set the date on the file */
2183           finfo.mtime = st.st_mtime;
2184
2185           do_put(rname,lname,&finfo);
2186         }
2187       fclose(f);
2188       unlink(tmpname);
2189     }
2190 }
2191
2192 /****************************************************************************
2193   cancel a print job
2194   ****************************************************************************/
2195 static void do_cancel(int job)
2196 {
2197   char *rparam = NULL;
2198   char *rdata = NULL;
2199   char *p;
2200   int rdrcnt,rprcnt;
2201   pstring param;
2202
2203   bzero(param,sizeof(param));
2204
2205   p = param;
2206   SSVAL(p,0,81);                /* DosPrintJobDel() */
2207   p += 2;
2208   pstrcpy(p,"W");
2209   p = skip_string(p,1);
2210   pstrcpy(p,"");
2211   p = skip_string(p,1);
2212   SSVAL(p,0,job);     
2213   p += 2;
2214
2215   if (cli_call_api(PIPE_LANMAN, 0,PTR_DIFF(p,param),0, 0,
2216            6, 1000,
2217                &rprcnt,&rdrcnt,
2218                param,NULL, NULL,
2219                &rparam,&rdata))
2220     {
2221       int res = SVAL(rparam,0);
2222
2223       if (!res)
2224         printf("Job %d cancelled\n",job);
2225       else
2226         printf("Error %d calcelling job %d\n",res,job);
2227       return;
2228     }
2229   else
2230   printf("Server refused cancel request\n");
2231
2232   if (rparam) free(rparam);
2233   if (rdata) free(rdata);
2234
2235   return;
2236 }
2237
2238
2239 /****************************************************************************
2240   cancel a print job
2241   ****************************************************************************/
2242 static void cmd_cancel(char *inbuf,char *outbuf )
2243 {
2244   fstring buf;
2245   int job; 
2246
2247   if (!connect_as_printer)
2248     {
2249       DEBUG(0,("WARNING: You didn't use the -P option to smbclient.\n"));
2250       DEBUG(0,("Trying to cancel print jobs without -P may fail\n"));
2251     }
2252
2253   if (!next_token(NULL,buf,NULL,sizeof(buf))) {
2254     printf("cancel <jobid> ...\n");
2255     return;
2256   }
2257   do {
2258     job = atoi(buf);
2259     do_cancel(job);
2260   } while (next_token(NULL,buf,NULL,sizeof(buf)));
2261 }
2262
2263
2264
2265
2266 /****************************************************************************
2267   print a file
2268   ****************************************************************************/
2269 static void cmd_print(char *inbuf,char *outbuf )
2270 {
2271   int fnum;
2272   FILE *f = NULL;
2273   uint32 nread=0;
2274   pstring lname;
2275   pstring rname;
2276   char *p;
2277
2278   if (!connect_as_printer)
2279     {
2280       DEBUG(0,("WARNING: You didn't use the -P option to smbclient.\n"));
2281       DEBUG(0,("Trying to print without -P may fail\n"));
2282     }
2283
2284   if (!next_token(NULL,lname,NULL, sizeof(lname)))
2285     {
2286       DEBUG(0,("print <filename>\n"));
2287       return;
2288     }
2289
2290   pstrcpy(rname,lname);
2291   p = strrchr(rname,'/');
2292   if (p)
2293     {
2294       pstring tname;
2295       pstrcpy(tname,p+1);
2296       pstrcpy(rname,tname);
2297     }
2298
2299   if ((int)strlen(rname) > 14)
2300     rname[14] = 0;
2301
2302   if (strequal(lname,"-"))
2303     {
2304       f = stdin;
2305       pstrcpy(rname,"stdin");
2306     }
2307   
2308   dos_clean_name(rname);
2309
2310   bzero(outbuf,smb_size);
2311   set_message(outbuf,2,2 + strlen(rname),True);
2312   
2313   CVAL(outbuf,smb_com) = SMBsplopen;
2314   SSVAL(outbuf,smb_tid,cnum);
2315   cli_setup_pkt(outbuf);
2316
2317   SSVAL(outbuf,smb_vwv0,0);
2318   SSVAL(outbuf,smb_vwv1,printmode);
2319   
2320   p = smb_buf(outbuf);
2321   *p++ = 4;      
2322   pstrcpy(p,rname);
2323   
2324   send_smb(Client,outbuf);
2325   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2326   
2327   if (CVAL(inbuf,smb_rcls) != 0)
2328     {
2329       DEBUG(0,("%s opening printer for %s\n",smb_errstr(inbuf),CNV_LANG(rname)));
2330       return;
2331     }
2332   
2333   if (!f)
2334     f = fopen(lname,"r");
2335   if (!f)
2336     {
2337       DEBUG(0,("Error opening local file %s\n",lname));
2338       return;
2339     }
2340
2341   
2342   fnum = SVAL(inbuf,smb_vwv0);
2343   
2344   DEBUG(1,("printing file %s as %s\n",lname,CNV_LANG(rname)));
2345   
2346   while (!feof(f))
2347     {
2348       int n;
2349   
2350       bzero(outbuf,smb_size);
2351       set_message(outbuf,1,3,True);
2352
2353       /* for some strange reason the OS/2 print server can't handle large
2354          packets when printing. weird */
2355       n = MIN(1024,max_xmit-(smb_len(outbuf)+4));
2356
2357       if (translation)
2358         n = printread(f,smb_buf(outbuf)+3,(int)(0.95*n));
2359       else
2360         n = readfile(smb_buf(outbuf)+3,1,n,f);
2361       if (n <= 0) 
2362         {
2363           DEBUG(0,("read gave %d\n",n));
2364           break;
2365         }
2366
2367       smb_setlen(outbuf,smb_len(outbuf) + n);
2368
2369       CVAL(outbuf,smb_com) = SMBsplwr;
2370       SSVAL(outbuf,smb_tid,cnum);
2371       cli_setup_pkt(outbuf);
2372
2373       SSVAL(outbuf,smb_vwv0,fnum);
2374       SSVAL(outbuf,smb_vwv1,n+3);
2375       CVAL(smb_buf(outbuf),0) = 1;
2376       SSVAL(smb_buf(outbuf),1,n);
2377
2378       send_smb(Client,outbuf);
2379       client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2380
2381       if (CVAL(inbuf,smb_rcls) != 0)
2382         {
2383           DEBUG(0,("%s printing remote file\n",smb_errstr(inbuf)));
2384           break;
2385         }
2386
2387       nread += n;
2388     }
2389
2390   DEBUG(2,("%d bytes printed\n",nread));
2391
2392   bzero(outbuf,smb_size);
2393   set_message(outbuf,1,0,True);
2394   CVAL(outbuf,smb_com) = SMBsplclose;
2395   SSVAL(outbuf,smb_tid,cnum);
2396   cli_setup_pkt(outbuf);
2397
2398   SSVAL(outbuf,smb_vwv0,fnum);
2399
2400   send_smb(Client,outbuf);
2401   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2402   
2403   if (CVAL(inbuf,smb_rcls) != 0)
2404     {
2405       DEBUG(0,("%s closing print file\n",smb_errstr(inbuf)));
2406       if (f != stdin)
2407         fclose(f);
2408       return;
2409     }
2410
2411   if (f != stdin)
2412     fclose(f);
2413 }
2414
2415 /****************************************************************************
2416  show a print queue - this is deprecated as it uses the old smb that
2417  has limited support - the correct call is the cmd_p_queue_4() after this.
2418 ****************************************************************************/
2419 static void cmd_queue(char *inbuf,char *outbuf )
2420 {
2421   int count;
2422   char *p;
2423
2424   bzero(outbuf,smb_size);
2425   set_message(outbuf,2,0,True);
2426   
2427   CVAL(outbuf,smb_com) = SMBsplretq;
2428   SSVAL(outbuf,smb_tid,cnum);
2429   cli_setup_pkt(outbuf);
2430
2431   SSVAL(outbuf,smb_vwv0,32); /* a max of 20 entries is to be shown */
2432   SSVAL(outbuf,smb_vwv1,0); /* the index into the queue */
2433   
2434   send_smb(Client,outbuf);
2435   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2436   
2437   if (CVAL(inbuf,smb_rcls) != 0)
2438     {
2439       DEBUG(0,("%s obtaining print queue\n",smb_errstr(inbuf)));
2440       return;
2441     }
2442
2443   count = SVAL(inbuf,smb_vwv0);
2444   p = smb_buf(inbuf) + 3;
2445   if (count <= 0)
2446     {
2447       DEBUG(0,("No entries in the print queue\n"));
2448       return;
2449     }  
2450
2451   {
2452     char status[20];
2453
2454     DEBUG(0,("Job      Name              Size         Status\n"));
2455
2456     while (count--)
2457       {
2458         switch (CVAL(p,4))
2459           {
2460           case 0x01: safe_strcpy(status,"held or stopped", sizeof(status)-1); break;
2461           case 0x02: safe_strcpy(status,"printing",sizeof(status)-1); break;
2462           case 0x03: safe_strcpy(status,"awaiting print", sizeof(status)-1); break;
2463           case 0x04: safe_strcpy(status,"in intercept",sizeof(status)-1); break;
2464           case 0x05: safe_strcpy(status,"file had error",sizeof(status)-1); break;
2465           case 0x06: safe_strcpy(status,"printer error",sizeof(status)-1); break;
2466           default: safe_strcpy(status,"unknown",sizeof(status)-1); break;
2467           }
2468
2469         DEBUG(0,("%-6d   %-16.16s  %-9d    %s\n",
2470                  SVAL(p,5),p+12,IVAL(p,7),status));
2471         p += 28;
2472       }
2473   }
2474   
2475 }
2476
2477
2478 /****************************************************************************
2479 show information about a print queue
2480 ****************************************************************************/
2481 static void cmd_p_queue_4(char *inbuf,char *outbuf )
2482 {
2483   char *rparam = NULL;
2484   char *rdata = NULL;
2485   char *p;
2486   int rdrcnt, rprcnt;
2487   pstring param;
2488   int result_code=0;
2489
2490   if (!connect_as_printer)
2491     {
2492       DEBUG(0,("WARNING: You didn't use the -P option to smbclient.\n"));
2493       DEBUG(0,("Trying to print without -P may fail\n"));
2494     }
2495   
2496   bzero(param,sizeof(param));
2497
2498   p = param;
2499   SSVAL(p,0,76);                        /* API function number 76 (DosPrintJobEnum) */
2500   p += 2;
2501   pstrcpy(p,"zWrLeh");                   /* parameter description? */
2502   p = skip_string(p,1);
2503   pstrcpy(p,"WWzWWDDzz");                /* returned data format */
2504   p = skip_string(p,1);
2505   pstrcpy(p,strrchr(service,'\\')+1);    /* name of queue */
2506   p = skip_string(p,1);
2507   SSVAL(p,0,2);                 /* API function level 2, PRJINFO_2 data structure */
2508   SSVAL(p,2,1000);                      /* size of bytes of returned data buffer */
2509   p += 4;
2510   pstrcpy(p,"");                         /* subformat */
2511   p = skip_string(p,1);
2512
2513   DEBUG(1,("Calling DosPrintJobEnum()...\n"));
2514   if( cli_call_api(PIPE_LANMAN, 0,PTR_DIFF(p,param), 0, 0,
2515                10, 4096,
2516                &rprcnt, &rdrcnt,
2517                param, NULL, NULL,
2518                &rparam, &rdata) )
2519     {
2520       int converter;
2521       result_code = SVAL(rparam,0);
2522       converter = SVAL(rparam,2);             /* conversion factor */
2523
2524       DEBUG(2,("returned %d bytes of parameters, %d bytes of data, %d records\n", rprcnt, rdrcnt, SVAL(rparam,4) ));
2525
2526       if (result_code == 0)                   /* if no error, */
2527         {
2528           int i;
2529           uint16 JobId;
2530           uint16 Priority;
2531           uint32 Size;
2532           char *UserName;
2533           char *JobName;
2534           char *JobTimeStr;
2535           time_t JobTime;
2536           fstring PrinterName;
2537              
2538           fstrcpy(PrinterName,strrchr(service,'\\')+1);       /* name of queue */
2539           strlower(PrinterName);                             /* in lower case */
2540
2541           p = rdata;                          /* received data */
2542           for( i = 0; i < SVAL(rparam,4); ++i)
2543             {
2544               JobId = SVAL(p,0);
2545               Priority = SVAL(p,2);
2546               UserName = fix_char_ptr(SVAL(p,4), converter, rdata, rdrcnt);
2547               strlower(UserName);
2548               Priority = SVAL(p,2);
2549               JobTime = make_unix_date3( p + 12);
2550               JobTimeStr = asctime(LocalTime( &JobTime));
2551               Size = IVAL(p,16);
2552               JobName = fix_char_ptr(SVAL(p,24), converter, rdata, rdrcnt);
2553             
2554
2555               printf("%s-%u    %s    priority %u   %s    %s   %u bytes\n", 
2556                 PrinterName, JobId, UserName,
2557                 Priority, JobTimeStr, JobName, Size);
2558    
2559 #if 0 /* DEBUG code */
2560               printf("Job Id: \"%u\"\n", SVAL(p,0));
2561               printf("Priority: \"%u\"\n", SVAL(p,2));
2562             
2563               printf("User Name: \"%s\"\n", fix_char_ptr(SVAL(p,4), converter, rdata, rdrcnt) );
2564               printf("Position: \"%u\"\n", SVAL(p,8));
2565               printf("Status: \"%u\"\n", SVAL(p,10));
2566             
2567               JobTime = make_unix_date3( p + 12);
2568               printf("Submitted: \"%s\"\n", asctime(LocalTime(&JobTime)));
2569               printf("date: \"%u\"\n", SVAL(p,12));
2570
2571               printf("Size: \"%u\"\n", SVAL(p,16));
2572               printf("Comment: \"%s\"\n", fix_char_ptr(SVAL(p,20), converter, rdata, rdrcnt) );
2573               printf("Document: \"%s\"\n", fix_char_ptr(SVAL(p,24), converter, rdata, rdrcnt) );
2574 #endif /* DEBUG CODE */ 
2575               p += 28;
2576             }
2577         }
2578     }
2579   else                  /* cli_call_api() failed */
2580     {
2581       printf("Failed, error = %d\n", result_code);
2582     }
2583
2584   /* If any parameters or data were returned, free the storage. */
2585   if(rparam) free(rparam);
2586   if(rdata) free(rdata);
2587
2588   return;
2589 }
2590
2591 /****************************************************************************
2592 show information about a print queue
2593 ****************************************************************************/
2594 static void cmd_qinfo(char *inbuf,char *outbuf )
2595 {
2596   char *rparam = NULL;
2597   char *rdata = NULL;
2598   char *p;
2599   int rdrcnt, rprcnt;
2600   pstring param;
2601   int result_code=0;
2602   
2603   bzero(param,sizeof(param));
2604
2605   p = param;
2606   SSVAL(p,0,70);                        /* API function number 70 (DosPrintQGetInfo) */
2607   p += 2;
2608   pstrcpy(p,"zWrLh");                   /* parameter description? */
2609   p = skip_string(p,1);
2610   pstrcpy(p,"zWWWWzzzzWWzzl");          /* returned data format */
2611   p = skip_string(p,1);
2612   pstrcpy(p,strrchr(service,'\\')+1);   /* name of queue */
2613   p = skip_string(p,1);
2614   SSVAL(p,0,3);                         /* API function level 3, just queue info, no job info */
2615   SSVAL(p,2,1000);                      /* size of bytes of returned data buffer */
2616   p += 4;
2617   pstrcpy(p,"");                                /* subformat */
2618   p = skip_string(p,1);
2619
2620   DEBUG(1,("Calling DosPrintQueueGetInfo()...\n"));
2621   if( cli_call_api(PIPE_LANMAN, 0,PTR_DIFF(p,param), 0, 0,
2622            10, 4096,
2623                &rprcnt, &rdrcnt,
2624                param, NULL, NULL,
2625                &rparam, &rdata) )
2626         {
2627         int converter;
2628         result_code = SVAL(rparam,0);
2629         converter = SVAL(rparam,2);             /* conversion factor */
2630
2631         DEBUG(2,("returned %d bytes of parameters, %d bytes of data, %d records\n", rprcnt, rdrcnt, SVAL(rparam,4) ));
2632
2633         if (result_code == 0)                   /* if no error, */
2634             {
2635             p = rdata;                          /* received data */
2636
2637             printf("Name: \"%s\"\n", fix_char_ptr(SVAL(p,0), converter, rdata, rdrcnt) );
2638             printf("Priority: %u\n", SVAL(p,4) );
2639             printf("Start time: %u\n", SVAL(p,6) );
2640             printf("Until time: %u\n", SVAL(p,8) );
2641             printf("Seperator file: \"%s\"\n", fix_char_ptr(SVAL(p,12), converter, rdata, rdrcnt) );
2642             printf("Print processor: \"%s\"\n", fix_char_ptr(SVAL(p,16), converter, rdata, rdrcnt) );
2643             printf("Parameters: \"%s\"\n", fix_char_ptr(SVAL(p,20), converter, rdata, rdrcnt) );
2644             printf("Comment: \"%s\"\n", fix_char_ptr(SVAL(p,24), converter, rdata, rdrcnt) );
2645             printf("Status: %u\n", SVAL(p,28) );
2646             printf("Jobs: %u\n", SVAL(p,30) );
2647             printf("Printers: \"%s\"\n", fix_char_ptr(SVAL(p,32), converter, rdata, rdrcnt) );
2648             printf("Drivername: \"%s\"\n", fix_char_ptr(SVAL(p,36), converter, rdata, rdrcnt) );
2649
2650             /* Dump the driver data */
2651             {
2652             int count, x, y, c;
2653             char *ddptr;
2654
2655             ddptr = rdata + SVAL(p,40) - converter;
2656             if( SVAL(p,40) == 0 ) {count = 0;} else {count = IVAL(ddptr,0);}
2657             printf("Driverdata: size=%d, version=%u\n", count, IVAL(ddptr,4) );
2658
2659             for(x=8; x < count; x+=16)
2660                 {
2661                 for(y=0; y < 16; y++)
2662                     {
2663                     if( (x+y) < count )
2664                         printf("%2.2X ", CVAL(ddptr,(x+y)) );
2665                     else
2666                         fputs("   ", stdout);
2667                     }
2668                 for(y=0; y < 16 && (x+y) < count; y++)
2669                     {
2670                     c = CVAL(ddptr,(x+y));
2671                     if(isprint(c))
2672                         fputc(c, stdout);
2673                     else
2674                         fputc('.', stdout);
2675                     }
2676                 fputc('\n', stdout);
2677                 }
2678             }
2679             
2680             }
2681         }
2682   else                  /* cli_call_api() failed */
2683         {
2684         printf("Failed, error = %d\n", result_code);
2685         }
2686
2687   /* If any parameters or data were returned, free the storage. */
2688   if(rparam) free(rparam);
2689   if(rdata) free(rdata);
2690
2691   return;
2692 }
2693
2694 /****************************************************************************
2695 delete some files
2696 ****************************************************************************/
2697 static void do_del(file_info *finfo)
2698 {
2699   char *p;
2700   char *inbuf,*outbuf;
2701   pstring mask;
2702
2703   pstrcpy(mask,cur_dir);
2704   pstrcat(mask,finfo->name);
2705
2706   if (finfo->mode & aDIR) 
2707     return;
2708
2709   inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
2710   outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
2711   
2712   if (!inbuf || !outbuf)
2713     {
2714       DEBUG(0,("out of memory\n"));
2715       return;
2716     }
2717
2718   bzero(outbuf,smb_size);
2719   set_message(outbuf,1,2 + strlen(mask),True);
2720   
2721   CVAL(outbuf,smb_com) = SMBunlink;
2722   SSVAL(outbuf,smb_tid,cnum);
2723   cli_setup_pkt(outbuf);
2724
2725   SSVAL(outbuf,smb_vwv0,0);
2726   
2727   p = smb_buf(outbuf);
2728   *p++ = 4;      
2729   pstrcpy(p,mask);
2730   
2731   send_smb(Client,outbuf);
2732   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2733   
2734   if (CVAL(inbuf,smb_rcls) != 0)
2735     DEBUG(0,("%s deleting remote file %s\n",smb_errstr(inbuf),CNV_LANG(mask)));
2736
2737   free(inbuf);free(outbuf);
2738   
2739 }
2740
2741 /****************************************************************************
2742 delete some files
2743 ****************************************************************************/
2744 static void cmd_del(char *inbuf,char *outbuf )
2745 {
2746   pstring mask;
2747   fstring buf;
2748   int attribute = aSYSTEM | aHIDDEN;
2749
2750   if (recurse)
2751     attribute |= aDIR;
2752   
2753   pstrcpy(mask,cur_dir);
2754     
2755   if (!next_token(NULL,buf,NULL,sizeof(buf)))
2756     {
2757       DEBUG(0,("del <filename>\n"));
2758       return;
2759     }
2760   pstrcat(mask,buf);
2761
2762   do_dir((char *)inbuf,(char *)outbuf,mask,attribute,do_del,False,False);
2763 }
2764
2765
2766 /****************************************************************************
2767 remove a directory
2768 ****************************************************************************/
2769 static void cmd_rmdir(char *inbuf,char *outbuf )
2770 {
2771   pstring mask;
2772   fstring buf;
2773   char *p;
2774   
2775   pstrcpy(mask,cur_dir);
2776   
2777   if (!next_token(NULL,buf,NULL,sizeof(buf)))
2778     {
2779       DEBUG(0,("rmdir <dirname>\n"));
2780       return;
2781     }
2782   pstrcat(mask,buf);
2783
2784   bzero(outbuf,smb_size);
2785   set_message(outbuf,0,2 + strlen(mask),True);
2786   
2787   CVAL(outbuf,smb_com) = SMBrmdir;
2788   SSVAL(outbuf,smb_tid,cnum);
2789   cli_setup_pkt(outbuf);
2790
2791   
2792   p = smb_buf(outbuf);
2793   *p++ = 4;      
2794   pstrcpy(p,mask);
2795   
2796   send_smb(Client,outbuf);
2797   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2798   
2799   if (CVAL(inbuf,smb_rcls) != 0)
2800     {
2801       DEBUG(0,("%s removing remote directory file %s\n",smb_errstr(inbuf),CNV_LANG(mask)));
2802       return;
2803     }
2804   
2805 }
2806
2807 /****************************************************************************
2808 rename some files
2809 ****************************************************************************/
2810 static void cmd_rename(char *inbuf,char *outbuf )
2811 {
2812   pstring src,dest;
2813   fstring buf,buf2;
2814   char *p;
2815   
2816   pstrcpy(src,cur_dir);
2817   pstrcpy(dest,cur_dir);
2818   
2819   if (!next_token(NULL,buf,NULL,sizeof(buf)) || 
2820       !next_token(NULL,buf2,NULL, sizeof(buf2)))
2821     {
2822       DEBUG(0,("rename <src> <dest>\n"));
2823       return;
2824     }
2825   pstrcat(src,buf);
2826   pstrcat(dest,buf2);
2827
2828   bzero(outbuf,smb_size);
2829   set_message(outbuf,1,4 + strlen(src) + strlen(dest),True);
2830   
2831   CVAL(outbuf,smb_com) = SMBmv;
2832   SSVAL(outbuf,smb_tid,cnum);
2833   SSVAL(outbuf,smb_vwv0,aHIDDEN | aDIR | aSYSTEM);
2834   cli_setup_pkt(outbuf);
2835   
2836   p = smb_buf(outbuf);
2837   *p++ = 4;      
2838   pstrcpy(p,src);
2839   p = skip_string(p,1);
2840   *p++ = 4;      
2841   pstrcpy(p,dest);
2842   
2843   send_smb(Client,outbuf);
2844   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2845   
2846   if (CVAL(inbuf,smb_rcls) != 0)
2847     {
2848       DEBUG(0,("%s renaming files\n",smb_errstr(inbuf)));
2849       return;
2850     }
2851   
2852 }
2853
2854
2855 /****************************************************************************
2856 toggle the prompt flag
2857 ****************************************************************************/
2858 static void cmd_prompt(char *dum_in, char *dum_out)
2859 {
2860   prompt = !prompt;
2861   DEBUG(2,("prompting is now %s\n",prompt?"on":"off"));
2862 }
2863
2864
2865 /****************************************************************************
2866 set the newer than time
2867 ****************************************************************************/
2868 static void cmd_newer(char *dum_in, char *dum_out)
2869 {
2870   fstring buf;
2871   BOOL ok;
2872   SMB_STRUCT_STAT sbuf;
2873
2874   ok = next_token(NULL,buf,NULL,sizeof(buf));
2875   if (ok && (dos_stat(buf,&sbuf) == 0))
2876     {
2877       newer_than = sbuf.st_mtime;
2878       DEBUG(1,("Getting files newer than %s",
2879                asctime(LocalTime(&newer_than))));
2880     }
2881   else
2882     newer_than = 0;
2883
2884   if (ok && newer_than == 0)
2885     DEBUG(0,("Error setting newer-than time\n"));
2886 }
2887
2888 /****************************************************************************
2889 set the archive level
2890 ****************************************************************************/
2891 static void cmd_archive(char *dum_in, char *dum_out)
2892 {
2893   fstring buf;
2894
2895   if (next_token(NULL,buf,NULL,sizeof(buf))) {
2896     archive_level = atoi(buf);
2897   } else
2898     DEBUG(0,("Archive level is %d\n",archive_level));
2899 }
2900
2901 /****************************************************************************
2902 toggle the lowercaseflag
2903 ****************************************************************************/
2904 static void cmd_lowercase(char *dum_in, char *dum_out)
2905 {
2906   lowercase = !lowercase;
2907   DEBUG(2,("filename lowercasing is now %s\n",lowercase?"on":"off"));
2908 }
2909
2910
2911
2912
2913 /****************************************************************************
2914 toggle the recurse flag
2915 ****************************************************************************/
2916 static void cmd_recurse(char *dum_in, char *dum_out)
2917 {
2918   recurse = !recurse;
2919   DEBUG(2,("directory recursion is now %s\n",recurse?"on":"off"));
2920 }
2921
2922 /****************************************************************************
2923 toggle the translate flag
2924 ****************************************************************************/
2925 static void cmd_translate(char *dum_in, char *dum_out)
2926 {
2927   translation = !translation;
2928   DEBUG(2,("CR/LF<->LF and print text translation now %s\n",
2929         translation?"on":"off"));
2930 }
2931
2932
2933 /****************************************************************************
2934 do a printmode command
2935 ****************************************************************************/
2936 static void cmd_printmode(char *dum_in, char *dum_out)
2937 {
2938   fstring buf;
2939   fstring mode;
2940
2941   if (next_token(NULL,buf,NULL,sizeof(buf)))
2942     {
2943       if (strequal(buf,"text"))
2944         printmode = 0;      
2945       else
2946         {
2947           if (strequal(buf,"graphics"))
2948             printmode = 1;
2949           else
2950             printmode = atoi(buf);
2951         }
2952     }
2953
2954   switch(printmode)
2955     {
2956     case 0: 
2957       fstrcpy(mode,"text");
2958       break;
2959     case 1: 
2960       fstrcpy(mode,"graphics");
2961       break;
2962     default: 
2963       slprintf(mode,sizeof(mode)-1,"%d",printmode);
2964       break;
2965     }
2966
2967   DEBUG(2,("the printmode is now %s\n",mode));
2968 }
2969
2970 /****************************************************************************
2971 do the lcd command
2972 ****************************************************************************/
2973 static void cmd_lcd(char *dum_in, char *dum_out)
2974 {
2975   fstring buf;
2976   pstring d;
2977
2978   if (next_token(NULL,buf,NULL,sizeof(buf)))
2979     dos_chdir(buf);
2980   DEBUG(2,("the local directory is now %s\n",GetWd(d)));
2981 }
2982
2983
2984 /****************************************************************************
2985 try and browse available connections on a host
2986 ****************************************************************************/
2987 static BOOL browse_host(BOOL sort)
2988 {
2989   char *rparam = NULL;
2990   char *rdata = NULL;
2991   char *p;
2992   int rdrcnt,rprcnt;
2993   pstring param;
2994   int count = -1;
2995
2996   /* now send a SMBtrans command with api RNetShareEnum */
2997   p = param;
2998   SSVAL(p,0,0); /* api number */
2999   p += 2;
3000   pstrcpy(p,"WrLeh");
3001   p = skip_string(p,1);
3002   pstrcpy(p,"B13BWz");
3003   p = skip_string(p,1);
3004   SSVAL(p,0,1);
3005   SSVAL(p,2,BUFFER_SIZE);
3006   p += 4;
3007
3008   if (cli_call_api(PIPE_LANMAN, 0,PTR_DIFF(p,param),0, 0,
3009              1024, BUFFER_SIZE,
3010              &rprcnt,&rdrcnt,
3011              param,NULL, NULL,
3012              &rparam,&rdata))
3013   {
3014     int res = SVAL(rparam,0);
3015     int converter=SVAL(rparam,2);
3016     int i;
3017     BOOL long_share_name=False;
3018       
3019     if (res == 0 || res == ERRmoredata)
3020     {
3021       count=SVAL(rparam,4);
3022       p = rdata;
3023
3024       if (count > 0)
3025       {
3026         printf("\n\tSharename      Type      Comment\n");
3027         printf("\t---------      ----      -------\n");
3028       }
3029
3030       if (sort)
3031         qsort(p,count,20,QSORT_CAST StrCaseCmp);
3032
3033       for (i=0;i<count;i++)
3034       {
3035         char *sname = p;
3036         int type = SVAL(p,14);
3037         int comment_offset = IVAL(p,16) & 0xFFFF;
3038         fstring typestr;
3039         *typestr=0;
3040
3041         switch (type)
3042         {
3043           case STYPE_DISKTREE:
3044             fstrcpy(typestr,"Disk"); break;
3045           case STYPE_PRINTQ:
3046             fstrcpy(typestr,"Printer"); break;        
3047           case STYPE_DEVICE:
3048             fstrcpy(typestr,"Device"); break;
3049           case STYPE_IPC:
3050             fstrcpy(typestr,"IPC"); break;      
3051         }
3052
3053         printf("\t%-15.15s%-10.10s%s\n",
3054                sname, typestr,
3055                comment_offset?rdata+comment_offset-converter:"");
3056           
3057         if (strlen(sname)>8) long_share_name=True;
3058           
3059         p += 20;
3060       }
3061
3062       if (long_share_name) {
3063         printf("\nNOTE: There were share names longer than 8 chars.\n\
3064 On older clients these may not be accessible or may give browsing errors\n");
3065       }
3066
3067       if(res == ERRmoredata)
3068         printf("\nNOTE: More data was available, the list was truncated.\n");
3069     }
3070   }
3071   
3072   if (rparam) free(rparam);
3073   if (rdata) free(rdata);
3074
3075   return(count>0);
3076 }
3077
3078
3079 /****************************************************************************
3080 get some server info
3081 ****************************************************************************/
3082 static void server_info(void)
3083 {
3084   char *rparam = NULL;
3085   char *rdata = NULL;
3086   char *p;
3087   int rdrcnt,rprcnt;
3088   pstring param;
3089
3090   bzero(param,sizeof(param));
3091
3092   p = param;
3093   SSVAL(p,0,63);                /* NetServerGetInfo()? */
3094   p += 2;
3095   pstrcpy(p,"WrLh");
3096   p = skip_string(p,1);
3097   pstrcpy(p,"zzzBBzz");
3098   p = skip_string(p,1);
3099   SSVAL(p,0,10); /* level 10 */
3100   SSVAL(p,2,1000);
3101   p += 6;
3102
3103   if (cli_call_api(PIPE_LANMAN, 0,PTR_DIFF(p,param),0, 0,
3104            6, 1000,
3105                &rprcnt,&rdrcnt,
3106                param,NULL, NULL,
3107                &rparam,&rdata))
3108     {
3109       int res = SVAL(rparam,0);
3110       int converter=SVAL(rparam,2);
3111
3112       if (res == 0)
3113         {
3114       p = rdata;
3115
3116       printf("\nServer=[%s] User=[%s] Workgroup=[%s] Domain=[%s]\n",
3117              rdata+SVAL(p,0)-converter,
3118              rdata+SVAL(p,4)-converter,
3119              rdata+SVAL(p,8)-converter,
3120              rdata+SVAL(p,14)-converter);
3121     }
3122     }
3123
3124   if (rparam) free(rparam);
3125   if (rdata) free(rdata);
3126
3127   return;
3128 }
3129
3130
3131 /****************************************************************************
3132 try and browse available connections on a host
3133 ****************************************************************************/
3134 static BOOL list_servers(char *wk_grp)
3135 {
3136   char *rparam = NULL;
3137   char *rdata = NULL;
3138   int rdrcnt,rprcnt;
3139   char *p,*svtype_p;
3140   pstring param;
3141   int uLevel = 1;
3142   int count = 0;
3143   BOOL ok = False;
3144   BOOL generic_request = False;
3145
3146
3147   if (strequal(wk_grp,"WORKGROUP")) {
3148     /* we won't specify a workgroup */
3149     generic_request = True;
3150   } 
3151
3152   /* now send a SMBtrans command with api ServerEnum? */
3153   p = param;
3154   SSVAL(p,0,0x68); /* api number */
3155   p += 2;
3156
3157   pstrcpy(p,generic_request?"WrLehDO":"WrLehDz");
3158   p = skip_string(p,1);
3159
3160   pstrcpy(p,"B16BBDz");
3161
3162   p = skip_string(p,1);
3163   SSVAL(p,0,uLevel);
3164   SSVAL(p,2,BUFFER_SIZE - SAFETY_MARGIN); /* buf length */
3165   p += 4;
3166
3167   svtype_p = p;
3168   p += 4;
3169
3170   if (!generic_request) {
3171     pstrcpy(p, wk_grp);
3172     p = skip_string(p,1);
3173   }
3174
3175   /* first ask for a list of servers in this workgroup */
3176   SIVAL(svtype_p,0,SV_TYPE_ALL);
3177
3178   if (cli_call_api(PIPE_LANMAN, 0,PTR_DIFF(p+4,param),0, 0,
3179            8, BUFFER_SIZE - SAFETY_MARGIN,
3180            &rprcnt,&rdrcnt,
3181            param,NULL, NULL,
3182            &rparam,&rdata))
3183   {
3184     int res = SVAL(rparam,0);
3185     int converter=SVAL(rparam,2);
3186     int i;
3187
3188     if (res == 0 || res == ERRmoredata) {       
3189       char *p2 = rdata;
3190       count=SVAL(rparam,4);
3191
3192       if (count > 0) {
3193         printf("\n\nThis machine has a browse list:\n");
3194         printf("\n\tServer               Comment\n");
3195         printf("\t---------            -------\n");
3196       }
3197         
3198       for (i=0;i<count;i++) {
3199         char *sname = p2;
3200         int comment_offset = IVAL(p2,22) & 0xFFFF;
3201         printf("\t%-16.16s     %s\n", sname,
3202                comment_offset?rdata+comment_offset-converter:"");
3203
3204         ok=True;
3205         p2 += 26;
3206       }
3207
3208       if(res == ERRmoredata)
3209         printf("\nNOTE: More data was available, the list was truncated.\n");
3210     }
3211   }
3212
3213   if (rparam) {free(rparam); rparam = NULL;}
3214   if (rdata) {free(rdata); rdata = NULL;}
3215
3216   /* now ask for a list of workgroups */
3217   SIVAL(svtype_p,0,SV_TYPE_DOMAIN_ENUM);
3218
3219   if (cli_call_api(PIPE_LANMAN, 0,PTR_DIFF(p+4,param),0, 0,
3220            8, BUFFER_SIZE - SAFETY_MARGIN,
3221            &rprcnt,&rdrcnt,
3222            param,NULL, NULL,
3223            &rparam,&rdata))
3224   {
3225     int res = SVAL(rparam,0);
3226     int converter=SVAL(rparam,2);
3227     int i;
3228
3229     if (res == 0 || res == ERRmoredata) {
3230       char *p2 = rdata;
3231       count=SVAL(rparam,4);
3232
3233       if (count > 0) {
3234         printf("\n\nThis machine has a workgroup list:\n");
3235         printf("\n\tWorkgroup            Master\n");
3236         printf("\t---------            -------\n");
3237       }
3238         
3239       for (i=0;i<count;i++) {
3240         char *sname = p2;
3241         int comment_offset = IVAL(p2,22) & 0xFFFF;
3242         printf("\t%-16.16s     %s\n", sname,
3243                comment_offset?rdata+comment_offset-converter:"");
3244           
3245         ok=True;
3246         p2 += 26;
3247       }
3248
3249       if(res == ERRmoredata)
3250         printf("\nNOTE: More data was available, the list was truncated.\n");
3251     }
3252   }
3253
3254   if (rparam) free(rparam);
3255   if (rdata) free(rdata);
3256
3257   return(ok);
3258 }
3259
3260
3261 /* Some constants for completing filename arguments */
3262
3263 #define COMPL_NONE        0          /* No completions */
3264 #define COMPL_REMOTE      1          /* Complete remote filename */
3265 #define COMPL_LOCAL       2          /* Complete local filename */
3266
3267 /* This defines the commands supported by this client */
3268 struct
3269 {
3270   char *name;
3271   void (*fn)(char *, char *);
3272   char *description;
3273   char compl_args[2];      /* Completion argument info */
3274 } commands[] = 
3275 {
3276   {"ls",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
3277   {"dir",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
3278   {"du",cmd_du,"<mask> computes the total size of the current directory",{COMPL_REMOTE,COMPL_NONE}},
3279   {"lcd",cmd_lcd,"[directory] change/report the local current working directory",{COMPL_LOCAL,COMPL_NONE}},
3280   {"cd",cmd_cd,"[directory] change/report the remote directory",{COMPL_REMOTE,COMPL_NONE}},
3281   {"pwd",cmd_pwd,"show current remote directory (same as 'cd' with no args)",{COMPL_NONE,COMPL_NONE}},
3282   {"get",cmd_get,"<remote name> [local name] get a file",{COMPL_REMOTE,COMPL_LOCAL}},
3283   {"mget",cmd_mget,"<mask> get all the matching files",{COMPL_REMOTE,COMPL_NONE}},
3284   {"put",cmd_put,"<local name> [remote name] put a file",{COMPL_LOCAL,COMPL_REMOTE}},
3285   {"mput",cmd_mput,"<mask> put all matching files",{COMPL_REMOTE,COMPL_NONE}},
3286   {"rename",cmd_rename,"<src> <dest> rename some files",{COMPL_REMOTE,COMPL_REMOTE}},
3287   {"more",cmd_more,"<remote name> view a remote file with your pager",{COMPL_REMOTE,COMPL_NONE}},  
3288   {"mask",cmd_select,"<mask> mask all filenames against this",{COMPL_REMOTE,COMPL_NONE}},
3289   {"del",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
3290   {"rm",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
3291   {"mkdir",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
3292   {"md",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
3293   {"rmdir",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
3294   {"rd",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
3295   {"pq",cmd_p_queue_4,"enumerate the print queue",{COMPL_NONE,COMPL_NONE}},
3296   {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput",{COMPL_NONE,COMPL_NONE}},  
3297   {"recurse",cmd_recurse,"toggle directory recursion for mget and mput",{COMPL_NONE,COMPL_NONE}},  
3298   {"translate",cmd_translate,"toggle text translation for printing",{COMPL_NONE,COMPL_NONE}},  
3299   {"lowercase",cmd_lowercase,"toggle lowercasing of filenames for get",{COMPL_NONE,COMPL_NONE}},  
3300   {"print",cmd_print,"<file name> print a file",{COMPL_NONE,COMPL_NONE}},
3301   {"printmode",cmd_printmode,"<graphics or text> set the print mode",{COMPL_NONE,COMPL_NONE}},
3302   {"queue",cmd_queue,"show the print queue",{COMPL_NONE,COMPL_NONE}},
3303   {"qinfo",cmd_qinfo,"show print queue information",{COMPL_NONE,COMPL_NONE}},
3304   {"cancel",cmd_cancel,"<jobid> cancel a print queue entry",{COMPL_NONE,COMPL_NONE}},
3305   {"quit",cli_send_logout,"logoff the server",{COMPL_NONE,COMPL_NONE}},
3306   {"q",cli_send_logout,"logoff the server",{COMPL_NONE,COMPL_NONE}},
3307   {"exit",cli_send_logout,"logoff the server",{COMPL_NONE,COMPL_NONE}},
3308   {"newer",cmd_newer,"<file> only mget files newer than the specified local file",{COMPL_LOCAL,COMPL_NONE}},
3309   {"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}},
3310   {"tar",cmd_tar,"tar <c|x>[IXFqbgNan] current directory to/from <file name>",{COMPL_NONE,COMPL_NONE}},
3311   {"blocksize",cmd_block,"blocksize <number> (default 20)",{COMPL_NONE,COMPL_NONE}},
3312   {"tarmode",cmd_tarmode,
3313      "<full|inc|reset|noreset> tar's behaviour towards archive bits",{COMPL_NONE,COMPL_NONE}},
3314   {"setmode",cmd_setmode,"filename <setmode string> change modes of file",{COMPL_REMOTE,COMPL_NONE}},
3315   {"help",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
3316   {"?",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
3317   {"!",NULL,"run a shell command on the local system",{COMPL_NONE,COMPL_NONE}},
3318   {"",NULL,NULL,{COMPL_NONE,COMPL_NONE}}
3319 };
3320
3321
3322 /*******************************************************************
3323   lookup a command string in the list of commands, including 
3324   abbreviations
3325   ******************************************************************/
3326 static int process_tok(fstring tok)
3327 {
3328   int i = 0, matches = 0;
3329   int cmd=0;
3330   int tok_len = strlen(tok);
3331   
3332   while (commands[i].fn != NULL)
3333     {
3334       if (strequal(commands[i].name,tok))
3335         {
3336           matches = 1;
3337           cmd = i;
3338           break;
3339         }
3340       else if (strnequal(commands[i].name, tok, tok_len))
3341         {
3342           matches++;
3343           cmd = i;
3344         }
3345       i++;
3346     }
3347   
3348   if (matches == 0)
3349     return(-1);
3350   else if (matches == 1)
3351     return(cmd);
3352   else
3353     return(-2);
3354 }
3355
3356 /****************************************************************************
3357 help
3358 ****************************************************************************/
3359 static void cmd_help(char *dum_in, char *dum_out)
3360 {
3361   int i=0,j;
3362   fstring buf;
3363
3364   if (next_token(NULL,buf,NULL,sizeof(buf)))
3365     {
3366       if ((i = process_tok(buf)) >= 0)
3367         DEBUG(0,("HELP %s:\n\t%s\n\n",commands[i].name,commands[i].description));                   
3368     }
3369   else
3370     while (commands[i].description)
3371       {
3372         for (j=0; commands[i].description && (j<5); j++) {
3373           DEBUG(0,("%-15s",commands[i].name));
3374           i++;
3375         }
3376         DEBUG(0,("\n"));
3377       }
3378 }
3379
3380 #ifndef HAVE_LIBREADLINE
3381
3382 /****************************************************************************
3383 wait for keyboard activity, swallowing network packets
3384 ****************************************************************************/
3385 static void wait_keyboard(char *buffer)
3386 {
3387   fd_set fds;
3388   struct timeval timeout;
3389   
3390   while (1) 
3391     {
3392       extern int Client;
3393       FD_ZERO(&fds);
3394       FD_SET(Client,&fds);
3395       FD_SET(fileno(stdin),&fds);
3396
3397       timeout.tv_sec = 20;
3398       timeout.tv_usec = 0;
3399       sys_select(MAX(Client,fileno(stdin))+1,&fds,&timeout);
3400       
3401       if (FD_ISSET(fileno(stdin),&fds))
3402         return;
3403
3404       /* We deliberately use receive_smb instead of
3405          client_receive_smb as we want to receive
3406          session keepalives and then drop them here.
3407        */
3408       if (FD_ISSET(Client,&fds))
3409         receive_smb(Client,buffer,0);
3410       
3411       chkpath("\\",False);
3412     }  
3413 }
3414
3415 #else /* if HAVE_LIBREADLINE */
3416
3417 /****************************************************************************
3418   completion routines for GNU Readline
3419 ****************************************************************************/
3420
3421 /* To avoid filename completion being activated when no valid
3422    completions are found, we assign this stub completion function
3423    to the rl_completion_entry_function variable. */
3424
3425 char *complete_cmd_null(char *text, int state)
3426 {
3427   return NULL;
3428 }
3429
3430 /* Argh.  This is starting to get ugly.  We need to be able to pass data
3431    back from the do_dir() iterator function. */
3432
3433 static int compl_state;
3434 static char *compl_text;
3435 static pstring result;
3436
3437 /* Iterator function for do_dir() */
3438
3439 void complete_process_file(file_info *f)
3440 {
3441   /* Do we have a partial match? */
3442
3443   if ((compl_state >= 0) && (strncmp(compl_text, f->name, 
3444                                      strlen(compl_text)) == 0)) {
3445
3446     /* Return filename if we have made enough matches */
3447
3448     if (compl_state == 0) {
3449       pstrcpy(result, f->name);
3450       compl_state = -1;
3451
3452       return;
3453     }
3454     compl_state--;
3455   }
3456 }
3457
3458 /* Complete a remote file */
3459
3460 char *complete_remote_file(char *text, int state)
3461 {
3462   char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
3463   char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
3464   int attribute = aDIR | aSYSTEM | aHIDDEN;
3465   pstring mask;
3466
3467   if ((InBuffer == NULL) || (OutBuffer == NULL)) 
3468     return(NULL);
3469
3470   /* Create dir mask */
3471
3472   pstrcpy(mask, cur_dir);
3473   pstrcat(mask, "*");
3474
3475   /* Initialise static vars for filename match */
3476
3477   compl_text = text;
3478   compl_state = state;
3479   result[0] = '\0';
3480
3481   /* Iterate over all files in directory */
3482
3483   do_dir(InBuffer, OutBuffer, mask, attribute, complete_process_file, False, 
3484          True);
3485
3486   /* Clean up */
3487
3488   free(InBuffer);
3489   free(OutBuffer);
3490
3491   /* Return matched filename */
3492
3493   if (result[0] != '\0') {
3494     return strdup(result);      /* Readline will dispose of strings */
3495   } else {
3496     return NULL;
3497   }
3498 }
3499
3500 /* Complete a smbclient command */
3501
3502 char *complete_cmd(char *text, int state)
3503 {
3504   static int cmd_index;
3505   char *name;
3506
3507   /* Initialise */
3508   
3509   if (state == 0) {
3510     cmd_index = 0;
3511   }
3512
3513   /* Return the next name which partially matches the list of commands */
3514
3515   while (strlen(name = commands[cmd_index++].name) > 0) {
3516     if (strncmp(name, text, strlen(text)) == 0) {
3517       return strdup(name);
3518     }
3519   }
3520
3521   return NULL;
3522 }
3523
3524 /* Main completion function for smbclient.  Work out which word we are
3525    trying to complete and call the appropriate function. */
3526
3527 char **completion_fn(char *text, int start, int end)
3528 {
3529   int i, num_words, cmd_index;
3530   char lastch = ' ';
3531
3532   /* If we are at the start of a word, we are completing a smbclient
3533      command. */
3534
3535   if (start == 0) {
3536     return completion_matches(text, complete_cmd);
3537   }
3538
3539   /* Count # of words in command */
3540
3541   num_words = 0;
3542   for (i = 0; i <= end; i++) {
3543     if ((rl_line_buffer[i] != ' ') && (lastch == ' '))
3544       num_words++;
3545     lastch = rl_line_buffer[i];
3546   }
3547
3548   if (rl_line_buffer[end] == ' ')
3549     num_words++;
3550
3551   /* Work out which command we are completing for */
3552
3553   for (cmd_index = 0; strcmp(commands[cmd_index].name, "") != 0; 
3554        cmd_index++) {
3555
3556     /* Check each command in array */
3557
3558     if (strncmp(rl_line_buffer, commands[cmd_index].name,
3559                 strlen(commands[cmd_index].name)) == 0) {
3560
3561       /* Call appropriate completion function */
3562
3563       if ((num_words == 2) || (num_words == 3)) {
3564         switch (commands[cmd_index].compl_args[num_words - 2]) {
3565
3566         case COMPL_REMOTE:
3567           return completion_matches(text, complete_remote_file);
3568           break;
3569
3570         case COMPL_LOCAL:
3571           return completion_matches(text, filename_completion_function);
3572           break;
3573
3574         default:
3575             /* An invalid completion type */
3576             break;
3577         }
3578       }
3579
3580       /* We're either completing an argument > 3 or found an invalid
3581          completion type.  Either way do nothing about it. */
3582
3583       break;
3584     }
3585   }
3586  
3587   return NULL;
3588 }
3589
3590 #endif /* HAVE_LIBREADLINE */
3591
3592 /****************************************************************************
3593   process commands from the client
3594 ****************************************************************************/
3595 static BOOL process(char *base_directory)
3596 {
3597   pstring line;
3598   char *cmd;
3599
3600   char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
3601   char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
3602
3603   if ((InBuffer == NULL) || (OutBuffer == NULL)) 
3604     return(False);
3605   
3606   bzero(OutBuffer,smb_size);
3607
3608   if (!cli_send_login(InBuffer,OutBuffer,True,True,NULL))
3609     return(False);
3610
3611   if (*base_directory) do_cd(base_directory);
3612
3613   cmd = cmdstr;
3614   if (cmd[0] != '\0') while (cmd[0] != '\0')
3615     {
3616       char *p;
3617       fstring tok;
3618       int i;
3619
3620       if ((p = strchr(cmd, ';')) == 0)
3621         {
3622           strncpy(line, cmd, 999);
3623           line[1000] = '\0';
3624           cmd += strlen(cmd);
3625         }
3626       else
3627         {
3628           if (p - cmd > 999) p = cmd + 999;
3629           strncpy(line, cmd, p - cmd);
3630           line[p - cmd] = '\0';
3631           cmd = p + 1;
3632         }
3633
3634       /* input language code to internal one */
3635       CNV_INPUT (line);
3636       
3637       /* and get the first part of the command */
3638       {
3639         char *ptr = line;
3640         if (!next_token(&ptr,tok,NULL,sizeof(tok))) continue;
3641       }
3642
3643       if ((i = process_tok(tok)) >= 0)
3644         commands[i].fn(InBuffer,OutBuffer);
3645       else if (i == -2)
3646         DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok)));
3647       else
3648         DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
3649     }
3650   else while (!feof(stdin))
3651     {
3652       fstring tok;
3653       int i;
3654
3655       bzero(OutBuffer,smb_size);
3656
3657 #ifdef HAVE_LIBREADLINE
3658
3659       {
3660         pstring promptline;
3661         
3662         /* Read input using GNU Readline */
3663
3664         slprintf(promptline, 
3665                  sizeof(promptline) - 1, "smb: %s> ", CNV_LANG(cur_dir));
3666         if (!readline(promptline))
3667           break;
3668
3669         /* Copy read line to samba buffer */
3670         
3671         pstrcpy(line, rl_line_buffer);
3672         pstrcat(line, "\n");
3673
3674         /* Add line to history */
3675
3676         if (strlen(line) > 0)
3677           add_history(line);
3678       }
3679
3680 #else
3681
3682       /* display a prompt */
3683       DEBUG(0,("smb: %s> ", CNV_LANG(cur_dir)));
3684       dbgflush( );
3685
3686       wait_keyboard(InBuffer);
3687   
3688       /* and get a response */
3689       if (!fgets(line,1000,stdin))
3690         break;
3691
3692 #endif
3693
3694       /* input language code to internal one */
3695       CNV_INPUT (line);
3696
3697       /* special case - first char is ! */
3698       if (*line == '!')
3699         {
3700           system(line + 1);
3701           continue;
3702         }
3703       
3704       /* and get the first part of the command */
3705       {
3706         char *ptr = line;
3707         if (!next_token(&ptr,tok,NULL,sizeof(tok))) continue;
3708       }
3709
3710       if ((i = process_tok(tok)) >= 0)
3711         commands[i].fn(InBuffer,OutBuffer);
3712       else if (i == -2)
3713         DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok)));
3714       else
3715         DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
3716     }
3717   
3718   cli_send_logout(InBuffer,OutBuffer);
3719   return(True);
3720 }
3721
3722 /****************************************************************************
3723 usage on the program
3724 ****************************************************************************/
3725 static void usage(char *pname)
3726 {
3727   DEBUG(0,("Usage: %s service <password> ", pname));
3728
3729   DEBUG(0,("\nVersion %s\n",VERSION));
3730   DEBUG(0,("\t-s smb.conf           pathname to smb.conf file\n"));
3731   DEBUG(0,("\t-B IP addr            broadcast IP address to use\n"));
3732   DEBUG(0,("\t-O socket_options     socket options to use\n"));
3733   DEBUG(0,("\t-R name resolve order use these name resolution services only\n"));
3734   DEBUG(0,("\t-M host               send a winpopup message to the host\n"));
3735   DEBUG(0,("\t-i scope              use this NetBIOS scope\n"));
3736   DEBUG(0,("\t-N                    don't ask for a password\n"));
3737   DEBUG(0,("\t-n netbios name.      Use this name as my netbios name\n"));
3738   DEBUG(0,("\t-d debuglevel         set the debuglevel\n"));
3739   DEBUG(0,("\t-P                    connect to service as a printer\n"));
3740   DEBUG(0,("\t-p port               connect to the specified port\n"));
3741   DEBUG(0,("\t-l log basename.      Basename for log/debug files\n"));
3742   DEBUG(0,("\t-h                    Print this help message.\n"));
3743   DEBUG(0,("\t-I dest IP            use this IP to connect to\n"));
3744   DEBUG(0,("\t-E                    write messages to stderr instead of stdout\n"));
3745   DEBUG(0,("\t-U username           set the network username\n"));
3746   DEBUG(0,("\t-L host               get a list of shares available on a host\n"));
3747   DEBUG(0,("\t-t terminal code      terminal i/o code {sjis|euc|jis7|jis8|junet|hex}\n"));
3748   DEBUG(0,("\t-m max protocol       set the max protocol level\n"));
3749   DEBUG(0,("\t-W workgroup          set the workgroup name\n"));
3750   DEBUG(0,("\t-T<c|x>IXFqgbNan      command line tar\n"));
3751   DEBUG(0,("\t-D directory          start from directory\n"));
3752   DEBUG(0,("\t-c command string     execute semicolon separated commands\n"));
3753   DEBUG(0,("\n"));
3754 }
3755
3756 /****************************************************************************
3757   main program
3758 ****************************************************************************/
3759  int main(int argc,char *argv[])
3760 {
3761   fstring base_directory;
3762   char *pname = argv[0];
3763   int port = SMB_PORT;
3764   int opt;
3765   extern FILE *dbf;
3766   extern char *optarg;
3767   extern int optind;
3768   pstring query_host;
3769   BOOL message = False;
3770   BOOL explicit_user = False;
3771   extern char tar_type;
3772   static pstring servicesf = CONFIGFILE;
3773   pstring term_code;
3774   pstring new_name_resolve_order;
3775   char *p;
3776
3777 #ifdef KANJI
3778   pstrcpy(term_code, KANJI);
3779 #else /* KANJI */
3780   *term_code = 0;
3781 #endif /* KANJI */
3782
3783   *query_host = 0;
3784   *base_directory = 0;
3785
3786   *new_name_resolve_order = 0;
3787
3788   DEBUGLEVEL = 2;
3789
3790   setup_logging(pname,True);
3791
3792   TimeInit();
3793   charset_initialise();
3794
3795   if(!get_myname(myhostname,NULL))
3796   {
3797     DEBUG(0,("Failed to get my hostname.\n"));
3798   }
3799
3800   in_client = True;   /* Make sure that we tell lp_load we are */
3801
3802   if (!lp_load(servicesf,True,False,False)) {
3803     fprintf(stderr, "Can't load %s - run testparm to debug it\n", servicesf);
3804   }
3805
3806   codepage_initialise(lp_client_code_page());
3807
3808   interpret_coding_system(term_code);
3809
3810 #ifdef WITH_SSL
3811   sslutil_init(0);
3812 #endif
3813
3814   pstrcpy(workgroup,lp_workgroup());
3815
3816   load_interfaces();
3817   pid = (uint16)getpid();
3818   vuid = (uint16)getuid();
3819   mid = pid + 100;
3820   myumask = umask(0);
3821   umask(myumask);
3822
3823   if (getenv("USER"))
3824   {
3825     pstrcpy(username,getenv("USER"));
3826
3827     /* modification to support userid%passwd syntax in the USER var
3828        25.Aug.97, jdblair@uab.edu */
3829
3830     if ((p=strchr(username,'%')))
3831     {
3832       *p = 0;
3833       pstrcpy(password,p+1);
3834       got_pass = True;
3835       memset(strchr(getenv("USER"),'%')+1,'X',strlen(password));
3836     }
3837     strupper(username);
3838   }
3839
3840  /* modification to support PASSWD environmental var
3841   25.Aug.97, jdblair@uab.edu */
3842
3843   if (getenv("PASSWD")) {
3844     pstrcpy(password,getenv("PASSWD"));
3845     got_pass = True;
3846   }
3847
3848   if (getenv("PASSWD_FD") || getenv("PASSWD_FILE")) {
3849     int fd = -1;
3850     BOOL close_it = False;
3851     pstring spec;
3852     char pass[128];
3853
3854     if ((p = getenv("PASSWD_FD")) != NULL) {
3855       pstrcpy(spec, "descriptor ");
3856       pstrcat(spec, p);
3857       sscanf(p, "%d", &fd);
3858       close_it = False;
3859     } else if ((p = getenv("PASSWD_FILE")) != NULL) {
3860       fd = open(p, O_RDONLY);
3861       pstrcpy(spec, p);
3862       if (fd < 0) {
3863         fprintf(stderr, "Error opening PASSWD_FILE %s: %s\n",
3864                 spec, strerror(errno));
3865         exit(1);
3866       }
3867       close_it = True;
3868     }
3869     for(p = pass, *p = '\0'; /* ensure that pass is null-terminated */
3870         p && p - pass < sizeof(pass);) {
3871       switch (read(fd, p, 1)) {
3872       case 1:
3873         if (*p != '\n' && *p != '\0') {
3874           *++p = '\0'; /* advance p, and null-terminate pass */
3875           break;
3876         }
3877       case 0:
3878         if (p - pass) {
3879           *p = '\0'; /* null-terminate it, just in case... */
3880           p = NULL; /* then force the loop condition to become false */
3881           break;
3882         } else {
3883           fprintf(stderr, "Error reading password from file %s: %s\n",
3884                   spec, "empty password\n");
3885           exit(1);
3886         }
3887
3888       default:
3889         fprintf(stderr, "Error reading password from file %s: %s\n",
3890                 spec, strerror(errno));
3891         exit(1);
3892       }
3893     }
3894     pstrcpy(password, pass);
3895     got_pass = True;
3896     if (close_it)
3897       close(fd);
3898   }
3899
3900   if (*username == 0 && getenv("LOGNAME"))
3901     {
3902       pstrcpy(username,getenv("LOGNAME"));
3903       strupper(username);
3904     }
3905
3906   if (*username == 0)
3907     {
3908       pstrcpy(username,"GUEST");
3909     }
3910
3911   if (argc < 2)
3912     {
3913       usage(pname);
3914       exit(1);
3915     }
3916   
3917   if (*argv[1] != '-')
3918     {
3919
3920       pstrcpy(service,argv[1]);  
3921       /* Convert any '/' characters in the service name to '\' characters */
3922       string_replace( service, '/','\\');
3923       argc--;
3924       argv++;
3925
3926       if (count_chars(service,'\\') < 3)
3927         {
3928           usage(pname);
3929           printf("\n%s: Not enough '\\' characters in service\n",service);
3930           exit(1);
3931         }
3932
3933 /*
3934       if (count_chars(service,'\\') > 3)
3935         {
3936           usage(pname);
3937           printf("\n%s: Too many '\\' characters in service\n",service);
3938           exit(1);
3939         }
3940         */
3941
3942       if (argc > 1 && (*argv[1] != '-'))
3943         {
3944           got_pass = True;
3945           pstrcpy(password,argv[1]);  
3946           memset(argv[1],'X',strlen(argv[1]));
3947           argc--;
3948           argv++;
3949         }
3950     }
3951
3952   while ((opt = 
3953           getopt(argc, argv,"s:B:O:R:M:i:Nn:d:Pp:l:hI:EU:L:t:m:W:T:D:c:")) != EOF)
3954         switch (opt)
3955         {
3956         case 's':
3957                 pstrcpy(servicesf, optarg);
3958                 break;
3959         case 'B':
3960                 iface_set_default(NULL,optarg,NULL);
3961                 break;
3962         case 'O':
3963                 pstrcpy(user_socket_options,optarg);
3964                 break;  
3965         case 'R':
3966                 pstrcpy(new_name_resolve_order, optarg);
3967                 break;
3968         case 'M':
3969                 name_type = 0x03; /* messages are sent to NetBIOS name type 0x3 */
3970                 pstrcpy(desthost,optarg);
3971                 strupper(desthost);
3972                 message = True;
3973                 break;
3974 #if 0 /* This option doesn't seem to do anything - JRA. */
3975         case 'S':
3976                 pstrcpy(desthost,optarg);
3977                 strupper(desthost);
3978                 nt_domain_logon = True;
3979                 break;
3980 #endif /* 0 */
3981         case 'i':
3982                 pstrcpy(scope,optarg);
3983                 break;
3984         case 'N':
3985                 got_pass = True;
3986                 no_pass = True;
3987                 break;
3988         case 'n':
3989                 pstrcpy(global_myname,optarg);
3990                 break;
3991         case 'd':
3992                 if (*optarg == 'A')
3993                         DEBUGLEVEL = 10000;
3994                 else
3995                         DEBUGLEVEL = atoi(optarg);
3996                 break;
3997         case 'P':
3998                 connect_as_printer = True;
3999                 break;
4000         case 'p':
4001                 port = atoi(optarg);
4002                 break;
4003         case 'l':
4004                 slprintf(debugf,sizeof(debugf)-1, "%s.client",optarg);
4005                 break;
4006         case 'h':
4007                 usage(pname);
4008                 exit(0);
4009                 break;
4010         case 'I':
4011                 {
4012                         dest_ip = *interpret_addr2(optarg);
4013                         if (zero_ip(dest_ip))
4014                                 exit(1);
4015                         have_ip = True;
4016                 }
4017                 break;
4018         case 'E':
4019                 dbf = stderr;
4020                 break;
4021         case 'U':
4022                 {
4023                         char *lp;
4024                         explicit_user = True;
4025                         pstrcpy(username,optarg);
4026                         if ((lp=strchr(username,'%')))
4027                         {
4028                                 *lp = 0;
4029                                 pstrcpy(password,lp+1);
4030                                 got_pass = True;
4031                                 memset(strchr(optarg,'%')+1,'X',strlen(password));
4032                         }
4033                 }
4034                 break;
4035         case 'L':
4036                 got_pass = True;
4037                 pstrcpy(query_host,optarg);
4038                 if(!explicit_user)
4039                         *username = '\0';
4040                 break;
4041         case 't':
4042                 pstrcpy(term_code, optarg);
4043                 break;
4044         case 'm':
4045                 max_protocol = interpret_protocol(optarg,max_protocol);
4046                 break;
4047         case 'W':
4048                 pstrcpy(workgroup,optarg);
4049                 break;
4050         case 'T':
4051                 if (!tar_parseargs(argc, argv, optarg, optind)) {
4052                         usage(pname);
4053                         exit(1);
4054                 }
4055                 break;
4056         case 'D':
4057                 pstrcpy(base_directory,optarg);
4058                 break;
4059         case 'c':
4060                 cmdstr = optarg;
4061                 got_pass = True;
4062                 break;
4063         default:
4064                 usage(pname);
4065                 exit(1);
4066         }
4067
4068   get_myname((*global_myname)?NULL:global_myname,NULL);  
4069   strupper(global_myname);
4070
4071   if(*new_name_resolve_order)
4072     lp_set_name_resolve_order(new_name_resolve_order);
4073
4074   if (!tar_type && !*query_host && !*service && !message)
4075     {
4076       usage(pname);
4077       exit(1);
4078     }
4079
4080 #ifdef HAVE_LIBREADLINE
4081
4082   /* Initialise GNU Readline */
4083   
4084   rl_readline_name = "smbclient";
4085   rl_attempted_completion_function = completion_fn;
4086   rl_completion_entry_function = (Function *)complete_cmd_null;
4087
4088   /* Initialise history list */
4089
4090   using_history();
4091
4092 #endif /* HAVE_LIBREADLINE */
4093
4094   DEBUG( 3, ( "Client started (version %s).\n", VERSION ) );
4095
4096   if (tar_type) {
4097     recurse=True;
4098
4099     if (cli_open_sockets(port)) {
4100         char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
4101         char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
4102         int ret;
4103
4104         if ((InBuffer == NULL) || (OutBuffer == NULL)) 
4105           return(1);
4106
4107         bzero(OutBuffer,smb_size);
4108         if (!cli_send_login(InBuffer,OutBuffer,True,True,NULL))
4109           return(False);
4110
4111         if (*base_directory) do_cd(base_directory);
4112
4113         ret=process_tar(InBuffer, OutBuffer);
4114
4115         cli_send_logout(InBuffer, OutBuffer);
4116         close_sockets();
4117         return(ret);
4118     } else
4119       return(1);
4120   }
4121
4122   if ((p=strchr(query_host,'#'))) {
4123           *p = 0;
4124           p++;
4125           sscanf(p, "%x", &name_type);
4126   }
4127   
4128 #if 0 /* This seemed to be used with the unknown -S option. JRA */
4129   if (*query_host && !nt_domain_logon)
4130 #else
4131   if (*query_host)
4132 #endif
4133     {
4134       int ret = 0;
4135       slprintf(service,sizeof(service)-1,
4136                "\\\\%s\\IPC$",query_host);
4137       strupper(service);
4138       connect_as_ipc = True;
4139       if (cli_open_sockets(port))
4140         {
4141 #if 0
4142           *username = 0;
4143 #endif
4144           if (!cli_send_login(NULL,NULL,True,True,NULL))
4145             return(1);
4146
4147           server_info();
4148           if (!browse_host(True)) {
4149             sleep(1);
4150             browse_host(True);
4151           }
4152           if (!list_servers(workgroup)) {
4153             sleep(1);
4154             list_servers(workgroup);
4155           }
4156
4157           cli_send_logout(NULL,NULL);
4158           close_sockets();
4159         }
4160
4161       return(ret);
4162     }
4163
4164   if (message)
4165     {
4166       int ret = 0;
4167       if (cli_open_sockets(port))
4168         {
4169           pstring inbuf,outbuf;
4170           bzero(outbuf,smb_size);
4171           if (!cli_send_session_request(inbuf,outbuf))
4172             return(1);
4173
4174           send_message(inbuf,outbuf);
4175
4176           close_sockets();
4177         }
4178
4179       return(ret);
4180     }
4181
4182   if (cli_open_sockets(port))
4183     {
4184       if (!process(base_directory))
4185         {
4186           close_sockets();
4187           return(1);
4188         }
4189       close_sockets();
4190     }
4191   else
4192     return(1);
4193
4194   return(0);
4195 }