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