charset.c: Split charset_initialise() into 2 - a charset_initialise() and
[kai/samba-autobuild/.git] / source3 / client / client.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    SMB client
5    Copyright (C) Andrew Tridgell 1994-1997
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 pstring service="";
35 pstring desthost="";
36 extern pstring myname;
37 pstring password = "";
38 pstring username="";
39 pstring workgroup="";
40 char *cmdstr="";
41 BOOL got_pass = False;
42 BOOL connect_as_printer = False;
43 BOOL connect_as_ipc = False;
44 extern struct in_addr ipzero;
45
46 char cryptkey[8];
47 BOOL doencrypt=False;
48
49 extern pstring user_socket_options;
50
51 /* 30 second timeout on most commands */
52 #define CLIENT_TIMEOUT (30*1000)
53 #define SHORT_TIMEOUT (5*1000)
54
55 /* value for unused fid field in trans2 secondary request */
56 #define FID_UNUSED (0xFFFF)
57
58 int name_type = 0x20;
59
60 int max_protocol = PROTOCOL_NT1;
61
62
63 time_t newer_than = 0;
64 int archive_level = 0;
65
66 extern pstring debugf;
67 extern int DEBUGLEVEL;
68
69 BOOL translation = False;
70
71
72 static BOOL send_trans_request(char *outbuf,int trans,
73                                char *name,int fid,int flags,
74                                char *data,char *param,uint16 *setup,
75                                int ldata,int lparam,int lsetup,
76                                int mdata,int mparam,int msetup);
77 static BOOL receive_trans_response(char *inbuf,int trans,
78                                    int *data_len,int *param_len,
79                                    char **data,char **param);
80 static int interpret_long_filename(int level,char *p,file_info *finfo);
81 static void dir_action(char *inbuf,char *outbuf,int attribute,file_info *finfo,BOOL recurse_dir,void (*fn)(),BOOL longdir);
82 static int interpret_short_filename(char *p,file_info *finfo);
83 static BOOL call_api(int prcnt,int drcnt,
84                      int mprcnt,int mdrcnt,
85                      int *rprcnt,int *rdrcnt,
86                      char *param,char *data,
87                      char **rparam,char **rdata);
88
89
90 /* clitar bits insert */
91 extern int blocksize;
92 extern BOOL tar_inc;
93 extern BOOL tar_reset;
94 /* clitar bits end */
95  
96
97 int cnum = 0;
98 int pid = 0;
99 int gid = 0;
100 int uid = 0;
101 int mid = 0;
102 int myumask = 0755;
103
104 int max_xmit = BUFFER_SIZE;
105
106 extern pstring scope;
107
108 BOOL prompt = True;
109
110 int printmode = 1;
111
112 BOOL recurse = False;
113 BOOL lowercase = False;
114
115 BOOL have_ip = False;
116
117 struct in_addr dest_ip;
118
119 #define SEPARATORS " \t\n\r"
120
121 BOOL abort_mget = True;
122
123 extern int Protocol;
124
125 BOOL readbraw_supported = False;
126 BOOL writebraw_supported = False;
127
128 pstring fileselection = "";
129
130 extern file_info def_finfo;
131
132 /* timing globals */
133 int get_total_size = 0;
134 int get_total_time_ms = 0;
135 int put_total_size = 0;
136 int put_total_time_ms = 0;
137
138
139 extern int Client;
140
141 #define USENMB
142
143 #ifdef KANJI
144 extern int coding_system;
145 #define CNV_LANG(s) (coding_system == DOSV_CODE?s:dos_to_unix(s, False))
146 #define CNV_INPUT(s) (coding_system == DOSV_CODE?s:unix_to_dos(s, True))
147 static BOOL
148 setup_term_code (char *code)
149 {
150     int new;
151     new = interpret_coding_system (code, UNKNOWN_CODE);
152     if (new != UNKNOWN_CODE) {
153         coding_system = new;
154         return True;
155     }
156     return False;
157 }
158 #else
159 #define CNV_LANG(s) dos2unix_format(s,False)
160 #define CNV_INPUT(s) unix2dos_format(s,True)
161 #endif
162
163 /****************************************************************************
164 setup basics in a outgoing packet
165 ****************************************************************************/
166 void setup_pkt(char *outbuf)
167 {
168   SSVAL(outbuf,smb_pid,pid);
169   SSVAL(outbuf,smb_uid,uid);
170   SSVAL(outbuf,smb_mid,mid);
171   if (Protocol > PROTOCOL_COREPLUS)
172     {
173       SCVAL(outbuf,smb_flg,0x8);
174       SSVAL(outbuf,smb_flg2,0x1);
175     }
176 }
177
178 /****************************************************************************
179 write to a local file with CR/LF->LF translation if appropriate. return the 
180 number taken from the buffer. This may not equal the number written.
181 ****************************************************************************/
182 static int writefile(int f, char *b, int n)
183 {
184   int i;
185
186   if (!translation)
187     return(write(f,b,n));
188   
189   i = 0;
190   while (i < n)
191     {
192       if (*b == '\r' && (i<(n-1)) && *(b+1) == '\n')
193         {
194           b++;i++;
195         }
196       if (write(f, b, 1) != 1)
197         {
198           break;
199         }
200       b++;
201       i++;
202     }
203   
204   return(i);
205 }
206
207 /****************************************************************************
208   read from a file with LF->CR/LF translation if appropriate. return the 
209   number read. read approx n bytes.
210 ****************************************************************************/
211 static int readfile(char *b, int size, int n, FILE *f)
212 {
213   int i;
214   int c;
215
216   if (!translation || (size != 1))
217     return(fread(b,size,n,f));
218   
219   i = 0;
220   while (i < n)
221     {
222       if ((c = getc(f)) == EOF)
223         {
224           break;
225         }
226       
227       if (c == '\n') /* change all LFs to CR/LF */
228         {
229           b[i++] = '\r';
230           n++;
231         }
232       
233       b[i++] = c;
234     }
235   
236   return(i);
237 }
238  
239
240 /****************************************************************************
241 read from a file with print translation. return the number read. read approx n
242 bytes.
243 ****************************************************************************/
244 static int printread(FILE *f,char *b,int n)
245 {
246   int i;
247
248   i = readfile(b,1, n-1,f);
249 #if FORMFEED
250   if (feof(f) && i>0)
251     b[i++] = '\014';
252 #endif
253
254   return(i);
255 }
256
257 /****************************************************************************
258 check for existance of a dir
259 ****************************************************************************/
260 static BOOL chkpath(char *path,BOOL report)
261 {
262   fstring path2;
263   pstring inbuf,outbuf;
264   char *p;
265
266   strcpy(path2,path);
267   trim_string(path2,NULL,"\\");
268   if (!*path2) *path2 = '\\';
269
270   bzero(outbuf,smb_size);
271   set_message(outbuf,0,4 + strlen(path2),True);
272   SCVAL(outbuf,smb_com,SMBchkpth);
273   SSVAL(outbuf,smb_tid,cnum);
274   setup_pkt(outbuf);
275
276   p = smb_buf(outbuf);
277   *p++ = 4;
278   strcpy(p,path2);
279
280   send_smb(Client,outbuf);
281   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
282
283   if (report && CVAL(inbuf,smb_rcls) != 0)
284     DEBUG(2,("chkpath: %s\n",smb_errstr(inbuf)));
285
286   return(CVAL(inbuf,smb_rcls) == 0);
287 }
288
289
290 /****************************************************************************
291 send a message
292 ****************************************************************************/
293 static void send_message(char *inbuf,char *outbuf)
294 {
295   int total_len = 0;
296
297   char *p;
298   int grp_id;
299
300   /* send a SMBsendstrt command */
301   bzero(outbuf,smb_size);
302   set_message(outbuf,0,0,True);
303   CVAL(outbuf,smb_com) = SMBsendstrt;
304   SSVAL(outbuf,smb_tid,cnum);
305
306   p = smb_buf(outbuf);
307   *p++ = 4;
308   strcpy(p,username);
309   p = skip_string(p,1);
310   *p++ = 4;
311   strcpy(p,desthost);
312   p = skip_string(p,1);
313
314   set_message(outbuf,0,PTR_DIFF(p,smb_buf(outbuf)),False);
315
316   send_smb(Client,outbuf);
317   
318
319   if (!receive_smb(Client,inbuf,SHORT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
320     {
321       printf("SMBsendstrt failed. (%s)\n",smb_errstr(inbuf));
322       return;
323     }
324
325   grp_id = SVAL(inbuf,smb_vwv0);
326
327   printf("Connected. Type your message, ending it with a Control-D\n");
328
329   while (!feof(stdin) && total_len < 1600)
330     {
331       int maxlen = MIN(1600 - total_len,127);
332       pstring msg;
333       int l=0;
334       int c;
335
336       bzero(msg,smb_size);
337
338       for (l=0;l<maxlen && (c=fgetc(stdin))!=EOF;l++)
339         {
340           if (c == '\n')
341             msg[l++] = '\r';
342           msg[l] = c;   
343         }
344
345       CVAL(outbuf,smb_com) = SMBsendtxt;
346
347       set_message(outbuf,1,l+3,True);
348
349       SSVAL(outbuf,smb_vwv0,grp_id);
350
351       p = smb_buf(outbuf);
352       *p = 1;
353       SSVAL(p,1,l);
354       memcpy(p+3,msg,l);
355
356       send_smb(Client,outbuf);
357       
358
359       if (!receive_smb(Client,inbuf,SHORT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
360         {
361           printf("SMBsendtxt failed (%s)\n",smb_errstr(inbuf));
362           return;
363         }      
364
365       total_len += l;
366     }
367
368   if (total_len >= 1600)
369     printf("the message was truncated to 1600 bytes ");
370   else
371     printf("sent %d bytes ",total_len);
372
373   printf("(status was %d-%d)\n",CVAL(inbuf,smb_rcls),SVAL(inbuf,smb_err));
374
375   CVAL(outbuf,smb_com) = SMBsendend;
376   set_message(outbuf,1,0,False);
377   SSVAL(outbuf,smb_vwv0,grp_id);
378
379   send_smb(Client,outbuf);
380   
381
382   if (!receive_smb(Client,inbuf,SHORT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
383     {
384       printf("SMBsendend failed (%s)\n",smb_errstr(inbuf));
385       return;
386     }      
387 }
388
389
390
391 /****************************************************************************
392 check the space on a device
393 ****************************************************************************/
394 static void do_dskattr(void)
395 {
396   pstring inbuf,outbuf;
397
398   bzero(outbuf,smb_size);
399   set_message(outbuf,0,0,True);
400   CVAL(outbuf,smb_com) = SMBdskattr;
401   SSVAL(outbuf,smb_tid,cnum);
402   setup_pkt(outbuf);
403
404   send_smb(Client,outbuf);
405   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
406
407   if (CVAL(inbuf,smb_rcls) != 0) 
408     DEBUG(0,("Error in dskattr: %s\n",smb_errstr(inbuf)));      
409
410   DEBUG(0,("\n\t\t%d blocks of size %d. %d blocks available\n",
411         SVAL(inbuf,smb_vwv0),
412         SVAL(inbuf,smb_vwv1)*SVAL(inbuf,smb_vwv2),
413         SVAL(inbuf,smb_vwv3)));
414 }
415
416 /****************************************************************************
417 show cd/pwd
418 ****************************************************************************/
419 static void cmd_pwd(void)
420 {
421   DEBUG(0,("Current directory is %s",CNV_LANG(service)));
422   DEBUG(0,("%s\n",CNV_LANG(cur_dir)));
423 }
424
425
426 /****************************************************************************
427 change directory - inner section
428 ****************************************************************************/
429 static void do_cd(char *newdir)
430 {
431   char *p = newdir;
432   pstring saved_dir;
433   pstring dname;
434       
435   /* Save the current directory in case the
436      new directory is invalid */
437   strcpy(saved_dir, cur_dir);
438   if (*p == '\\')
439     strcpy(cur_dir,p);
440   else
441     strcat(cur_dir,p);
442   if (*(cur_dir+strlen(cur_dir)-1) != '\\') {
443     strcat(cur_dir, "\\");
444   }
445   dos_clean_name(cur_dir);
446   strcpy(dname,cur_dir);
447   strcat(cur_dir,"\\");
448   dos_clean_name(cur_dir);
449
450   if (!strequal(cur_dir,"\\"))
451     if (!chkpath(dname,True))
452       strcpy(cur_dir,saved_dir);
453
454   strcpy(cd_path,cur_dir);
455 }
456
457 /****************************************************************************
458 change directory
459 ****************************************************************************/
460 static void cmd_cd(char *inbuf,char *outbuf)
461 {
462   fstring buf;
463
464   if (next_token(NULL,buf,NULL))
465     do_cd(buf);
466   else
467     DEBUG(0,("Current directory is %s\n",CNV_LANG(cur_dir)));
468 }
469
470
471 /****************************************************************************
472   display info about a file
473   ****************************************************************************/
474 static void display_finfo(file_info *finfo)
475 {
476   time_t t = finfo->mtime; /* the time is assumed to be passed as GMT */
477   DEBUG(0,("  %-30s%7.7s%10d  %s",
478            CNV_LANG(finfo->name),
479            attrib_string(finfo->mode),
480            finfo->size,
481            asctime(LocalTime(&t))));
482 }
483
484
485 /****************************************************************************
486   do a directory listing, calling fn on each file found. Use the TRANSACT2
487   call for long filenames
488   ****************************************************************************/
489 static int do_long_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir)
490 {
491   int max_matches = 512;
492   int info_level = Protocol<PROTOCOL_NT1?1:260; /* NT uses 260, OS/2 uses 2. Both accept 1. */
493   char *p;
494   pstring mask;
495   file_info finfo;
496   int i;
497   char *dirlist = NULL;
498   int dirlist_len = 0;
499   int total_received = 0;
500   BOOL First = True;
501   char *resp_data=NULL;
502   char *resp_param=NULL;
503   int resp_data_len = 0;
504   int resp_param_len=0;
505
506   int ff_resume_key = 0;
507   int ff_searchcount=0;
508   int ff_eos=0;
509   int ff_lastname=0;
510   int ff_dir_handle=0;
511   int loop_count = 0;
512
513   uint16 setup;
514   pstring param;
515
516   strcpy(mask,Mask);
517
518   while (ff_eos == 0)
519     {
520       loop_count++;
521       if (loop_count > 200)
522         {
523           DEBUG(0,("ERROR: Looping in FIND_NEXT??\n"));
524           break;
525         }
526
527       if (First)
528         {
529           setup = TRANSACT2_FINDFIRST;
530           SSVAL(param,0,attribute); /* attribute */
531           SSVAL(param,2,max_matches); /* max count */
532           SSVAL(param,4,8+4+2); /* resume required + close on end + continue */
533           SSVAL(param,6,info_level); 
534           SIVAL(param,8,0);
535           strcpy(param+12,mask);
536         }
537       else
538         {
539           setup = TRANSACT2_FINDNEXT;
540           SSVAL(param,0,ff_dir_handle);
541           SSVAL(param,2,max_matches); /* max count */
542           SSVAL(param,4,info_level); 
543           SIVAL(param,6,ff_resume_key); /* ff_resume_key */
544           SSVAL(param,10,8+4+2);        /* resume required + close on end + continue */
545           strcpy(param+12,mask);
546
547           DEBUG(5,("hand=0x%X resume=%d ff_lastname=%d mask=%s\n",
548                    ff_dir_handle,ff_resume_key,ff_lastname,mask));
549         }
550       /* ??? original code added 1 pad byte after param */
551
552       send_trans_request(outbuf,SMBtrans2,NULL,FID_UNUSED,0,
553                          NULL,param,&setup,
554                          0,12+strlen(mask)+1,1,
555                          BUFFER_SIZE,10,0);
556
557       if (!receive_trans_response(inbuf,SMBtrans2,
558                               &resp_data_len,&resp_param_len,
559                                   &resp_data,&resp_param))
560         {
561           DEBUG(3,("FIND%s gave %s\n",First?"FIRST":"NEXT",smb_errstr(inbuf)));
562           break;
563         }
564
565       /* parse out some important return info */
566       p = resp_param;
567       if (First)
568         {
569           ff_dir_handle = SVAL(p,0);
570           ff_searchcount = SVAL(p,2);
571           ff_eos = SVAL(p,4);
572           ff_lastname = SVAL(p,8);
573         }
574       else
575         {
576           ff_searchcount = SVAL(p,0);
577           ff_eos = SVAL(p,2);
578           ff_lastname = SVAL(p,6);
579         }
580
581       if (ff_searchcount == 0) 
582         break;
583
584       /* point to the data bytes */
585       p = resp_data;
586
587       /* we might need the lastname for continuations */
588       if (ff_lastname > 0)
589         {
590           switch(info_level)
591             {
592             case 260:
593               ff_resume_key =0;
594               StrnCpy(mask,p+ff_lastname,resp_data_len-ff_lastname);
595               /* strcpy(mask,p+ff_lastname+94); */
596               break;
597             case 1:
598               strcpy(mask,p + ff_lastname + 1);
599               ff_resume_key = 0;
600               break;
601             }
602         }
603       else
604         strcpy(mask,"");
605   
606       /* and add them to the dirlist pool */
607       dirlist = Realloc(dirlist,dirlist_len + resp_data_len);
608
609       if (!dirlist)
610         {
611           DEBUG(0,("Failed to expand dirlist\n"));
612           break;
613         }
614
615       /* put in a length for the last entry, to ensure we can chain entries 
616          into the next packet */
617       {
618         char *p2;
619         for (p2=p,i=0;i<(ff_searchcount-1);i++)
620           p2 += interpret_long_filename(info_level,p2,NULL);
621         SSVAL(p2,0,resp_data_len - PTR_DIFF(p2,p));
622       }
623
624       /* grab the data for later use */
625       memcpy(dirlist+dirlist_len,p,resp_data_len);
626       dirlist_len += resp_data_len;
627
628       total_received += ff_searchcount;
629
630       if (resp_data) free(resp_data); resp_data = NULL;
631       if (resp_param) free(resp_param); resp_param = NULL;
632
633       DEBUG(3,("received %d entries (eos=%d resume=%d)\n",
634                ff_searchcount,ff_eos,ff_resume_key));
635
636       First = False;
637     }
638
639   if (!fn)
640     for (p=dirlist,i=0;i<total_received;i++)
641       {
642         p += interpret_long_filename(info_level,p,&finfo);
643         display_finfo(&finfo);
644       }
645
646   for (p=dirlist,i=0;i<total_received;i++)
647     {
648       p += interpret_long_filename(info_level,p,&finfo);
649       dir_action(inbuf,outbuf,attribute,&finfo,recurse_dir,fn,True);
650     }
651
652   /* free up the dirlist buffer */
653   if (dirlist) free(dirlist);
654   return(total_received);
655 }
656
657
658 /****************************************************************************
659   do a directory listing, calling fn on each file found
660   ****************************************************************************/
661 static int do_short_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir)
662 {
663   char *p;
664   int received = 0;
665   BOOL first = True;
666   char status[21];
667   int num_asked = (max_xmit - 100)/DIR_STRUCT_SIZE;
668   int num_received = 0;
669   int i;
670   char *dirlist = NULL;
671   pstring mask;
672   file_info finfo;
673
674   finfo = def_finfo;
675
676   bzero(status,21);
677
678   strcpy(mask,Mask);
679   
680   while (1)
681     {
682       bzero(outbuf,smb_size);
683       if (first)        
684         set_message(outbuf,2,5 + strlen(mask),True);
685       else
686         set_message(outbuf,2,5 + 21,True);
687
688 #if FFIRST
689       if (Protocol >= PROTOCOL_LANMAN1)
690         CVAL(outbuf,smb_com) = SMBffirst;
691       else
692 #endif
693         CVAL(outbuf,smb_com) = SMBsearch;
694
695       SSVAL(outbuf,smb_tid,cnum);
696       setup_pkt(outbuf);
697
698       SSVAL(outbuf,smb_vwv0,num_asked);
699       SSVAL(outbuf,smb_vwv1,attribute);
700   
701       p = smb_buf(outbuf);
702       *p++ = 4;
703       
704       if (first)
705         strcpy(p,mask);
706       else
707         strcpy(p,"");
708       p += strlen(p) + 1;
709       
710       *p++ = 5;
711       if (first)
712         SSVAL(p,0,0);
713       else
714         {
715           SSVAL(p,0,21);
716           p += 2;
717           memcpy(p,status,21);
718         }
719
720       send_smb(Client,outbuf);
721       receive_smb(Client,inbuf,CLIENT_TIMEOUT);
722
723       received = SVAL(inbuf,smb_vwv0);
724
725       DEBUG(5,("dir received %d\n",received));
726
727       DEBUG(6,("errstr=%s\n",smb_errstr(inbuf)));
728
729       if (received <= 0) break;
730
731       first = False;
732
733       dirlist = Realloc(dirlist,(num_received + received)*DIR_STRUCT_SIZE);
734
735       if (!dirlist) 
736         return 0;
737
738       p = smb_buf(inbuf) + 3;
739
740       memcpy(dirlist+num_received*DIR_STRUCT_SIZE,
741              p,received*DIR_STRUCT_SIZE);
742
743       memcpy(status,p + ((received-1)*DIR_STRUCT_SIZE),21);
744
745       num_received += received;
746
747       if (CVAL(inbuf,smb_rcls) != 0) break;
748     }
749
750 #if FFIRST
751   if (!first && Protocol >= PROTOCOL_LANMAN1)
752     {
753       bzero(outbuf,smb_size);
754       CVAL(outbuf,smb_com) = SMBfclose;
755
756       SSVAL(outbuf,smb_tid,cnum);
757       setup_pkt(outbuf);
758
759       p = smb_buf(outbuf);
760       *p++ = 4;
761       
762       strcpy(p,"");
763       p += strlen(p) + 1;
764       
765       *p++ = 5;
766       SSVAL(p,0,21);
767       p += 2;
768       memcpy(p,status,21);
769
770       send_smb(Client,outbuf);
771       receive_smb(Client,inbuf,CLIENT_TIMEOUT);
772
773       if (CVAL(inbuf,smb_rcls) != 0) 
774         DEBUG(0,("Error closing search: %s\n",smb_errstr(inbuf)));      
775     }
776 #endif
777
778   if (!fn)
779     for (p=dirlist,i=0;i<num_received;i++)
780       {
781         p += interpret_short_filename(p,&finfo);
782         display_finfo(&finfo);
783       }
784
785   for (p=dirlist,i=0;i<num_received;i++)
786     {
787       p += interpret_short_filename(p,&finfo);
788       dir_action(inbuf,outbuf,attribute,&finfo,recurse_dir,fn,False);
789     }
790
791   if (dirlist) free(dirlist);
792   return(num_received);
793 }
794
795
796
797 /****************************************************************************
798   do a directory listing, calling fn on each file found
799   ****************************************************************************/
800 void do_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir)
801 {
802   DEBUG(5,("do_dir(%s,%x,%s)\n",Mask,attribute,BOOLSTR(recurse_dir)));
803   if (Protocol >= PROTOCOL_LANMAN2)
804     {
805       if (do_long_dir(inbuf,outbuf,Mask,attribute,fn,recurse_dir) > 0)
806         return;
807     }
808
809   expand_mask(Mask,False);
810   do_short_dir(inbuf,outbuf,Mask,attribute,fn,recurse_dir);
811   return;
812 }
813
814 /*******************************************************************
815   decide if a file should be operated on
816   ********************************************************************/
817 static BOOL do_this_one(file_info *finfo)
818 {
819   if (finfo->mode & aDIR) return(True);
820
821   if (newer_than && finfo->mtime < newer_than)
822     return(False);
823
824   if ((archive_level==1 || archive_level==2) && !(finfo->mode & aARCH))
825     return(False);
826
827   return(True);
828 }
829
830
831 /*****************************************************************************
832  Convert a character pointer in a call_api() response to a form we can use.
833  This function contains code to prevent core dumps if the server returns 
834  invalid data.
835 *****************************************************************************/
836 static char *fix_char_ptr(unsigned int datap, unsigned int converter, char *rdata, int rdrcnt)
837 {
838 if( datap == 0 )                /* turn NULL pointers */
839   {                             /* into zero length strings */
840   return "";
841   }
842 else
843   {
844   unsigned int offset = datap - converter;
845
846   if( offset >= rdrcnt )
847     {
848       DEBUG(1,("bad char ptr: datap=%u, converter=%u, rdata=%u, rdrcnt=%d>", datap, converter, (unsigned)rdata, rdrcnt));
849     return "<ERROR>";
850     }
851   else
852     {
853     return &rdata[offset];
854     }
855   }
856 }
857
858 /****************************************************************************
859 interpret a short filename structure
860 The length of the structure is returned
861 ****************************************************************************/
862 static int interpret_short_filename(char *p,file_info *finfo)
863 {
864   finfo->mode = CVAL(p,21);
865
866   /* this date is converted to GMT by make_unix_date */
867   finfo->ctime = make_unix_date(p+22);
868   finfo->mtime = finfo->atime = finfo->ctime;
869   finfo->size = IVAL(p,26);
870   strcpy(finfo->name,p+30);
871   
872   return(DIR_STRUCT_SIZE);
873 }
874
875 /****************************************************************************
876 interpret a long filename structure - this is mostly guesses at the moment
877 The length of the structure is returned
878 The structure of a long filename depends on the info level. 260 is used
879 by NT and 2 is used by OS/2
880 ****************************************************************************/
881 static int interpret_long_filename(int level,char *p,file_info *finfo)
882 {
883   if (finfo)
884     memcpy(finfo,&def_finfo,sizeof(*finfo));
885
886   switch (level)
887     {
888     case 1: /* OS/2 understands this */
889       if (finfo)
890         {
891           /* these dates are converted to GMT by make_unix_date */
892           finfo->ctime = make_unix_date2(p+4);
893           finfo->atime = make_unix_date2(p+8);
894           finfo->mtime = make_unix_date2(p+12);
895           finfo->size = IVAL(p,16);
896           finfo->mode = CVAL(p,24);
897           strcpy(finfo->name,p+27);
898         }
899       return(28 + CVAL(p,26));
900
901     case 2: /* this is what OS/2 uses mostly */
902       if (finfo)
903         {
904           /* these dates are converted to GMT by make_unix_date */
905           finfo->ctime = make_unix_date2(p+4);
906           finfo->atime = make_unix_date2(p+8);
907           finfo->mtime = make_unix_date2(p+12);
908           finfo->size = IVAL(p,16);
909           finfo->mode = CVAL(p,24);
910           strcpy(finfo->name,p+31);
911         }
912       return(32 + CVAL(p,30));
913
914       /* levels 3 and 4 are untested */
915     case 3:
916       if (finfo)
917         {
918           /* these dates are probably like the other ones */
919           finfo->ctime = make_unix_date2(p+8);
920           finfo->atime = make_unix_date2(p+12);
921           finfo->mtime = make_unix_date2(p+16);
922           finfo->size = IVAL(p,20);
923           finfo->mode = CVAL(p,28);
924           strcpy(finfo->name,p+33);
925         }
926       return(SVAL(p,4)+4);
927
928     case 4:
929       if (finfo)
930         {
931           /* these dates are probably like the other ones */
932           finfo->ctime = make_unix_date2(p+8);
933           finfo->atime = make_unix_date2(p+12);
934           finfo->mtime = make_unix_date2(p+16);
935           finfo->size = IVAL(p,20);
936           finfo->mode = CVAL(p,28);
937           strcpy(finfo->name,p+37);
938         }
939       return(SVAL(p,4)+4);
940
941     case 260: /* NT uses this, but also accepts 2 */
942       if (finfo)
943         {
944           int ret = SVAL(p,0);
945           int namelen;
946           p += 4; /* next entry offset */
947           p += 4; /* fileindex */
948
949           /* these dates appear to arrive in a weird way. It seems to
950              be localtime plus the serverzone given in the initial
951              connect. This is GMT when DST is not in effect and one
952              hour from GMT otherwise. Can this really be right??
953
954              I suppose this could be called kludge-GMT. Is is the GMT
955              you get by using the current DST setting on a different
956              localtime. It will be cheap to calculate, I suppose, as
957              no DST tables will be needed */
958
959           finfo->ctime = interpret_long_date(p); p += 8;
960           finfo->atime = interpret_long_date(p); p += 8;
961           finfo->mtime = interpret_long_date(p); p += 8; p += 8;
962           finfo->size = IVAL(p,0); p += 8;
963           p += 8; /* alloc size */
964           finfo->mode = CVAL(p,0); p += 4;
965           namelen = IVAL(p,0); p += 4;
966           p += 4; /* EA size */
967           p += 2; /* short name len? */
968           p += 24; /* short name? */      
969           StrnCpy(finfo->name,p,namelen);
970           return(ret);
971         }
972       return(SVAL(p,0));
973     }
974
975   DEBUG(1,("Unknown long filename format %d\n",level));
976   return(SVAL(p,0));
977 }
978
979
980
981
982 /****************************************************************************
983   act on the files in a dir listing
984   ****************************************************************************/
985 static void dir_action(char *inbuf,char *outbuf,int attribute,file_info *finfo,BOOL recurse_dir,void (*fn)(),BOOL longdir)
986 {
987
988   if (!((finfo->mode & aDIR) == 0 && *fileselection && 
989         !mask_match(finfo->name,fileselection,False,False)) &&
990       !(recurse_dir && (strequal(finfo->name,".") || 
991                         strequal(finfo->name,".."))))
992     {
993       if (recurse_dir && (finfo->mode & aDIR))
994         {
995           pstring mask2;
996           pstring sav_dir;
997           strcpy(sav_dir,cur_dir);
998           strcat(cur_dir,finfo->name);
999           strcat(cur_dir,"\\");
1000           strcpy(mask2,cur_dir);
1001
1002           if (!fn)
1003             DEBUG(0,("\n%s\n",CNV_LANG(cur_dir)));
1004
1005           strcat(mask2,"*");
1006
1007           if (longdir)
1008             do_long_dir(inbuf,outbuf,mask2,attribute,fn,True);      
1009           else
1010             do_dir(inbuf,outbuf,mask2,attribute,fn,True);
1011
1012           strcpy(cur_dir,sav_dir);
1013         }
1014       else
1015         {
1016           if (fn && do_this_one(finfo))
1017             fn(finfo);
1018         }
1019     }
1020 }
1021
1022
1023 /****************************************************************************
1024   receive a SMB trans or trans2 response allocating the necessary memory
1025   ****************************************************************************/
1026 static BOOL receive_trans_response(char *inbuf,int trans,
1027                                    int *data_len,int *param_len,
1028                                    char **data,char **param)
1029 {
1030   int total_data=0;
1031   int total_param=0;
1032   int this_data,this_param;
1033
1034   *data_len = *param_len = 0;
1035
1036   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1037   show_msg(inbuf);
1038
1039   /* sanity check */
1040   if (CVAL(inbuf,smb_com) != trans)
1041     {
1042       DEBUG(0,("Expected %s response, got command 0x%02x\n",
1043                trans==SMBtrans?"SMBtrans":"SMBtrans2", CVAL(inbuf,smb_com)));
1044       return(False);
1045     }
1046   if (CVAL(inbuf,smb_rcls) != 0)
1047     return(False);
1048
1049   /* parse out the lengths */
1050   total_data = SVAL(inbuf,smb_tdrcnt);
1051   total_param = SVAL(inbuf,smb_tprcnt);
1052
1053   /* allocate it */
1054   *data = Realloc(*data,total_data);
1055   *param = Realloc(*param,total_param);
1056
1057   while (1)
1058     {
1059       this_data = SVAL(inbuf,smb_drcnt);
1060       this_param = SVAL(inbuf,smb_prcnt);
1061       if (this_data)
1062         memcpy(*data + SVAL(inbuf,smb_drdisp),
1063                smb_base(inbuf) + SVAL(inbuf,smb_droff),
1064                this_data);
1065       if (this_param)
1066         memcpy(*param + SVAL(inbuf,smb_prdisp),
1067                smb_base(inbuf) + SVAL(inbuf,smb_proff),
1068                this_param);
1069       *data_len += this_data;
1070       *param_len += this_param;
1071
1072       /* parse out the total lengths again - they can shrink! */
1073       total_data = SVAL(inbuf,smb_tdrcnt);
1074       total_param = SVAL(inbuf,smb_tprcnt);
1075
1076       if (total_data <= *data_len && total_param <= *param_len)
1077         break;
1078
1079       receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1080       show_msg(inbuf);
1081
1082       /* sanity check */
1083       if (CVAL(inbuf,smb_com) != trans)
1084         {
1085           DEBUG(0,("Expected %s response, got command 0x%02x\n",
1086                    trans==SMBtrans?"SMBtrans":"SMBtrans2", CVAL(inbuf,smb_com)));
1087           return(False);
1088         }
1089       if (CVAL(inbuf,smb_rcls) != 0)
1090           return(False);
1091     }
1092   
1093   return(True);
1094 }
1095
1096
1097 /****************************************************************************
1098   get a directory listing
1099   ****************************************************************************/
1100 static void cmd_dir(char *inbuf,char *outbuf)
1101 {
1102   int attribute = aDIR | aSYSTEM | aHIDDEN;
1103   pstring mask;
1104   fstring buf;
1105   char *p=buf;
1106
1107   strcpy(mask,cur_dir);
1108   if(mask[strlen(mask)-1]!='\\')
1109     strcat(mask,"\\");
1110
1111   if (next_token(NULL,buf,NULL))
1112     {
1113       if (*p == '\\')
1114         strcpy(mask,p);
1115       else
1116         strcat(mask,p);
1117     }
1118   else {
1119     strcat(mask,"*");
1120   }
1121
1122   do_dir(inbuf,outbuf,mask,attribute,NULL,recurse);
1123
1124   do_dskattr();
1125 }
1126
1127
1128
1129 /****************************************************************************
1130   get a file from rname to lname
1131   ****************************************************************************/
1132 static void do_get(char *rname,char *lname,file_info *finfo1)
1133 {  
1134   int handle=0,fnum;
1135   uint32 nread=0;
1136   char *p;
1137   BOOL newhandle = False;
1138   char *inbuf,*outbuf;
1139   file_info finfo;
1140   BOOL close_done = False;
1141   BOOL ignore_close_error = False;
1142   char *dataptr=NULL;
1143   int datalen=0;
1144
1145   struct timeval tp_start;
1146   GetTimeOfDay(&tp_start);
1147
1148   if (finfo1) 
1149     finfo = *finfo1;
1150   else
1151     finfo = def_finfo;
1152
1153   if (lowercase)
1154     strlower(lname);
1155
1156
1157   inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1158   outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1159
1160   if (!inbuf || !outbuf)
1161     {
1162       DEBUG(0,("out of memory\n"));
1163       return;
1164     }
1165
1166   bzero(outbuf,smb_size);
1167   set_message(outbuf,15,1 + strlen(rname),True);
1168
1169   CVAL(outbuf,smb_com) = SMBopenX;
1170   SSVAL(outbuf,smb_tid,cnum);
1171   setup_pkt(outbuf);
1172
1173   SSVAL(outbuf,smb_vwv0,0xFF);
1174   SSVAL(outbuf,smb_vwv2,1);
1175   SSVAL(outbuf,smb_vwv3,(DENY_NONE<<4));
1176   SSVAL(outbuf,smb_vwv4,aSYSTEM | aHIDDEN);
1177   SSVAL(outbuf,smb_vwv5,aSYSTEM | aHIDDEN);
1178   SSVAL(outbuf,smb_vwv8,1);
1179   
1180   p = smb_buf(outbuf);
1181   strcpy(p,rname);
1182   p = skip_string(p,1);
1183
1184   /* do a chained openX with a readX? */
1185 #if 1
1186   if (finfo.size > 0)
1187     {
1188       DEBUG(3,("Chaining readX wth openX\n"));
1189       SSVAL(outbuf,smb_vwv0,SMBreadX);
1190       SSVAL(outbuf,smb_vwv1,smb_offset(p,outbuf));
1191       bzero(p,200);
1192       p -= smb_wct;
1193       SSVAL(p,smb_wct,10);
1194       SSVAL(p,smb_vwv0,0xFF);
1195       SSVAL(p,smb_vwv5,MIN(max_xmit-500,finfo.size));
1196       SSVAL(p,smb_vwv9,MIN(BUFFER_SIZE,finfo.size));
1197       smb_setlen(outbuf,smb_len(outbuf)+11*2+1);  
1198     }
1199 #endif
1200
1201   if(!strcmp(lname,"-"))
1202     handle = fileno(stdout);
1203   else 
1204     {
1205       handle = creat(lname,0644);
1206       newhandle = True;
1207     }
1208   if (handle < 0)
1209     {
1210       DEBUG(0,("Error opening local file %s\n",lname));
1211       free(inbuf);free(outbuf);
1212       return;
1213     }
1214
1215   send_smb(Client,outbuf);
1216   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1217
1218   if (CVAL(inbuf,smb_rcls) != 0)
1219     {
1220       if (CVAL(inbuf,smb_rcls) == ERRSRV &&
1221           SVAL(inbuf,smb_err) == ERRnoresource &&
1222           reopen_connection(inbuf,outbuf))
1223         {
1224           do_get(rname,lname,finfo1);
1225           return;
1226         }
1227       DEBUG(0,("%s opening remote file %s\n",smb_errstr(inbuf),CNV_LANG(rname)));
1228       if(newhandle)
1229         close(handle);
1230       free(inbuf);free(outbuf);
1231       return;
1232     }
1233
1234   strcpy(finfo.name,rname);
1235
1236   if (!finfo1)
1237     {
1238       finfo.mode = SVAL(inbuf,smb_vwv3);
1239       /* these times arrive as LOCAL time, using the DST offset 
1240          corresponding to that time, we convert them to GMT */
1241       finfo.mtime = make_unix_date3(inbuf+smb_vwv4);
1242       finfo.atime = finfo.ctime = finfo.mtime;
1243       finfo.size = IVAL(inbuf,smb_vwv6);
1244     }
1245
1246   DEBUG(3,("file %s attrib 0x%X\n",CNV_LANG(finfo.name),finfo.mode));
1247
1248   fnum = SVAL(inbuf,smb_vwv2);
1249
1250   /* we might have got some data from a chained readX */
1251   if (SVAL(inbuf,smb_vwv0) == SMBreadX)
1252     {
1253       p = (smb_base(inbuf)+SVAL(inbuf,smb_vwv1)) - smb_wct;
1254       datalen = SVAL(p,smb_vwv5);
1255       dataptr = smb_base(inbuf) + SVAL(p,smb_vwv6);
1256     }
1257   else
1258     {
1259       dataptr = NULL;
1260       datalen = 0;
1261     }
1262
1263
1264   DEBUG(2,("getting file %s of size %d bytes as %s ",
1265            CNV_LANG(finfo.name),
1266            finfo.size,
1267            lname));
1268
1269   while (nread < finfo.size && !close_done)
1270     {
1271       int method = -1;
1272       static BOOL can_chain_close = True;
1273
1274       p=NULL;
1275       
1276       DEBUG(3,("nread=%d max_xmit=%d fsize=%d\n",nread,max_xmit,finfo.size));
1277
1278       /* 3 possible read types. readbraw if a large block is required.
1279          readX + close if not much left and read if neither is supported */
1280
1281       /* we might have already read some data from a chained readX */
1282       if (dataptr && datalen>0)
1283         method=3;
1284
1285       /* if we can finish now then readX+close */
1286       if (method<0 && can_chain_close && (Protocol >= PROTOCOL_LANMAN1) && 
1287           ((finfo.size - nread) < 
1288            (max_xmit - (2*smb_size + 13*SIZEOFWORD + 300))))
1289         method = 0;
1290
1291       /* if we support readraw then use that */
1292       if (method<0 && readbraw_supported)
1293         method = 1;
1294
1295       /* if we can then use readX */
1296       if (method<0 && (Protocol >= PROTOCOL_LANMAN1))
1297         method = 2;
1298
1299       switch (method)
1300         {
1301           /* use readX */
1302         case 0:
1303         case 2:
1304           if (method == 0)
1305             close_done = True;
1306             
1307           /* use readX + close */
1308           bzero(outbuf,smb_size);
1309           set_message(outbuf,10,0,True);
1310           CVAL(outbuf,smb_com) = SMBreadX;
1311           SSVAL(outbuf,smb_tid,cnum);
1312           setup_pkt(outbuf);
1313           
1314           if (close_done)
1315             {
1316               CVAL(outbuf,smb_vwv0) = SMBclose;
1317               SSVAL(outbuf,smb_vwv1,smb_offset(smb_buf(outbuf),outbuf));
1318             }
1319           else
1320             CVAL(outbuf,smb_vwv0) = 0xFF;             
1321           
1322           SSVAL(outbuf,smb_vwv2,fnum);
1323           SIVAL(outbuf,smb_vwv3,nread);
1324           SSVAL(outbuf,smb_vwv5,MIN(max_xmit-200,finfo.size - nread));
1325           SSVAL(outbuf,smb_vwv6,0);
1326           SIVAL(outbuf,smb_vwv7,0);
1327           SSVAL(outbuf,smb_vwv9,MIN(BUFFER_SIZE,finfo.size-nread));
1328           
1329           if (close_done)
1330             {
1331               p = smb_buf(outbuf);
1332               bzero(p,9);
1333               
1334               CVAL(p,0) = 3;
1335               SSVAL(p,1,fnum);
1336               SIVALS(p,3,-1);
1337               
1338               /* now set the total packet length */
1339               smb_setlen(outbuf,smb_len(outbuf)+9);
1340             }
1341           
1342           send_smb(Client,outbuf);
1343           receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1344           
1345           if (CVAL(inbuf,smb_rcls) != 0)
1346             {
1347               DEBUG(0,("Error %s reading remote file\n",smb_errstr(inbuf)));
1348               break;
1349             }
1350           
1351           if (close_done &&
1352               SVAL(inbuf,smb_vwv0) != SMBclose)
1353             {
1354               /* NOTE: WfWg sometimes just ignores the chained
1355                  command! This seems to break the spec? */
1356               DEBUG(3,("Rejected chained close?\n"));
1357               close_done = False;
1358               can_chain_close = False;
1359               ignore_close_error = True;
1360             }
1361           
1362           datalen = SVAL(inbuf,smb_vwv5);
1363           dataptr = smb_base(inbuf) + SVAL(inbuf,smb_vwv6);
1364           break;
1365
1366           /* use readbraw */
1367         case 1:
1368           {
1369             static int readbraw_size = BUFFER_SIZE;
1370           
1371             extern int Client;
1372             bzero(outbuf,smb_size);
1373             set_message(outbuf,8,0,True);
1374             CVAL(outbuf,smb_com) = SMBreadbraw;
1375             SSVAL(outbuf,smb_tid,cnum);
1376             setup_pkt(outbuf);
1377             SSVAL(outbuf,smb_vwv0,fnum);
1378             SIVAL(outbuf,smb_vwv1,nread);
1379             SSVAL(outbuf,smb_vwv3,MIN(finfo.size-nread,readbraw_size));
1380             SSVAL(outbuf,smb_vwv4,0);
1381             SIVALS(outbuf,smb_vwv5,-1);
1382             send_smb(Client,outbuf);
1383
1384             /* Now read the raw data into the buffer and write it */      
1385             if(read_smb_length(Client,inbuf,0) == -1) {
1386               DEBUG(0,("Failed to read length in readbraw\n"));     
1387               exit(1);
1388             }
1389             
1390             /* Even though this is not an smb message, smb_len
1391                returns the generic length of an smb message */
1392             datalen = smb_len(inbuf);
1393
1394             if (datalen == 0)
1395               {
1396                 /* we got a readbraw error */
1397                 DEBUG(4,("readbraw error - reducing size\n"));
1398                 readbraw_size = (readbraw_size * 9) / 10;
1399                 
1400                 if (readbraw_size < max_xmit)
1401                   {
1402                     DEBUG(0,("disabling readbraw\n"));
1403                     readbraw_supported = False;
1404                   }
1405                 
1406                 dataptr=NULL;
1407                 continue;
1408               }
1409
1410             if(read_data(Client,inbuf,datalen) != datalen) {
1411               DEBUG(0,("Failed to read data in readbraw\n"));
1412               exit(1);
1413             }
1414             dataptr = inbuf;
1415           }
1416           break;
1417
1418         case 3:
1419           /* we've already read some data with a chained readX */
1420           break;
1421
1422         default:
1423           /* use plain read */
1424           bzero(outbuf,smb_size);
1425           set_message(outbuf,5,0,True);
1426           CVAL(outbuf,smb_com) = SMBread;
1427           SSVAL(outbuf,smb_tid,cnum);
1428           setup_pkt(outbuf);
1429
1430           SSVAL(outbuf,smb_vwv0,fnum);
1431           SSVAL(outbuf,smb_vwv1,MIN(max_xmit-200,finfo.size - nread));
1432           SIVAL(outbuf,smb_vwv2,nread);
1433           SSVAL(outbuf,smb_vwv4,finfo.size - nread);
1434
1435           send_smb(Client,outbuf);
1436           receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1437
1438           if (CVAL(inbuf,smb_rcls) != 0)
1439             {
1440               DEBUG(0,("Error %s reading remote file\n",smb_errstr(inbuf)));
1441               break;
1442             }
1443
1444           datalen = SVAL(inbuf,smb_vwv0);
1445           dataptr = smb_buf(inbuf) + 3;
1446           break;
1447         }
1448  
1449       if (writefile(handle,dataptr,datalen) != datalen)
1450         {
1451           DEBUG(0,("Error writing local file\n"));
1452           break;
1453         }
1454       
1455       nread += datalen;
1456       if (datalen == 0) 
1457         {
1458           DEBUG(0,("Error reading file %s. Got %d bytes\n",CNV_LANG(rname),nread));
1459           break;
1460         }
1461
1462       dataptr=NULL;
1463       datalen=0;
1464     }
1465
1466
1467
1468   if (!close_done)
1469     {
1470       bzero(outbuf,smb_size);
1471       set_message(outbuf,3,0,True);
1472       CVAL(outbuf,smb_com) = SMBclose;
1473       SSVAL(outbuf,smb_tid,cnum);
1474       setup_pkt(outbuf);
1475       
1476       SSVAL(outbuf,smb_vwv0,fnum);
1477       SIVALS(outbuf,smb_vwv1,-1);
1478       
1479       send_smb(Client,outbuf);
1480       receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1481       
1482       if (!ignore_close_error && CVAL(inbuf,smb_rcls) != 0)
1483         {
1484           DEBUG(0,("Error %s closing remote file\n",smb_errstr(inbuf)));
1485           if(newhandle)
1486             close(handle);
1487           free(inbuf);free(outbuf);
1488           return;
1489         }
1490     }
1491
1492   if(newhandle)
1493     close(handle);
1494
1495   if (archive_level >= 2 && (finfo.mode & aARCH)) {
1496     bzero(outbuf,smb_size);
1497     set_message(outbuf,8,strlen(rname)+4,True);
1498     CVAL(outbuf,smb_com) = SMBsetatr;
1499     SSVAL(outbuf,smb_tid,cnum);
1500     setup_pkt(outbuf);
1501     SSVAL(outbuf,smb_vwv0,finfo.mode & ~(aARCH));
1502     SIVALS(outbuf,smb_vwv1,0);
1503     p = smb_buf(outbuf);
1504     *p++ = 4;
1505     strcpy(p,rname);
1506     p += strlen(p)+1;
1507     *p++ = 4;
1508     *p = 0;
1509     send_smb(Client,outbuf);
1510     receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1511   }
1512
1513   {
1514     struct timeval tp_end;
1515     int this_time;
1516
1517     GetTimeOfDay(&tp_end);
1518     this_time = 
1519       (tp_end.tv_sec - tp_start.tv_sec)*1000 +
1520         (tp_end.tv_usec - tp_start.tv_usec)/1000;
1521     get_total_time_ms += this_time;
1522     get_total_size += finfo.size;
1523
1524     DEBUG(1,("(%g kb/s) (average %g kb/s)\n",
1525              finfo.size / (1.024*this_time + 1.0e-4),
1526              get_total_size / (1.024*get_total_time_ms)));
1527   }
1528
1529   free(inbuf);free(outbuf);
1530 }
1531
1532
1533 /****************************************************************************
1534   get a file
1535   ****************************************************************************/
1536 static void cmd_get(void)
1537 {
1538   pstring lname;
1539   pstring rname;
1540   char *p;
1541
1542   strcpy(rname,cur_dir);
1543   strcat(rname,"\\");
1544
1545   p = rname + strlen(rname);
1546
1547   if (!next_token(NULL,p,NULL)) {
1548     DEBUG(0,("get <filename>\n"));
1549     return;
1550   }
1551   strcpy(lname,p);
1552   dos_clean_name(rname);
1553     
1554   next_token(NULL,lname,NULL);
1555
1556   do_get(rname,lname,NULL);
1557 }
1558
1559
1560 /****************************************************************************
1561   do a mget operation on one file
1562   ****************************************************************************/
1563 static void do_mget(file_info *finfo)
1564 {
1565   pstring rname;
1566   pstring quest;
1567
1568   if (strequal(finfo->name,".") || strequal(finfo->name,".."))
1569     return;
1570
1571   if (abort_mget)
1572     {
1573       DEBUG(0,("mget aborted\n"));
1574       return;
1575     }
1576
1577   if (finfo->mode & aDIR)
1578     sprintf(quest,"Get directory %s? ",CNV_LANG(finfo->name));
1579   else
1580     sprintf(quest,"Get file %s? ",CNV_LANG(finfo->name));
1581
1582   if (prompt && !yesno(quest)) return;
1583
1584   if (finfo->mode & aDIR)
1585     {
1586       pstring saved_curdir;
1587       pstring mget_mask;
1588       char *inbuf,*outbuf;
1589
1590       inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1591       outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1592
1593       if (!inbuf || !outbuf)
1594         {
1595           DEBUG(0,("out of memory\n"));
1596           return;
1597         }
1598
1599       strcpy(saved_curdir,cur_dir);
1600
1601       strcat(cur_dir,finfo->name);
1602       strcat(cur_dir,"\\");
1603
1604       unix_format(finfo->name);
1605       {
1606         if (lowercase)
1607           strlower(finfo->name);
1608
1609         if (!directory_exist(finfo->name,NULL) && 
1610             sys_mkdir(finfo->name,0777) != 0) 
1611           {
1612             DEBUG(0,("failed to create directory %s\n",CNV_LANG(finfo->name)));
1613             strcpy(cur_dir,saved_curdir);
1614             free(inbuf);free(outbuf);
1615             return;
1616           }
1617
1618         if (sys_chdir(finfo->name) != 0)
1619           {
1620             DEBUG(0,("failed to chdir to directory %s\n",CNV_LANG(finfo->name)));
1621             strcpy(cur_dir,saved_curdir);
1622             free(inbuf);free(outbuf);
1623             return;
1624           }
1625       }       
1626
1627       strcpy(mget_mask,cur_dir);
1628       strcat(mget_mask,"*");
1629       
1630       do_dir((char *)inbuf,(char *)outbuf,
1631              mget_mask,aSYSTEM | aHIDDEN | aDIR,do_mget,False);
1632       chdir("..");
1633       strcpy(cur_dir,saved_curdir);
1634       free(inbuf);free(outbuf);
1635     }
1636   else
1637     {
1638       strcpy(rname,cur_dir);
1639       strcat(rname,finfo->name);
1640       do_get(rname,finfo->name,finfo);
1641     }
1642 }
1643
1644 /****************************************************************************
1645 view the file using the pager
1646 ****************************************************************************/
1647 static void cmd_more(void)
1648 {
1649   fstring rname,lname,tmpname,pager_cmd;
1650   char *pager;
1651
1652   strcpy(rname,cur_dir);
1653   strcat(rname,"\\");
1654   sprintf(tmpname,"%s/smbmore.%d",tmpdir(),(int)getpid());
1655   strcpy(lname,tmpname);
1656
1657   if (!next_token(NULL,rname+strlen(rname),NULL)) {
1658     DEBUG(0,("more <filename>\n"));
1659     return;
1660   }
1661   dos_clean_name(rname);
1662
1663   do_get(rname,lname,NULL);
1664
1665   pager=getenv("PAGER");
1666   sprintf(pager_cmd,"%s %s",(pager? pager:PAGER), tmpname);
1667   system(pager_cmd);
1668   unlink(tmpname);
1669 }
1670
1671
1672
1673 /****************************************************************************
1674 do a mget command
1675 ****************************************************************************/
1676 static void cmd_mget(char *inbuf,char *outbuf)
1677 {
1678   int attribute = aSYSTEM | aHIDDEN;
1679   pstring mget_mask;
1680   fstring buf;
1681   char *p=buf;
1682
1683   *mget_mask = 0;
1684
1685   if (recurse)
1686     attribute |= aDIR;
1687
1688   abort_mget = False;
1689
1690   while (next_token(NULL,p,NULL))
1691     {
1692       strcpy(mget_mask,cur_dir);
1693       if(mget_mask[strlen(mget_mask)-1]!='\\')
1694         strcat(mget_mask,"\\");
1695
1696       if (*p == '\\')
1697         strcpy(mget_mask,p);
1698       else
1699         strcat(mget_mask,p);
1700       do_dir((char *)inbuf,(char *)outbuf,mget_mask,attribute,do_mget,False);
1701     }
1702
1703   if (! *mget_mask)
1704     {
1705       strcpy(mget_mask,cur_dir);
1706       if(mget_mask[strlen(mget_mask)-1]!='\\')
1707         strcat(mget_mask,"\\");
1708       strcat(mget_mask,"*");
1709       do_dir((char *)inbuf,(char *)outbuf,mget_mask,attribute,do_mget,False);
1710     }
1711 }
1712
1713 /****************************************************************************
1714 make a directory of name "name"
1715 ****************************************************************************/
1716 static BOOL do_mkdir(char *name)
1717 {
1718   char *p;
1719   char *inbuf,*outbuf;
1720
1721   inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1722   outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1723
1724   if (!inbuf || !outbuf)
1725     {
1726       DEBUG(0,("out of memory\n"));
1727       return False;
1728     }
1729
1730   bzero(outbuf,smb_size);
1731   set_message(outbuf,0,2 + strlen(name),True);
1732   
1733   CVAL(outbuf,smb_com) = SMBmkdir;
1734   SSVAL(outbuf,smb_tid,cnum);
1735   setup_pkt(outbuf);
1736
1737   
1738   p = smb_buf(outbuf);
1739   *p++ = 4;      
1740   strcpy(p,name);
1741   
1742   send_smb(Client,outbuf);
1743   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1744   
1745   if (CVAL(inbuf,smb_rcls) != 0)
1746     {
1747       DEBUG(0,("%s making remote directory %s\n",
1748                smb_errstr(inbuf),CNV_LANG(name)));
1749
1750       free(inbuf);free(outbuf);
1751       return(False);
1752     }
1753
1754   free(inbuf);free(outbuf);
1755   return(True);
1756 }
1757
1758
1759 /****************************************************************************
1760   make a directory
1761   ****************************************************************************/
1762 static void cmd_mkdir(char *inbuf,char *outbuf)
1763 {
1764   pstring mask;
1765   fstring buf;
1766   char *p=buf;
1767   
1768   strcpy(mask,cur_dir);
1769
1770   if (!next_token(NULL,p,NULL))
1771     {
1772       if (!recurse)
1773         DEBUG(0,("mkdir <dirname>\n"));
1774       return;
1775     }
1776   strcat(mask,p);
1777
1778   if (recurse)
1779     {
1780       pstring ddir;
1781       pstring ddir2;
1782       *ddir2 = 0;
1783
1784       strcpy(ddir,mask);
1785       trim_string(ddir,".",NULL);
1786       p = strtok(ddir,"/\\");
1787       while (p)
1788         {
1789           strcat(ddir2,p);
1790           if (!chkpath(ddir2,False))
1791             {             
1792               do_mkdir(ddir2);
1793             }
1794           strcat(ddir2,"\\");
1795           p = strtok(NULL,"/\\");
1796         }        
1797     }
1798   else
1799     do_mkdir(mask);
1800 }
1801
1802
1803 /*******************************************************************
1804   write to a file using writebraw
1805   ********************************************************************/
1806 static int smb_writeraw(char *outbuf,int fnum,int pos,char *buf,int n)
1807 {
1808   extern int Client;
1809   pstring inbuf;
1810
1811   bzero(outbuf,smb_size);
1812   bzero(inbuf,smb_size);  
1813   set_message(outbuf,Protocol>PROTOCOL_COREPLUS?12:10,0,True);
1814
1815   CVAL(outbuf,smb_com) = SMBwritebraw;
1816   SSVAL(outbuf,smb_tid,cnum);
1817   setup_pkt(outbuf);
1818
1819   SSVAL(outbuf,smb_vwv0,fnum);
1820   SSVAL(outbuf,smb_vwv1,n);
1821   SIVAL(outbuf,smb_vwv3,pos);
1822   SSVAL(outbuf,smb_vwv7,1);
1823
1824   send_smb(Client,outbuf);
1825   
1826   if (!receive_smb(Client,inbuf,CLIENT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
1827     return(0);
1828
1829   _smb_setlen(buf-4,n);         /* HACK! XXXX */
1830
1831   if (write_socket(Client,buf-4,n+4) != n+4)
1832     return(0);
1833
1834   if (!receive_smb(Client,inbuf,CLIENT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0) {
1835     DEBUG(0,("Error writing remote file (2)\n"));
1836     return(0);
1837   }
1838   return(SVAL(inbuf,smb_vwv0));
1839 }
1840       
1841
1842
1843 /*******************************************************************
1844   write to a file
1845   ********************************************************************/
1846 static int smb_writefile(char *outbuf,int fnum,int pos,char *buf,int n)
1847 {
1848   pstring inbuf;
1849
1850   if (writebraw_supported && n > (max_xmit-200)) 
1851     return(smb_writeraw(outbuf,fnum,pos,buf,n));
1852
1853   bzero(outbuf,smb_size);
1854   bzero(inbuf,smb_size);
1855   set_message(outbuf,5,n + 3,True);
1856
1857   CVAL(outbuf,smb_com) = SMBwrite;
1858   SSVAL(outbuf,smb_tid,cnum);
1859   setup_pkt(outbuf);
1860
1861   SSVAL(outbuf,smb_vwv0,fnum);
1862   SSVAL(outbuf,smb_vwv1,n);
1863   SIVAL(outbuf,smb_vwv2,pos);
1864   SSVAL(outbuf,smb_vwv4,0);
1865   CVAL(smb_buf(outbuf),0) = 1;
1866   SSVAL(smb_buf(outbuf),1,n);
1867
1868   memcpy(smb_buf(outbuf)+3,buf,n);
1869
1870   send_smb(Client,outbuf);
1871   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1872
1873   if (CVAL(inbuf,smb_rcls) != 0) {
1874     DEBUG(0,("%s writing remote file\n",smb_errstr(inbuf)));
1875     return(0);
1876   }
1877   return(SVAL(inbuf,smb_vwv0));
1878 }
1879       
1880
1881
1882 /****************************************************************************
1883   put a single file
1884   ****************************************************************************/
1885 static void do_put(char *rname,char *lname,file_info *finfo)
1886 {
1887   int fnum;
1888   FILE *f;
1889   int nread=0;
1890   char *p;
1891   char *inbuf,*outbuf; 
1892   time_t close_time = finfo->mtime;
1893   char *buf=NULL;
1894   static int maxwrite=0;
1895
1896   struct timeval tp_start;
1897   GetTimeOfDay(&tp_start);
1898
1899   inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1900   outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1901
1902   if (!inbuf || !outbuf)
1903     {
1904       DEBUG(0,("out of memory\n"));
1905       return;
1906     }
1907
1908   bzero(outbuf,smb_size);
1909   set_message(outbuf,3,2 + strlen(rname),True);
1910
1911   if (finfo->mtime == 0 || finfo->mtime == -1)
1912     finfo->mtime = finfo->atime = finfo->ctime = time(NULL);
1913
1914   CVAL(outbuf,smb_com) = SMBcreate;
1915   SSVAL(outbuf,smb_tid,cnum);
1916   setup_pkt(outbuf);
1917
1918   SSVAL(outbuf,smb_vwv0,finfo->mode);
1919   put_dos_date3(outbuf,smb_vwv1,finfo->mtime);
1920   
1921   p = smb_buf(outbuf);
1922   *p++ = 4;      
1923   strcpy(p,rname);
1924   
1925   send_smb(Client,outbuf);
1926   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1927   
1928   if (CVAL(inbuf,smb_rcls) != 0)
1929     {
1930       DEBUG(0,("%s opening remote file %s\n",smb_errstr(inbuf),CNV_LANG(rname)));
1931
1932       free(inbuf);free(outbuf);if (buf) free(buf);
1933       return;
1934     }
1935
1936   f = fopen(lname,"r");
1937
1938   if (!f)
1939     {
1940       DEBUG(0,("Error opening local file %s\n",lname));
1941       free(inbuf);free(outbuf);
1942       return;
1943     }
1944
1945   
1946   fnum = SVAL(inbuf,smb_vwv0);
1947   if (finfo->size < 0)
1948     finfo->size = file_size(lname);
1949   
1950   DEBUG(1,("putting file %s of size %d bytes as %s ",lname,finfo->size,CNV_LANG(rname)));
1951   
1952   if (!maxwrite)
1953     maxwrite = writebraw_supported?MAX(max_xmit,BUFFER_SIZE):(max_xmit-200);
1954
1955   while (nread < finfo->size)
1956     {
1957       int n = maxwrite;
1958       int ret;
1959
1960       n = MIN(n,finfo->size - nread);
1961
1962       buf = (char *)Realloc(buf,n+4);
1963   
1964       fseek(f,nread,SEEK_SET);
1965       if ((n = readfile(buf+4,1,n,f)) < 1)
1966         {
1967           DEBUG(0,("Error reading local file\n"));
1968           break;
1969         }         
1970
1971       ret = smb_writefile(outbuf,fnum,nread,buf+4,n);
1972
1973       if (n != ret) {
1974         if (!maxwrite) {
1975           DEBUG(0,("Error writing file\n"));
1976           break;
1977         } else {
1978           maxwrite /= 2;
1979           continue;
1980         }
1981       }
1982
1983       nread += n;
1984     }
1985
1986
1987
1988   bzero(outbuf,smb_size);
1989   set_message(outbuf,3,0,True);
1990   CVAL(outbuf,smb_com) = SMBclose;
1991   SSVAL(outbuf,smb_tid,cnum);
1992   setup_pkt(outbuf);
1993
1994   SSVAL(outbuf,smb_vwv0,fnum);  
1995   put_dos_date3(outbuf,smb_vwv1,close_time);
1996
1997   send_smb(Client,outbuf);
1998   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1999   
2000   if (CVAL(inbuf,smb_rcls) != 0)
2001     {
2002       DEBUG(0,("%s closing remote file %s\n",smb_errstr(inbuf),CNV_LANG(rname)));
2003       fclose(f);
2004       free(inbuf);free(outbuf);
2005       if (buf) free(buf);
2006       return;
2007     }
2008
2009   
2010   fclose(f);
2011   free(inbuf);free(outbuf);
2012   if (buf) free(buf);
2013
2014   {
2015     struct timeval tp_end;
2016     int this_time;
2017
2018     GetTimeOfDay(&tp_end);
2019     this_time = 
2020       (tp_end.tv_sec - tp_start.tv_sec)*1000 +
2021         (tp_end.tv_usec - tp_start.tv_usec)/1000;
2022     put_total_time_ms += this_time;
2023     put_total_size += finfo->size;
2024
2025     DEBUG(1,("(%g kb/s) (average %g kb/s)\n",
2026              finfo->size / (1.024*this_time + 1.0e-4),
2027              put_total_size / (1.024*put_total_time_ms)));
2028   }
2029
2030
2031  
2032
2033 /****************************************************************************
2034   put a file
2035   ****************************************************************************/
2036 static void cmd_put(void)
2037 {
2038   pstring lname;
2039   pstring rname;
2040   fstring buf;
2041   char *p=buf;
2042   file_info finfo;
2043   finfo = def_finfo;
2044   
2045   strcpy(rname,cur_dir);
2046   strcat(rname,"\\");
2047   
2048   
2049   if (!next_token(NULL,p,NULL))
2050     {
2051       DEBUG(0,("put <filename>\n"));
2052       return;
2053     }
2054   strcpy(lname,p);
2055   
2056   if (next_token(NULL,p,NULL))
2057     strcat(rname,p);      
2058   else
2059     strcat(rname,lname);
2060
2061   dos_clean_name(rname);
2062
2063   {
2064     struct stat st;
2065     if (!file_exist(lname,&st)) {
2066       DEBUG(0,("%s does not exist\n",lname));
2067       return;
2068     }
2069     finfo.mtime = st.st_mtime;
2070   }
2071
2072   do_put(rname,lname,&finfo);
2073 }
2074
2075 /****************************************************************************
2076   seek in a directory/file list until you get something that doesn't start with
2077   the specified name
2078   ****************************************************************************/
2079 static BOOL seek_list(FILE *f,char *name)
2080 {
2081   pstring s;
2082   while (!feof(f))
2083     {
2084       if (fscanf(f,"%s",s) != 1) return(False);
2085       trim_string(s,"./",NULL);
2086       if (strncmp(s,name,strlen(name)) != 0)
2087         {
2088           strcpy(name,s);
2089           return(True);
2090         }
2091     }
2092       
2093   return(False);
2094 }
2095
2096
2097 /****************************************************************************
2098   set the file selection mask
2099   ****************************************************************************/
2100 static void cmd_select(void)
2101 {
2102   strcpy(fileselection,"");
2103   next_token(NULL,fileselection,NULL);
2104 }
2105
2106
2107 /****************************************************************************
2108   mput some files
2109   ****************************************************************************/
2110 static void cmd_mput(void)
2111 {
2112   pstring lname;
2113   pstring rname;
2114   file_info finfo;
2115   fstring buf;
2116   char *p=buf;
2117
2118   finfo = def_finfo;
2119
2120   
2121   while (next_token(NULL,p,NULL))
2122     {
2123       struct stat st;
2124       pstring cmd;
2125       pstring tmpname;
2126       FILE *f;
2127       
2128       sprintf(tmpname,"%s/ls.smb.%d",tmpdir(),(int)getpid());
2129       if (recurse)
2130         sprintf(cmd,"find . -name \"%s\" -print > %s",p,tmpname);
2131       else
2132         sprintf(cmd,"/bin/ls %s > %s",p,tmpname);
2133       system(cmd);
2134
2135       f = fopen(tmpname,"r");
2136       if (!f) continue;
2137
2138       while (!feof(f))
2139         {
2140           pstring quest;
2141
2142           if (fscanf(f,"%s",lname) != 1) break;
2143           trim_string(lname,"./",NULL);
2144
2145         again1:
2146
2147           /* check if it's a directory */
2148           if (directory_exist(lname,&st))
2149             {
2150               if (!recurse) continue;
2151               sprintf(quest,"Put directory %s? ",lname);
2152               if (prompt && !yesno(quest)) 
2153                 {
2154                   strcat(lname,"/");
2155                   if (!seek_list(f,lname))
2156                     break;
2157                   goto again1;              
2158                 }
2159               
2160               strcpy(rname,cur_dir);
2161               strcat(rname,lname);
2162               if (!chkpath(rname,False) && !do_mkdir(rname)) {
2163                 strcat(lname,"/");
2164                 if (!seek_list(f,lname))
2165                   break;
2166                 goto again1;                              
2167               }
2168
2169               continue;
2170             }
2171           else
2172             {
2173               sprintf(quest,"Put file %s? ",lname);
2174               if (prompt && !yesno(quest)) continue;
2175
2176               strcpy(rname,cur_dir);
2177               strcat(rname,lname);
2178             }
2179           dos_format(rname);
2180
2181           /* null size so do_put knows to ignore it */
2182           finfo.size = -1;
2183
2184           /* set the date on the file */
2185           finfo.mtime = st.st_mtime;
2186
2187           do_put(rname,lname,&finfo);
2188         }
2189       fclose(f);
2190       unlink(tmpname);
2191     }
2192 }
2193
2194 /****************************************************************************
2195   cancel a print job
2196   ****************************************************************************/
2197 static void do_cancel(int job)
2198 {
2199   char *rparam = NULL;
2200   char *rdata = NULL;
2201   char *p;
2202   int rdrcnt,rprcnt;
2203   pstring param;
2204
2205   bzero(param,sizeof(param));
2206
2207   p = param;
2208   SSVAL(p,0,81);                /* DosPrintJobDel() */
2209   p += 2;
2210   strcpy(p,"W");
2211   p = skip_string(p,1);
2212   strcpy(p,"");
2213   p = skip_string(p,1);
2214   SSVAL(p,0,job);     
2215   p += 2;
2216
2217   if (call_api(PTR_DIFF(p,param),0,
2218                6,1000,
2219                &rprcnt,&rdrcnt,
2220                param,NULL,
2221                &rparam,&rdata))
2222     {
2223       int res = SVAL(rparam,0);
2224
2225       if (!res)
2226         printf("Job %d cancelled\n",job);
2227       else
2228         printf("Error %d calcelling job %d\n",res,job);
2229       return;
2230     }
2231   else
2232   printf("Server refused cancel request\n");
2233
2234   if (rparam) free(rparam);
2235   if (rdata) free(rdata);
2236
2237   return;
2238 }
2239
2240
2241 /****************************************************************************
2242   cancel a print job
2243   ****************************************************************************/
2244 static void cmd_cancel(char *inbuf,char *outbuf )
2245 {
2246   fstring buf;
2247   int job; 
2248
2249   if (!connect_as_printer)
2250     {
2251       DEBUG(0,("WARNING: You didn't use the -P option to smbclient.\n"));
2252       DEBUG(0,("Trying to cancel print jobs without -P may fail\n"));
2253     }
2254
2255   if (!next_token(NULL,buf,NULL)) {
2256     printf("cancel <jobid> ...\n");
2257     return;
2258   }
2259   do {
2260     job = atoi(buf);
2261     do_cancel(job);
2262   } while (next_token(NULL,buf,NULL));
2263 }
2264
2265
2266 /****************************************************************************
2267   get info on a file
2268   ****************************************************************************/
2269 static void cmd_stat(char *inbuf,char *outbuf)
2270 {
2271   fstring buf;
2272   pstring param;
2273   char *resp_data=NULL;
2274   char *resp_param=NULL;
2275   int resp_data_len = 0;
2276   int resp_param_len=0;
2277   char *p;
2278   uint16 setup = TRANSACT2_QPATHINFO;
2279
2280   if (!next_token(NULL,buf,NULL)) {
2281     printf("stat <file>\n");
2282     return;
2283   }
2284
2285   bzero(param,6);
2286   SSVAL(param,0,4); /* level */
2287   p = param+6;
2288   strcpy(p,cur_dir);
2289   strcat(p,buf);
2290
2291   send_trans_request(outbuf,SMBtrans2,NULL,FID_UNUSED,0,
2292                      NULL,param,&setup,
2293                      0,6 + strlen(p)+1,1,
2294                      BUFFER_SIZE,2,0);
2295
2296   receive_trans_response(inbuf,SMBtrans2,
2297                           &resp_data_len,&resp_param_len,
2298                           &resp_data,&resp_param);
2299
2300   if (resp_data) free(resp_data); resp_data = NULL;
2301   if (resp_param) free(resp_param); resp_param = NULL;
2302 }
2303
2304
2305 /****************************************************************************
2306   print a file
2307   ****************************************************************************/
2308 static void cmd_print(char *inbuf,char *outbuf )
2309 {
2310   int fnum;
2311   FILE *f = NULL;
2312   uint32 nread=0;
2313   pstring lname;
2314   pstring rname;
2315   char *p;
2316
2317   if (!connect_as_printer)
2318     {
2319       DEBUG(0,("WARNING: You didn't use the -P option to smbclient.\n"));
2320       DEBUG(0,("Trying to print without -P may fail\n"));
2321     }
2322
2323   if (!next_token(NULL,lname,NULL))
2324     {
2325       DEBUG(0,("print <filename>\n"));
2326       return;
2327     }
2328
2329   strcpy(rname,lname);
2330   p = strrchr(rname,'/');
2331   if (p)
2332     {
2333       pstring tname;
2334       strcpy(tname,p+1);
2335       strcpy(rname,tname);
2336     }
2337
2338   if ((int)strlen(rname) > 14)
2339     rname[14] = 0;
2340
2341   if (strequal(lname,"-"))
2342     {
2343       f = stdin;
2344       strcpy(rname,"stdin");
2345     }
2346   
2347   dos_clean_name(rname);
2348
2349   bzero(outbuf,smb_size);
2350   set_message(outbuf,2,2 + strlen(rname),True);
2351   
2352   CVAL(outbuf,smb_com) = SMBsplopen;
2353   SSVAL(outbuf,smb_tid,cnum);
2354   setup_pkt(outbuf);
2355
2356   SSVAL(outbuf,smb_vwv0,0);
2357   SSVAL(outbuf,smb_vwv1,printmode);
2358   
2359   p = smb_buf(outbuf);
2360   *p++ = 4;      
2361   strcpy(p,rname);
2362   
2363   send_smb(Client,outbuf);
2364   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2365   
2366   if (CVAL(inbuf,smb_rcls) != 0)
2367     {
2368       DEBUG(0,("%s opening printer for %s\n",smb_errstr(inbuf),CNV_LANG(rname)));
2369       return;
2370     }
2371   
2372   if (!f)
2373     f = fopen(lname,"r");
2374   if (!f)
2375     {
2376       DEBUG(0,("Error opening local file %s\n",lname));
2377       return;
2378     }
2379
2380   
2381   fnum = SVAL(inbuf,smb_vwv0);
2382   
2383   DEBUG(1,("printing file %s as %s\n",lname,CNV_LANG(rname)));
2384   
2385   while (!feof(f))
2386     {
2387       int n;
2388   
2389       bzero(outbuf,smb_size);
2390       set_message(outbuf,1,3,True);
2391
2392       /* for some strange reason the OS/2 print server can't handle large
2393          packets when printing. weird */
2394       n = MIN(1024,max_xmit-(smb_len(outbuf)+4));
2395
2396       if (translation)
2397         n = printread(f,smb_buf(outbuf)+3,(int)(0.95*n));
2398       else
2399         n = readfile(smb_buf(outbuf)+3,1,n,f);
2400       if (n <= 0) 
2401         {
2402           DEBUG(0,("read gave %d\n",n));
2403           break;
2404         }
2405
2406       smb_setlen(outbuf,smb_len(outbuf) + n);
2407
2408       CVAL(outbuf,smb_com) = SMBsplwr;
2409       SSVAL(outbuf,smb_tid,cnum);
2410       setup_pkt(outbuf);
2411
2412       SSVAL(outbuf,smb_vwv0,fnum);
2413       SSVAL(outbuf,smb_vwv1,n+3);
2414       CVAL(smb_buf(outbuf),0) = 1;
2415       SSVAL(smb_buf(outbuf),1,n);
2416
2417       send_smb(Client,outbuf);
2418       receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2419
2420       if (CVAL(inbuf,smb_rcls) != 0)
2421         {
2422           DEBUG(0,("%s printing remote file\n",smb_errstr(inbuf)));
2423           break;
2424         }
2425
2426       nread += n;
2427     }
2428
2429   DEBUG(2,("%d bytes printed\n",nread));
2430
2431   bzero(outbuf,smb_size);
2432   set_message(outbuf,1,0,True);
2433   CVAL(outbuf,smb_com) = SMBsplclose;
2434   SSVAL(outbuf,smb_tid,cnum);
2435   setup_pkt(outbuf);
2436
2437   SSVAL(outbuf,smb_vwv0,fnum);
2438
2439   send_smb(Client,outbuf);
2440   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2441   
2442   if (CVAL(inbuf,smb_rcls) != 0)
2443     {
2444       DEBUG(0,("%s closing print file\n",smb_errstr(inbuf)));
2445       if (f != stdin)
2446         fclose(f);
2447       return;
2448     }
2449
2450   if (f != stdin)
2451     fclose(f);
2452 }
2453
2454 /****************************************************************************
2455 show a print queue - this is deprecated as it uses the old smb that
2456 has limited support - the correct call is the cmd_p_queue_4() after this.
2457 ****************************************************************************/
2458 static void cmd_queue(char *inbuf,char *outbuf )
2459 {
2460   int count;
2461   char *p;
2462
2463   bzero(outbuf,smb_size);
2464   set_message(outbuf,2,0,True);
2465   
2466   CVAL(outbuf,smb_com) = SMBsplretq;
2467   SSVAL(outbuf,smb_tid,cnum);
2468   setup_pkt(outbuf);
2469
2470   SSVAL(outbuf,smb_vwv0,32); /* a max of 20 entries is to be shown */
2471   SSVAL(outbuf,smb_vwv1,0); /* the index into the queue */
2472   
2473   send_smb(Client,outbuf);
2474   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2475   
2476   if (CVAL(inbuf,smb_rcls) != 0)
2477     {
2478       DEBUG(0,("%s obtaining print queue\n",smb_errstr(inbuf)));
2479       return;
2480     }
2481
2482   count = SVAL(inbuf,smb_vwv0);
2483   p = smb_buf(inbuf) + 3;
2484   if (count <= 0)
2485     {
2486       DEBUG(0,("No entries in the print queue\n"));
2487       return;
2488     }  
2489
2490   {
2491     char status[20];
2492
2493     DEBUG(0,("Job      Name              Size         Status\n"));
2494
2495     while (count--)
2496       {
2497         switch (CVAL(p,4))
2498           {
2499           case 0x01: sprintf(status,"held or stopped"); break;
2500           case 0x02: sprintf(status,"printing"); break;
2501           case 0x03: sprintf(status,"awaiting print"); break;
2502           case 0x04: sprintf(status,"in intercept"); break;
2503           case 0x05: sprintf(status,"file had error"); break;
2504           case 0x06: sprintf(status,"printer error"); break;
2505           default: sprintf(status,"unknown"); break;
2506           }
2507
2508         DEBUG(0,("%-6d   %-16.16s  %-9d    %s\n",
2509                  SVAL(p,5),p+12,IVAL(p,7),status));
2510         p += 28;
2511       }
2512   }
2513   
2514 }
2515
2516
2517 /****************************************************************************
2518 show information about a print queue
2519 ****************************************************************************/
2520 static void cmd_p_queue_4(char *inbuf,char *outbuf )
2521 {
2522   char *rparam = NULL;
2523   char *rdata = NULL;
2524   char *p;
2525   int rdrcnt, rprcnt;
2526   pstring param;
2527   int result_code=0;
2528
2529   if (!connect_as_printer)
2530     {
2531       DEBUG(0,("WARNING: You didn't use the -P option to smbclient.\n"));
2532       DEBUG(0,("Trying to print without -P may fail\n"));
2533     }
2534   
2535   bzero(param,sizeof(param));
2536
2537   p = param;
2538   SSVAL(p,0,76);                        /* API function number 76 (DosPrintJobEnum) */
2539   p += 2;
2540   strcpy(p,"zWrLeh");                   /* parameter description? */
2541   p = skip_string(p,1);
2542   strcpy(p,"WWzWWDDzz");                /* returned data format */
2543   p = skip_string(p,1);
2544   strcpy(p,strrchr(service,'\\')+1);    /* name of queue */
2545   p = skip_string(p,1);
2546   SSVAL(p,0,2);                 /* API function level 2, PRJINFO_2 data structure */
2547   SSVAL(p,2,1000);                      /* size of bytes of returned data buffer */
2548   p += 4;
2549   strcpy(p,"");                         /* subformat */
2550   p = skip_string(p,1);
2551
2552   DEBUG(1,("Calling DosPrintJobEnum()...\n"));
2553   if( call_api(PTR_DIFF(p,param), 0,
2554                10, 4096,
2555                &rprcnt, &rdrcnt,
2556                param, NULL,
2557                &rparam, &rdata) )
2558     {
2559       int converter;
2560       result_code = SVAL(rparam,0);
2561       converter = SVAL(rparam,2);             /* conversion factor */
2562
2563       DEBUG(2,("returned %d bytes of parameters, %d bytes of data, %d records\n", rprcnt, rdrcnt, SVAL(rparam,4) ));
2564
2565       if (result_code == 0)                   /* if no error, */
2566         {
2567           int i;
2568           uint16 JobId;
2569           uint16 Priority;
2570           uint32 Size;
2571           char *UserName;
2572           char *JobName;
2573           char *JobTimeStr;
2574           time_t JobTime;
2575           char PrinterName[20];
2576              
2577           strcpy(PrinterName,strrchr(service,'\\')+1);       /* name of queue */
2578           strlower(PrinterName);                             /* in lower case */
2579
2580           p = rdata;                          /* received data */
2581           for( i = 0; i < SVAL(rparam,4); ++i)
2582             {
2583               JobId = SVAL(p,0);
2584               Priority = SVAL(p,2);
2585               UserName = fix_char_ptr(SVAL(p,4), converter, rdata, rdrcnt);
2586               strlower(UserName);
2587               Priority = SVAL(p,2);
2588               JobTime = make_unix_date3( p + 12);
2589               JobTimeStr = asctime(LocalTime( &JobTime));
2590               Size = IVAL(p,16);
2591               JobName = fix_char_ptr(SVAL(p,24), converter, rdata, rdrcnt);
2592             
2593
2594               printf("%s-%u    %s    priority %u   %s    %s   %u bytes\n", 
2595                 PrinterName, JobId, UserName,
2596                 Priority, JobTimeStr, JobName, Size);
2597    
2598 #if 0 /* DEBUG code */
2599               printf("Job Id: \"%u\"\n", SVAL(p,0));
2600               printf("Priority: \"%u\"\n", SVAL(p,2));
2601             
2602               printf("User Name: \"%s\"\n", fix_char_ptr(SVAL(p,4), converter, rdata, rdrcnt) );
2603               printf("Position: \"%u\"\n", SVAL(p,8));
2604               printf("Status: \"%u\"\n", SVAL(p,10));
2605             
2606               JobTime = make_unix_date3( p + 12);
2607               printf("Submitted: \"%s\"\n", asctime(LocalTime(&JobTime)));
2608               printf("date: \"%u\"\n", SVAL(p,12));
2609
2610               printf("Size: \"%u\"\n", SVAL(p,16));
2611               printf("Comment: \"%s\"\n", fix_char_ptr(SVAL(p,20), converter, rdata, rdrcnt) );
2612               printf("Document: \"%s\"\n", fix_char_ptr(SVAL(p,24), converter, rdata, rdrcnt) );
2613 #endif /* DEBUG CODE */ 
2614               p += 28;
2615             }
2616         }
2617     }
2618   else                  /* call_api() failed */
2619     {
2620       printf("Failed, error = %d\n", result_code);
2621     }
2622
2623   /* If any parameters or data were returned, free the storage. */
2624   if(rparam) free(rparam);
2625   if(rdata) free(rdata);
2626
2627   return;
2628 }
2629
2630 /****************************************************************************
2631 show information about a print queue
2632 ****************************************************************************/
2633 static void cmd_qinfo(char *inbuf,char *outbuf )
2634 {
2635   char *rparam = NULL;
2636   char *rdata = NULL;
2637   char *p;
2638   int rdrcnt, rprcnt;
2639   pstring param;
2640   int result_code=0;
2641   
2642   bzero(param,sizeof(param));
2643
2644   p = param;
2645   SSVAL(p,0,70);                        /* API function number 70 (DosPrintQGetInfo) */
2646   p += 2;
2647   strcpy(p,"zWrLh");                    /* parameter description? */
2648   p = skip_string(p,1);
2649   strcpy(p,"zWWWWzzzzWWzzl");           /* returned data format */
2650   p = skip_string(p,1);
2651   strcpy(p,strrchr(service,'\\')+1);    /* name of queue */
2652   p = skip_string(p,1);
2653   SSVAL(p,0,3);                         /* API function level 3, just queue info, no job info */
2654   SSVAL(p,2,1000);                      /* size of bytes of returned data buffer */
2655   p += 4;
2656   strcpy(p,"");                         /* subformat */
2657   p = skip_string(p,1);
2658
2659   DEBUG(1,("Calling DosPrintQueueGetInfo()...\n"));
2660   if( call_api(PTR_DIFF(p,param), 0,
2661                10, 4096,
2662                &rprcnt, &rdrcnt,
2663                param, NULL,
2664                &rparam, &rdata) )
2665         {
2666         int converter;
2667         result_code = SVAL(rparam,0);
2668         converter = SVAL(rparam,2);             /* conversion factor */
2669
2670         DEBUG(2,("returned %d bytes of parameters, %d bytes of data, %d records\n", rprcnt, rdrcnt, SVAL(rparam,4) ));
2671
2672         if (result_code == 0)                   /* if no error, */
2673             {
2674             p = rdata;                          /* received data */
2675
2676             printf("Name: \"%s\"\n", fix_char_ptr(SVAL(p,0), converter, rdata, rdrcnt) );
2677             printf("Priority: %u\n", SVAL(p,4) );
2678             printf("Start time: %u\n", SVAL(p,6) );
2679             printf("Until time: %u\n", SVAL(p,8) );
2680             printf("Seperator file: \"%s\"\n", fix_char_ptr(SVAL(p,12), converter, rdata, rdrcnt) );
2681             printf("Print processor: \"%s\"\n", fix_char_ptr(SVAL(p,16), converter, rdata, rdrcnt) );
2682             printf("Parameters: \"%s\"\n", fix_char_ptr(SVAL(p,20), converter, rdata, rdrcnt) );
2683             printf("Comment: \"%s\"\n", fix_char_ptr(SVAL(p,24), converter, rdata, rdrcnt) );
2684             printf("Status: %u\n", SVAL(p,28) );
2685             printf("Jobs: %u\n", SVAL(p,30) );
2686             printf("Printers: \"%s\"\n", fix_char_ptr(SVAL(p,32), converter, rdata, rdrcnt) );
2687             printf("Drivername: \"%s\"\n", fix_char_ptr(SVAL(p,36), converter, rdata, rdrcnt) );
2688
2689             /* Dump the driver data */
2690             {
2691             int count, x, y, c;
2692             char *ddptr;
2693
2694             ddptr = rdata + SVAL(p,40) - converter;
2695             if( SVAL(p,40) == 0 ) {count = 0;} else {count = IVAL(ddptr,0);}
2696             printf("Driverdata: size=%d, version=%u\n", count, IVAL(ddptr,4) );
2697
2698             for(x=8; x < count; x+=16)
2699                 {
2700                 for(y=0; y < 16; y++)
2701                     {
2702                     if( (x+y) < count )
2703                         printf("%2.2X ", CVAL(ddptr,(x+y)) );
2704                     else
2705                         fputs("   ", stdout);
2706                     }
2707                 for(y=0; y < 16 && (x+y) < count; y++)
2708                     {
2709                     c = CVAL(ddptr,(x+y));
2710                     if(isprint(c))
2711                         fputc(c, stdout);
2712                     else
2713                         fputc('.', stdout);
2714                     }
2715                 fputc('\n', stdout);
2716                 }
2717             }
2718             
2719             }
2720         }
2721   else                  /* call_api() failed */
2722         {
2723         printf("Failed, error = %d\n", result_code);
2724         }
2725
2726   /* If any parameters or data were returned, free the storage. */
2727   if(rparam) free(rparam);
2728   if(rdata) free(rdata);
2729
2730   return;
2731 }
2732
2733 /****************************************************************************
2734 delete some files
2735 ****************************************************************************/
2736 static void do_del(file_info *finfo)
2737 {
2738   char *p;
2739   char *inbuf,*outbuf;
2740   pstring mask;
2741
2742   strcpy(mask,cur_dir);
2743   strcat(mask,finfo->name);
2744
2745   if (finfo->mode & aDIR) 
2746     return;
2747
2748   inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
2749   outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
2750   
2751   if (!inbuf || !outbuf)
2752     {
2753       DEBUG(0,("out of memory\n"));
2754       return;
2755     }
2756
2757   bzero(outbuf,smb_size);
2758   set_message(outbuf,1,2 + strlen(mask),True);
2759   
2760   CVAL(outbuf,smb_com) = SMBunlink;
2761   SSVAL(outbuf,smb_tid,cnum);
2762   setup_pkt(outbuf);
2763
2764   SSVAL(outbuf,smb_vwv0,0);
2765   
2766   p = smb_buf(outbuf);
2767   *p++ = 4;      
2768   strcpy(p,mask);
2769   
2770   send_smb(Client,outbuf);
2771   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2772   
2773   if (CVAL(inbuf,smb_rcls) != 0)
2774     DEBUG(0,("%s deleting remote file %s\n",smb_errstr(inbuf),CNV_LANG(mask)));
2775
2776   free(inbuf);free(outbuf);
2777   
2778 }
2779
2780 /****************************************************************************
2781 delete some files
2782 ****************************************************************************/
2783 static void cmd_del(char *inbuf,char *outbuf )
2784 {
2785   pstring mask;
2786   fstring buf;
2787   int attribute = aSYSTEM | aHIDDEN;
2788
2789   if (recurse)
2790     attribute |= aDIR;
2791   
2792   strcpy(mask,cur_dir);
2793     
2794   if (!next_token(NULL,buf,NULL))
2795     {
2796       DEBUG(0,("del <filename>\n"));
2797       return;
2798     }
2799   strcat(mask,buf);
2800
2801   do_dir((char *)inbuf,(char *)outbuf,mask,attribute,do_del,False);
2802 }
2803
2804
2805 /****************************************************************************
2806 remove a directory
2807 ****************************************************************************/
2808 static void cmd_rmdir(char *inbuf,char *outbuf )
2809 {
2810   pstring mask;
2811   fstring buf;
2812   char *p;
2813   
2814   strcpy(mask,cur_dir);
2815   
2816   if (!next_token(NULL,buf,NULL))
2817     {
2818       DEBUG(0,("rmdir <dirname>\n"));
2819       return;
2820     }
2821   strcat(mask,buf);
2822
2823   bzero(outbuf,smb_size);
2824   set_message(outbuf,0,2 + strlen(mask),True);
2825   
2826   CVAL(outbuf,smb_com) = SMBrmdir;
2827   SSVAL(outbuf,smb_tid,cnum);
2828   setup_pkt(outbuf);
2829
2830   
2831   p = smb_buf(outbuf);
2832   *p++ = 4;      
2833   strcpy(p,mask);
2834   
2835   send_smb(Client,outbuf);
2836   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2837   
2838   if (CVAL(inbuf,smb_rcls) != 0)
2839     {
2840       DEBUG(0,("%s removing remote directory file %s\n",smb_errstr(inbuf),CNV_LANG(mask)));
2841       return;
2842     }
2843   
2844 }
2845
2846 /****************************************************************************
2847 rename some files
2848 ****************************************************************************/
2849 static void cmd_rename(char *inbuf,char *outbuf )
2850 {
2851   pstring src,dest;
2852   fstring buf,buf2;
2853   char *p;
2854   
2855   strcpy(src,cur_dir);
2856   strcpy(dest,cur_dir);
2857   
2858   if (!next_token(NULL,buf,NULL) || !next_token(NULL,buf2,NULL))
2859     {
2860       DEBUG(0,("rename <src> <dest>\n"));
2861       return;
2862     }
2863   strcat(src,buf);
2864   strcat(dest,buf2);
2865
2866   bzero(outbuf,smb_size);
2867   set_message(outbuf,1,4 + strlen(src) + strlen(dest),True);
2868   
2869   CVAL(outbuf,smb_com) = SMBmv;
2870   SSVAL(outbuf,smb_tid,cnum);
2871   SSVAL(outbuf,smb_vwv0,aHIDDEN | aDIR | aSYSTEM);
2872   setup_pkt(outbuf);
2873   
2874   p = smb_buf(outbuf);
2875   *p++ = 4;      
2876   strcpy(p,src);
2877   p = skip_string(p,1);
2878   *p++ = 4;      
2879   strcpy(p,dest);
2880   
2881   send_smb(Client,outbuf);
2882   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2883   
2884   if (CVAL(inbuf,smb_rcls) != 0)
2885     {
2886       DEBUG(0,("%s renaming files\n",smb_errstr(inbuf)));
2887       return;
2888     }
2889   
2890 }
2891
2892
2893 /****************************************************************************
2894 toggle the prompt flag
2895 ****************************************************************************/
2896 static void cmd_prompt(void)
2897 {
2898   prompt = !prompt;
2899   DEBUG(2,("prompting is now %s\n",prompt?"on":"off"));
2900 }
2901
2902
2903 /****************************************************************************
2904 set the newer than time
2905 ****************************************************************************/
2906 static void cmd_newer(void)
2907 {
2908   fstring buf;
2909   BOOL ok;
2910   struct stat sbuf;
2911
2912   ok = next_token(NULL,buf,NULL);
2913   if (ok && (sys_stat(buf,&sbuf) == 0))
2914     {
2915       newer_than = sbuf.st_mtime;
2916       DEBUG(1,("Getting files newer than %s",
2917                asctime(LocalTime(&newer_than))));
2918     }
2919   else
2920     newer_than = 0;
2921
2922   if (ok && newer_than == 0)
2923     DEBUG(0,("Error setting newer-than time\n"));
2924 }
2925
2926 /****************************************************************************
2927 set the archive level
2928 ****************************************************************************/
2929 static void cmd_archive(void)
2930 {
2931   fstring buf;
2932
2933   if (next_token(NULL,buf,NULL)) {
2934     archive_level = atoi(buf);
2935   } else
2936     DEBUG(0,("Archive level is %d\n",archive_level));
2937 }
2938
2939 /****************************************************************************
2940 toggle the lowercaseflag
2941 ****************************************************************************/
2942 static void cmd_lowercase(void)
2943 {
2944   lowercase = !lowercase;
2945   DEBUG(2,("filename lowercasing is now %s\n",lowercase?"on":"off"));
2946 }
2947
2948
2949
2950
2951 /****************************************************************************
2952 toggle the recurse flag
2953 ****************************************************************************/
2954 static void cmd_recurse(void)
2955 {
2956   recurse = !recurse;
2957   DEBUG(2,("directory recursion is now %s\n",recurse?"on":"off"));
2958 }
2959
2960 /****************************************************************************
2961 toggle the translate flag
2962 ****************************************************************************/
2963 static void cmd_translate(void)
2964 {
2965   translation = !translation;
2966   DEBUG(2,("CR/LF<->LF and print text translation now %s\n",
2967         translation?"on":"off"));
2968 }
2969
2970
2971 /****************************************************************************
2972 do a printmode command
2973 ****************************************************************************/
2974 static void cmd_printmode(void)
2975 {
2976   fstring buf;
2977   fstring mode;
2978
2979   if (next_token(NULL,buf,NULL))
2980     {
2981       if (strequal(buf,"text"))
2982         printmode = 0;      
2983       else
2984         {
2985           if (strequal(buf,"graphics"))
2986             printmode = 1;
2987           else
2988             printmode = atoi(buf);
2989         }
2990     }
2991
2992   switch(printmode)
2993     {
2994     case 0: 
2995       strcpy(mode,"text");
2996       break;
2997     case 1: 
2998       strcpy(mode,"graphics");
2999       break;
3000     default: 
3001       sprintf(mode,"%d",printmode);
3002       break;
3003     }
3004
3005   DEBUG(2,("the printmode is now %s\n",mode));
3006 }
3007
3008 /****************************************************************************
3009 do the lcd command
3010 ****************************************************************************/
3011 static void cmd_lcd(void)
3012 {
3013   fstring buf;
3014   pstring d;
3015
3016   if (next_token(NULL,buf,NULL))
3017     sys_chdir(buf);
3018   DEBUG(2,("the local directory is now %s\n",GetWd(d)));
3019 }
3020
3021
3022 /****************************************************************************
3023 send a session request
3024 ****************************************************************************/
3025 static BOOL send_session_request(char *inbuf,char *outbuf)
3026 {
3027   fstring dest;
3028   char *p;
3029   int len = 4;
3030   /* send a session request (RFC 8002) */
3031
3032   strcpy(dest,desthost);
3033   p = strchr(dest,'.');
3034   if (p) *p = 0;
3035
3036   /* put in the destination name */
3037   p = outbuf+len;
3038   name_mangle(dest,p,name_type); /* 0x20 is the SMB server NetBIOS type. */
3039   len += name_len(p);
3040
3041   /* and my name */
3042   p = outbuf+len;
3043   name_mangle(myname,p,0);
3044   len += name_len(p);
3045
3046   /* setup the packet length */
3047   _smb_setlen(outbuf,len);
3048   CVAL(outbuf,0) = 0x81;
3049
3050   send_smb(Client,outbuf);
3051   DEBUG(5,("Sent session request\n"));
3052
3053   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
3054
3055   if (CVAL(inbuf,0) == 0x84) /* C. Hoch  9/14/95 Start */
3056     {
3057       /* For information, here is the response structure.
3058        * We do the byte-twiddling to for portability.
3059        struct RetargetResponse{
3060        unsigned char type;
3061        unsigned char flags;
3062        int16 length;
3063        int32 ip_addr;
3064        int16 port;
3065        };
3066        */
3067       extern int Client;
3068       int port = (CVAL(inbuf,8)<<8)+CVAL(inbuf,9);
3069       /* SESSION RETARGET */
3070       putip((char *)&dest_ip,inbuf+4);
3071
3072       close_sockets();
3073       Client = open_socket_out(SOCK_STREAM, &dest_ip, port, LONG_CONNECT_TIMEOUT);
3074       if (Client == -1)
3075         return False;
3076
3077       DEBUG(3,("Retargeted\n"));
3078
3079       set_socket_options(Client,user_socket_options);
3080
3081       /* Try again */
3082       return send_session_request(inbuf,outbuf);
3083     } /* C. Hoch 9/14/95 End */
3084
3085
3086   if (CVAL(inbuf,0) != 0x82)
3087     {
3088       int ecode = CVAL(inbuf,4);
3089       DEBUG(0,("Session request failed (%d,%d) with myname=%s destname=%s\n",
3090                CVAL(inbuf,0),ecode,myname,desthost));
3091       switch (ecode)
3092         {
3093         case 0x80: 
3094           DEBUG(0,("Not listening on called name\n")); 
3095           DEBUG(0,("Try to connect to another name (instead of %s)\n",desthost));
3096           DEBUG(0,("You may find the -I option useful for this\n"));
3097           break;
3098         case 0x81: 
3099           DEBUG(0,("Not listening for calling name\n")); 
3100           DEBUG(0,("Try to connect as another name (instead of %s)\n",myname));
3101           DEBUG(0,("You may find the -n option useful for this\n"));
3102           break;
3103         case 0x82: 
3104           DEBUG(0,("Called name not present\n")); 
3105           DEBUG(0,("Try to connect to another name (instead of %s)\n",desthost));
3106           DEBUG(0,("You may find the -I option useful for this\n"));
3107           break;
3108         case 0x83: 
3109           DEBUG(0,("Called name present, but insufficient resources\n")); 
3110           DEBUG(0,("Perhaps you should try again later?\n")); 
3111           break;
3112         default:
3113           DEBUG(0,("Unspecified error 0x%X\n",ecode)); 
3114           DEBUG(0,("Your server software is being unfriendly\n"));
3115           break;          
3116         }
3117       return(False);
3118     }
3119   return(True);
3120 }
3121
3122 static struct {
3123   int prot;
3124   char *name;
3125 } prots[] = {
3126   {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"},
3127   {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
3128   {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
3129   {PROTOCOL_LANMAN1,"LANMAN1.0"},
3130   {PROTOCOL_LANMAN2,"LM1.2X002"},
3131   {PROTOCOL_LANMAN2,"Samba"},
3132   {PROTOCOL_NT1,"NT LM 0.12"},
3133   {PROTOCOL_NT1,"NT LANMAN 1.0"},
3134   {-1,NULL}
3135 };
3136
3137
3138 /****************************************************************************
3139 send a login command
3140 ****************************************************************************/
3141 static BOOL send_login(char *inbuf,char *outbuf,BOOL start_session,BOOL use_setup)
3142 {
3143   BOOL was_null = (!inbuf && !outbuf);
3144   int sesskey=0;
3145   time_t servertime = 0;
3146   extern int serverzone;
3147   int sec_mode=0;
3148   int crypt_len;
3149   int max_vcs=0;
3150   char *pass = NULL;  
3151   pstring dev;
3152   char *p;
3153   int numprots;
3154   int tries=0;
3155
3156   if (was_null)
3157     {
3158       inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
3159       outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
3160     }
3161
3162 #if AJT
3163   if (strstr(service,"IPC$")) connect_as_ipc = True;
3164 #endif
3165
3166   strcpy(dev,"A:");
3167   if (connect_as_printer)
3168     strcpy(dev,"LPT1:");
3169   if (connect_as_ipc)
3170     strcpy(dev,"IPC");
3171
3172
3173   if (start_session && !send_session_request(inbuf,outbuf))
3174     {
3175       if (was_null)
3176         {
3177           free(inbuf);
3178           free(outbuf);
3179         }      
3180       return(False);
3181     }
3182
3183   bzero(outbuf,smb_size);
3184
3185   /* setup the protocol strings */
3186   {
3187     int plength;
3188
3189     for (plength=0,numprots=0;
3190          prots[numprots].name && prots[numprots].prot<=max_protocol;
3191          numprots++)
3192       plength += strlen(prots[numprots].name)+2;
3193     
3194     set_message(outbuf,0,plength,True);
3195
3196     p = smb_buf(outbuf);
3197     for (numprots=0;
3198          prots[numprots].name && prots[numprots].prot<=max_protocol;
3199          numprots++)
3200       {
3201         *p++ = 2;
3202         strcpy(p,prots[numprots].name);
3203         p += strlen(p) + 1;
3204       }
3205   }
3206
3207   CVAL(outbuf,smb_com) = SMBnegprot;
3208   setup_pkt(outbuf);
3209
3210   CVAL(smb_buf(outbuf),0) = 2;
3211
3212   send_smb(Client,outbuf);
3213   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
3214
3215   show_msg(inbuf);
3216
3217   if (CVAL(inbuf,smb_rcls) != 0 || ((int)SVAL(inbuf,smb_vwv0) >= numprots))
3218     {
3219       DEBUG(0,("SMBnegprot failed. myname=%s destname=%s - %s \n",
3220             myname,desthost,smb_errstr(inbuf)));
3221       if (was_null)
3222         {
3223           free(inbuf);
3224           free(outbuf);
3225         }
3226       return(False);
3227     }
3228
3229   Protocol = prots[SVAL(inbuf,smb_vwv0)].prot;
3230
3231
3232   if (Protocol < PROTOCOL_NT1) {    
3233     sec_mode = SVAL(inbuf,smb_vwv1);
3234     max_xmit = SVAL(inbuf,smb_vwv2);
3235     sesskey = IVAL(inbuf,smb_vwv6);
3236     serverzone = SVALS(inbuf,smb_vwv10)*60;
3237     /* this time is converted to GMT by make_unix_date */
3238     servertime = make_unix_date(inbuf+smb_vwv8);
3239     if (Protocol >= PROTOCOL_COREPLUS) {
3240       readbraw_supported = ((SVAL(inbuf,smb_vwv5) & 0x1) != 0);
3241       writebraw_supported = ((SVAL(inbuf,smb_vwv5) & 0x2) != 0);
3242     }
3243     crypt_len = smb_buflen(inbuf);
3244     memcpy(cryptkey,smb_buf(inbuf),8);
3245     DEBUG(3,("max mux %d\n",SVAL(inbuf,smb_vwv3)));
3246     max_vcs = SVAL(inbuf,smb_vwv4); 
3247     DEBUG(3,("max vcs %d\n",max_vcs)); 
3248     DEBUG(3,("max blk %d\n",SVAL(inbuf,smb_vwv5)));
3249   } else {
3250     /* NT protocol */
3251     sec_mode = CVAL(inbuf,smb_vwv1);
3252     max_xmit = IVAL(inbuf,smb_vwv3+1);
3253     sesskey = IVAL(inbuf,smb_vwv7+1);
3254     serverzone = SVALS(inbuf,smb_vwv15+1)*60;
3255     /* this time arrives in real GMT */
3256     servertime = interpret_long_date(inbuf+smb_vwv11+1);
3257     crypt_len = CVAL(inbuf,smb_vwv16+1);
3258     memcpy(cryptkey,smb_buf(inbuf),8);
3259     if (IVAL(inbuf,smb_vwv9+1) & 1)
3260       readbraw_supported = writebraw_supported = True;      
3261     DEBUG(3,("max mux %d\n",SVAL(inbuf,smb_vwv1+1)));
3262     max_vcs = SVAL(inbuf,smb_vwv2+1); 
3263     DEBUG(3,("max vcs %d\n",max_vcs));
3264     DEBUG(3,("max raw %d\n",IVAL(inbuf,smb_vwv5+1)));
3265     DEBUG(3,("capabilities 0x%x\n",IVAL(inbuf,smb_vwv9+1)));
3266   }
3267
3268   DEBUG(3,("Sec mode %d\n",SVAL(inbuf,smb_vwv1)));
3269   DEBUG(3,("max xmt %d\n",max_xmit));
3270   DEBUG(3,("Got %d byte crypt key\n",crypt_len));
3271   DEBUG(3,("Chose protocol [%s]\n",prots[SVAL(inbuf,smb_vwv0)].name));
3272
3273   doencrypt = ((sec_mode & 2) != 0);
3274
3275   if (servertime) {
3276     static BOOL done_time = False;
3277     if (!done_time) {
3278       DEBUG(1,("Server time is %sTimezone is UTC%+02.1f\n",
3279                asctime(LocalTime(&servertime)),
3280                -(double)(serverzone/3600.0)));
3281       done_time = True;
3282     }
3283   }
3284
3285  get_pass:
3286
3287   if (got_pass)
3288     pass = password;
3289   else
3290     pass = (char *)getpass("Password: ");
3291
3292   /* use a blank username for the 2nd try with a blank password */
3293   if (tries++ && !*pass)
3294     *username = 0;
3295
3296   if (Protocol >= PROTOCOL_LANMAN1 && use_setup)
3297     {
3298       fstring pword;
3299       int passlen = strlen(pass)+1;
3300       strcpy(pword,pass);      
3301
3302 #ifdef SMB_PASSWD
3303       if (doencrypt && *pass) {
3304         DEBUG(3,("Using encrypted passwords\n"));
3305         passlen = 24;
3306         SMBencrypt(pass,cryptkey,pword);
3307       }
3308 #else
3309       doencrypt = False;
3310 #endif
3311
3312       /* if in share level security then don't send a password now */
3313       if (!(sec_mode & 1)) {strcpy(pword, "");passlen=1;} 
3314
3315       /* send a session setup command */
3316       bzero(outbuf,smb_size);
3317
3318       if (Protocol < PROTOCOL_NT1) {
3319         set_message(outbuf,10,1 + strlen(username) + passlen,True);
3320         CVAL(outbuf,smb_com) = SMBsesssetupX;
3321         setup_pkt(outbuf);
3322
3323         CVAL(outbuf,smb_vwv0) = 0xFF;
3324         SSVAL(outbuf,smb_vwv2,max_xmit);
3325         SSVAL(outbuf,smb_vwv3,2);
3326         SSVAL(outbuf,smb_vwv4,max_vcs-1);
3327         SIVAL(outbuf,smb_vwv5,sesskey);
3328         SSVAL(outbuf,smb_vwv7,passlen);
3329         p = smb_buf(outbuf);
3330         memcpy(p,pword,passlen);
3331         p += passlen;
3332         strcpy(p,username);
3333       } else {
3334         if (!doencrypt) passlen--;
3335         /* for Win95 */
3336         set_message(outbuf,13,0,True);
3337         CVAL(outbuf,smb_com) = SMBsesssetupX;
3338         setup_pkt(outbuf);
3339
3340         CVAL(outbuf,smb_vwv0) = 0xFF;
3341         SSVAL(outbuf,smb_vwv2,BUFFER_SIZE);
3342         SSVAL(outbuf,smb_vwv3,2);
3343         SSVAL(outbuf,smb_vwv4,getpid());
3344         SIVAL(outbuf,smb_vwv5,sesskey);
3345         SSVAL(outbuf,smb_vwv7,passlen);
3346         SSVAL(outbuf,smb_vwv8,0);
3347         p = smb_buf(outbuf);
3348         memcpy(p,pword,passlen); p += SVAL(outbuf,smb_vwv7);
3349         strcpy(p,username);p = skip_string(p,1);
3350         strcpy(p,workgroup);p = skip_string(p,1);
3351         strcpy(p,"Unix");p = skip_string(p,1);
3352         strcpy(p,"Samba");p = skip_string(p,1);
3353         set_message(outbuf,13,PTR_DIFF(p,smb_buf(outbuf)),False);
3354       }
3355
3356       send_smb(Client,outbuf);
3357       receive_smb(Client,inbuf,CLIENT_TIMEOUT);
3358
3359       show_msg(inbuf);
3360
3361       if (CVAL(inbuf,smb_rcls) != 0)
3362         {
3363           if (! *pass &&
3364               ((CVAL(inbuf,smb_rcls) == ERRDOS && 
3365                 SVAL(inbuf,smb_err) == ERRnoaccess) ||
3366                (CVAL(inbuf,smb_rcls) == ERRSRV && 
3367                 SVAL(inbuf,smb_err) == ERRbadpw)))
3368             {
3369               got_pass = False;
3370               DEBUG(3,("resending login\n"));
3371               goto get_pass;
3372             }
3373               
3374           DEBUG(0,("Session setup failed for username=%s myname=%s destname=%s   %s\n",
3375                 username,myname,desthost,smb_errstr(inbuf)));
3376           DEBUG(0,("You might find the -U, -W or -n options useful\n"));
3377           DEBUG(0,("Sometimes you have to use `-n USERNAME' (particularly with OS/2)\n"));
3378           DEBUG(0,("Some servers also insist on uppercase-only passwords\n"));
3379           if (was_null)
3380             {
3381               free(inbuf);
3382               free(outbuf);
3383             }
3384           return(False);
3385         }
3386
3387       if (Protocol >= PROTOCOL_NT1) {
3388         char *domain,*os,*lanman;
3389         p = smb_buf(inbuf);
3390         os = p;
3391         lanman = skip_string(os,1);
3392         domain = skip_string(lanman,1);
3393         if (*domain || *os || *lanman)
3394           DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",domain,os,lanman));
3395       }
3396
3397       /* use the returned uid from now on */
3398       if (SVAL(inbuf,smb_uid) != uid)
3399         DEBUG(3,("Server gave us a UID of %d. We gave %d\n",
3400               SVAL(inbuf,smb_uid),uid));
3401       uid = SVAL(inbuf,smb_uid);
3402     }
3403
3404   /* now we've got a connection - send a tcon message */
3405   bzero(outbuf,smb_size);
3406
3407   if (strncmp(service,"\\\\",2) != 0)
3408     {
3409       DEBUG(0,("\nWarning: Your service name doesn't start with \\\\. This is probably incorrect.\n"));
3410       DEBUG(0,("Perhaps try replacing each \\ with \\\\ on the command line?\n\n"));
3411     }
3412
3413
3414  again2:
3415
3416   {
3417     int passlen = strlen(pass)+1;
3418     fstring pword;
3419     strcpy(pword,pass);
3420
3421 #ifdef SMB_PASSWD
3422     if (doencrypt && *pass) {
3423       passlen=24;
3424       SMBencrypt(pass,cryptkey,pword);      
3425     }
3426 #endif
3427
3428     /* if in user level security then don't send a password now */
3429     if ((sec_mode & 1)) {
3430       strcpy(pword, ""); passlen=1; 
3431     }
3432
3433     if (Protocol <= PROTOCOL_COREPLUS) {
3434       set_message(outbuf,0,6 + strlen(service) + passlen + strlen(dev),True);
3435       CVAL(outbuf,smb_com) = SMBtcon;
3436       setup_pkt(outbuf);
3437
3438       p = smb_buf(outbuf);
3439       *p++ = 0x04;
3440       strcpy(p, service);
3441       p = skip_string(p,1);
3442       *p++ = 0x04;
3443       memcpy(p,pword,passlen);
3444       p += passlen;
3445       *p++ = 0x04;
3446       strcpy(p, dev);
3447     }
3448     else {
3449       set_message(outbuf,4,2 + strlen(service) + passlen + strlen(dev),True);
3450       CVAL(outbuf,smb_com) = SMBtconX;
3451       setup_pkt(outbuf);
3452   
3453       SSVAL(outbuf,smb_vwv0,0xFF);
3454       SSVAL(outbuf,smb_vwv3,passlen);
3455   
3456       p = smb_buf(outbuf);
3457       memcpy(p,pword,passlen);
3458       p += passlen;
3459       strcpy(p,service);
3460       p = skip_string(p,1);
3461       strcpy(p,dev);
3462     }
3463   }
3464
3465   send_smb(Client,outbuf);
3466   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
3467
3468   /* trying again with a blank password */
3469   if (CVAL(inbuf,smb_rcls) != 0 && 
3470       (int)strlen(pass) > 0 && 
3471       !doencrypt &&
3472       Protocol >= PROTOCOL_LANMAN1)
3473     {
3474       DEBUG(2,("first SMBtconX failed, trying again. %s\n",smb_errstr(inbuf)));
3475       strcpy(pass,"");
3476       goto again2;
3477     }  
3478
3479   if (CVAL(inbuf,smb_rcls) != 0)
3480     {
3481       DEBUG(0,("SMBtconX failed. %s\n",smb_errstr(inbuf)));
3482       DEBUG(0,("Perhaps you are using the wrong sharename, username or password?\n"));
3483       DEBUG(0,("Some servers insist that these be in uppercase\n"));
3484       if (was_null)
3485         {
3486           free(inbuf);
3487           free(outbuf);
3488         }
3489       return(False);
3490     }
3491   
3492
3493   if (Protocol <= PROTOCOL_COREPLUS) {
3494     max_xmit = SVAL(inbuf,smb_vwv0);
3495
3496     cnum = SVAL(inbuf,smb_vwv1);
3497   }
3498   else {
3499     max_xmit = MIN(max_xmit,BUFFER_SIZE-4);
3500     if (max_xmit <= 0)
3501       max_xmit = BUFFER_SIZE - 4;
3502
3503     cnum = SVAL(inbuf,smb_tid);
3504   }
3505
3506   DEBUG(3,("Connected with cnum=%d max_xmit=%d\n",cnum,max_xmit));
3507
3508   if (was_null)
3509     {
3510       free(inbuf);
3511       free(outbuf);
3512     }
3513   return True;
3514 }
3515
3516
3517 /****************************************************************************
3518 send a logout command
3519 ****************************************************************************/
3520 static void send_logout(void )
3521 {
3522   pstring inbuf,outbuf;
3523
3524   bzero(outbuf,smb_size);
3525   set_message(outbuf,0,0,True);
3526   CVAL(outbuf,smb_com) = SMBtdis;
3527   SSVAL(outbuf,smb_tid,cnum);
3528   setup_pkt(outbuf);
3529
3530   send_smb(Client,outbuf);
3531   receive_smb(Client,inbuf,SHORT_TIMEOUT);
3532
3533   if (CVAL(inbuf,smb_rcls) != 0)
3534     {
3535       DEBUG(0,("SMBtdis failed %s\n",smb_errstr(inbuf)));
3536     }
3537
3538   
3539 #ifdef STATS
3540   stats_report();
3541 #endif
3542   exit(0);
3543 }
3544
3545
3546
3547 /****************************************************************************
3548 call a remote api
3549 ****************************************************************************/
3550 static BOOL call_api(int prcnt,int drcnt,
3551                      int mprcnt,int mdrcnt,
3552                      int *rprcnt,int *rdrcnt,
3553                      char *param,char *data,
3554                      char **rparam,char **rdata)
3555 {
3556   static char *inbuf=NULL;
3557   static char *outbuf=NULL;
3558
3559   if (!inbuf) inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
3560   if (!outbuf) outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
3561
3562   send_trans_request(outbuf,SMBtrans,"\\PIPE\\LANMAN",0,0,
3563                      data,param,NULL,
3564                      drcnt,prcnt,0,
3565                      mdrcnt,mprcnt,0);
3566
3567   return (receive_trans_response(inbuf,SMBtrans,
3568                                  rdrcnt,rprcnt,
3569                                  rdata,rparam));
3570 }
3571
3572 /****************************************************************************
3573   send a SMB trans or trans2 request
3574   ****************************************************************************/
3575 static BOOL send_trans_request(char *outbuf,int trans,
3576                                char *name,int fid,int flags,
3577                                char *data,char *param,uint16 *setup,
3578                                int ldata,int lparam,int lsetup,
3579                                int mdata,int mparam,int msetup)
3580 {
3581   int i;
3582   int this_ldata,this_lparam;
3583   int tot_data=0,tot_param=0;
3584   char *outdata,*outparam;
3585   pstring inbuf;
3586   char *p;
3587
3588   this_lparam = MIN(lparam,max_xmit - (500+lsetup*SIZEOFWORD)); /* hack */
3589   this_ldata = MIN(ldata,max_xmit - (500+lsetup*SIZEOFWORD+this_lparam));
3590
3591   bzero(outbuf,smb_size);
3592   set_message(outbuf,14+lsetup,0,True);
3593   CVAL(outbuf,smb_com) = trans;
3594   SSVAL(outbuf,smb_tid,cnum);
3595   setup_pkt(outbuf);
3596
3597   outparam = smb_buf(outbuf)+(trans==SMBtrans ? strlen(name)+1 : 3);
3598   outdata = outparam+this_lparam;
3599
3600   /* primary request */
3601   SSVAL(outbuf,smb_tpscnt,lparam);      /* tpscnt */
3602   SSVAL(outbuf,smb_tdscnt,ldata);       /* tdscnt */
3603   SSVAL(outbuf,smb_mprcnt,mparam);      /* mprcnt */
3604   SSVAL(outbuf,smb_mdrcnt,mdata);       /* mdrcnt */
3605   SCVAL(outbuf,smb_msrcnt,msetup);      /* msrcnt */
3606   SSVAL(outbuf,smb_flags,flags);        /* flags */
3607   SIVAL(outbuf,smb_timeout,0);          /* timeout */
3608   SSVAL(outbuf,smb_pscnt,this_lparam);  /* pscnt */
3609   SSVAL(outbuf,smb_psoff,smb_offset(outparam,outbuf)); /* psoff */
3610   SSVAL(outbuf,smb_dscnt,this_ldata);   /* dscnt */
3611   SSVAL(outbuf,smb_dsoff,smb_offset(outdata,outbuf)); /* dsoff */
3612   SCVAL(outbuf,smb_suwcnt,lsetup);      /* suwcnt */
3613   for (i=0;i<lsetup;i++)                /* setup[] */
3614     SSVAL(outbuf,smb_setup+i*SIZEOFWORD,setup[i]);
3615   p = smb_buf(outbuf);
3616   if (trans==SMBtrans)
3617     strcpy(p,name);                     /* name[] */
3618   else
3619     {
3620       *p++ = 0;                         /* put in a null smb_name */
3621       *p++ = 'D'; *p++ = ' ';           /* this was added because OS/2 does it */
3622     }
3623   if (this_lparam)                      /* param[] */
3624     memcpy(outparam,param,this_lparam);
3625   if (this_ldata)                       /* data[] */
3626     memcpy(outdata,data,this_ldata);
3627   set_message(outbuf,14+lsetup,         /* wcnt, bcc */
3628               PTR_DIFF(outdata+this_ldata,smb_buf(outbuf)),False);
3629
3630   show_msg(outbuf);
3631   send_smb(Client,outbuf);
3632
3633   if (this_ldata < ldata || this_lparam < lparam)
3634     {
3635       /* receive interim response */
3636       if (!receive_smb(Client,inbuf,SHORT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
3637         {
3638           DEBUG(0,("%s request failed (%s)\n",
3639                    trans==SMBtrans?"SMBtrans":"SMBtrans2", smb_errstr(inbuf)));
3640           return(False);
3641         }      
3642
3643       tot_data = this_ldata;
3644       tot_param = this_lparam;
3645
3646       while (tot_data < ldata || tot_param < lparam)
3647     {
3648           this_lparam = MIN(lparam-tot_param,max_xmit - 500); /* hack */
3649           this_ldata = MIN(ldata-tot_data,max_xmit - (500+this_lparam));
3650
3651           set_message(outbuf,trans==SMBtrans?8:9,0,True);
3652           CVAL(outbuf,smb_com) = trans==SMBtrans ? SMBtranss : SMBtranss2;
3653
3654           outparam = smb_buf(outbuf);
3655           outdata = outparam+this_lparam;
3656
3657           /* secondary request */
3658           SSVAL(outbuf,smb_tpscnt,lparam);      /* tpscnt */
3659           SSVAL(outbuf,smb_tdscnt,ldata);       /* tdscnt */
3660           SSVAL(outbuf,smb_spscnt,this_lparam); /* pscnt */
3661           SSVAL(outbuf,smb_spsoff,smb_offset(outparam,outbuf)); /* psoff */
3662           SSVAL(outbuf,smb_spsdisp,tot_param);  /* psdisp */
3663           SSVAL(outbuf,smb_sdscnt,this_ldata);  /* dscnt */
3664           SSVAL(outbuf,smb_sdsoff,smb_offset(outdata,outbuf)); /* dsoff */
3665           SSVAL(outbuf,smb_sdsdisp,tot_data);   /* dsdisp */
3666           if (trans==SMBtrans2)
3667             SSVAL(outbuf,smb_sfid,fid);         /* fid */
3668           if (this_lparam)                      /* param[] */
3669             memcpy(outparam,param,this_lparam);
3670           if (this_ldata)                       /* data[] */
3671             memcpy(outdata,data,this_ldata);
3672           set_message(outbuf,trans==SMBtrans?8:9, /* wcnt, bcc */
3673                       PTR_DIFF(outdata+this_ldata,smb_buf(outbuf)),False);
3674
3675           show_msg(outbuf);
3676           send_smb(Client,outbuf);
3677
3678           tot_data += this_ldata;
3679           tot_param += this_lparam;
3680         }
3681     }
3682
3683     return(True);
3684 }
3685
3686 /****************************************************************************
3687 try and browse available connections on a host
3688 ****************************************************************************/
3689 static BOOL browse_host(BOOL sort)
3690 {
3691 #ifdef NOSTRCASECMP
3692 #define strcasecmp StrCaseCmp
3693 #endif
3694   extern int strcasecmp();
3695
3696   char *rparam = NULL;
3697   char *rdata = NULL;
3698   char *p;
3699   int rdrcnt,rprcnt;
3700   pstring param;
3701   int count = -1;
3702
3703   /* now send a SMBtrans command with api RNetShareEnum */
3704   p = param;
3705   SSVAL(p,0,0); /* api number */
3706   p += 2;
3707   strcpy(p,"WrLeh");
3708   p = skip_string(p,1);
3709   strcpy(p,"B13BWz");
3710   p = skip_string(p,1);
3711   SSVAL(p,0,1);
3712   SSVAL(p,2,BUFFER_SIZE);
3713   p += 4;
3714
3715   if (call_api(PTR_DIFF(p,param),0,
3716                1024,BUFFER_SIZE,
3717                &rprcnt,&rdrcnt,
3718                param,NULL,
3719                &rparam,&rdata))
3720     {
3721       int res = SVAL(rparam,0);
3722       int converter=SVAL(rparam,2);
3723       int i;
3724       BOOL long_share_name=False;
3725       
3726       if (res == 0)
3727         {
3728           count=SVAL(rparam,4);
3729           p = rdata;
3730
3731           if (count > 0)
3732             {
3733               printf("\n\tSharename      Type      Comment\n");
3734               printf("\t---------      ----      -------\n");
3735             }
3736
3737           if (sort)
3738             qsort(p,count,20,QSORT_CAST strcasecmp);
3739
3740           for (i=0;i<count;i++)
3741             {
3742               char *sname = p;
3743               int type = SVAL(p,14);
3744               int comment_offset = IVAL(p,16) & 0xFFFF;
3745               fstring typestr;
3746               *typestr=0;
3747
3748               switch (type)
3749                 {
3750                 case STYPE_DISKTREE:
3751                   strcpy(typestr,"Disk"); break;
3752                 case STYPE_PRINTQ:
3753                   strcpy(typestr,"Printer"); break;           
3754                 case STYPE_DEVICE:
3755                   strcpy(typestr,"Device"); break;
3756                 case STYPE_IPC:
3757                   strcpy(typestr,"IPC"); break;      
3758                 }
3759
3760               printf("\t%-15.15s%-10.10s%s\n",
3761                      sname,
3762                      typestr,
3763                      comment_offset?rdata+comment_offset-converter:"");
3764           
3765               if (strlen(sname)>8) long_share_name=True;
3766           
3767               p += 20;
3768             }
3769
3770           if (long_share_name) {
3771             printf("\nNOTE: There were share names longer than 8 chars.\nOn older clients these may not be accessible or may give browsing errors\n");
3772           }
3773         }
3774     }
3775   
3776   if (rparam) free(rparam);
3777   if (rdata) free(rdata);
3778
3779   return(count>0);
3780 }
3781
3782
3783 /****************************************************************************
3784 get some server info
3785 ****************************************************************************/
3786 static void server_info()
3787 {
3788   char *rparam = NULL;
3789   char *rdata = NULL;
3790   char *p;
3791   int rdrcnt,rprcnt;
3792   pstring param;
3793
3794   bzero(param,sizeof(param));
3795
3796   p = param;
3797   SSVAL(p,0,63);                /* NetServerGetInfo()? */
3798   p += 2;
3799   strcpy(p,"WrLh");
3800   p = skip_string(p,1);
3801   strcpy(p,"zzzBBzz");
3802   p = skip_string(p,1);
3803   SSVAL(p,0,10); /* level 10 */
3804   SSVAL(p,2,1000);
3805   p += 6;
3806
3807   if (call_api(PTR_DIFF(p,param),0,
3808                6,1000,
3809                &rprcnt,&rdrcnt,
3810                param,NULL,
3811                &rparam,&rdata))
3812     {
3813       int res = SVAL(rparam,0);
3814       int converter=SVAL(rparam,2);
3815
3816       if (res == 0)
3817         {
3818       p = rdata;
3819
3820       printf("\nServer=[%s] User=[%s] Workgroup=[%s] Domain=[%s]\n",
3821              rdata+SVAL(p,0)-converter,
3822              rdata+SVAL(p,4)-converter,
3823              rdata+SVAL(p,8)-converter,
3824              rdata+SVAL(p,14)-converter);
3825     }
3826     }
3827
3828   if (rparam) free(rparam);
3829   if (rdata) free(rdata);
3830
3831   return;
3832 }
3833
3834
3835 /****************************************************************************
3836 try and browse available connections on a host
3837 ****************************************************************************/
3838 static BOOL list_servers(char *wk_grp)
3839 {
3840   char *rparam = NULL;
3841   char *rdata = NULL;
3842   int rdrcnt,rprcnt;
3843   char *p,*svtype_p;
3844   pstring param;
3845   int uLevel = 1;
3846   int count = 0;
3847   BOOL ok = False;
3848   BOOL generic_request = False;
3849
3850
3851   if (strequal(wk_grp,"WORKGROUP")) {
3852     /* we won't specify a workgroup */
3853     generic_request = True;
3854   } 
3855
3856   /* now send a SMBtrans command with api ServerEnum? */
3857   p = param;
3858   SSVAL(p,0,0x68); /* api number */
3859   p += 2;
3860
3861   strcpy(p,generic_request?"WrLehDO":"WrLehDz");
3862   p = skip_string(p,1);
3863
3864   strcpy(p,"B16BBDz");
3865
3866   p = skip_string(p,1);
3867   SSVAL(p,0,uLevel);
3868   SSVAL(p,2,0x2000); /* buf length */
3869   p += 4;
3870
3871   svtype_p = p;
3872   p += 4;
3873
3874   if (!generic_request) {
3875     strcpy(p, wk_grp);
3876     p = skip_string(p,1);
3877   }
3878
3879   /* first ask for a list of servers in this workgroup */
3880   SIVAL(svtype_p,0,SV_TYPE_ALL);
3881
3882   if (call_api(PTR_DIFF(p+4,param),0,
3883                8,10000,
3884                &rprcnt,&rdrcnt,
3885                param,NULL,
3886                &rparam,&rdata))
3887     {
3888       int res = SVAL(rparam,0);
3889       int converter=SVAL(rparam,2);
3890       int i;
3891
3892       if (res == 0) {   
3893         char *p2 = rdata;
3894         count=SVAL(rparam,4);
3895
3896         if (count > 0) {
3897           printf("\n\nThis machine has a browse list:\n");
3898           printf("\n\tServer               Comment\n");
3899           printf("\t---------            -------\n");
3900         }
3901         
3902         for (i=0;i<count;i++) {
3903           char *sname = p2;
3904           int comment_offset = IVAL(p2,22) & 0xFFFF;
3905           printf("\t%-16.16s     %s\n",
3906                  sname,
3907                  comment_offset?rdata+comment_offset-converter:"");
3908
3909           ok=True;
3910           p2 += 26;
3911         }
3912       }
3913     }
3914
3915   if (rparam) {free(rparam); rparam = NULL;}
3916   if (rdata) {free(rdata); rdata = NULL;}
3917
3918   /* now ask for a list of workgroups */
3919   SIVAL(svtype_p,0,SV_TYPE_DOMAIN_ENUM);
3920
3921   if (call_api(PTR_DIFF(p+4,param),0,
3922                8,10000,
3923                &rprcnt,&rdrcnt,
3924                param,NULL,
3925                &rparam,&rdata))
3926     {
3927       int res = SVAL(rparam,0);
3928       int converter=SVAL(rparam,2);
3929       int i;
3930
3931       if (res == 0) {
3932         char *p2 = rdata;
3933         count=SVAL(rparam,4);
3934
3935         if (count > 0) {
3936           printf("\n\nThis machine has a workgroup list:\n");
3937           printf("\n\tWorkgroup            Master\n");
3938           printf("\t---------            -------\n");
3939         }
3940         
3941         for (i=0;i<count;i++) {
3942           char *sname = p2;
3943           int comment_offset = IVAL(p2,22) & 0xFFFF;
3944           printf("\t%-16.16s     %s\n",
3945                  sname,
3946                  comment_offset?rdata+comment_offset-converter:"");
3947           
3948           ok=True;
3949           p2 += 26;
3950         }
3951       }
3952     }
3953
3954   if (rparam) free(rparam);
3955   if (rdata) free(rdata);
3956
3957   return(ok);
3958 }
3959
3960
3961 /* This defines the commands supported by this client */
3962 struct
3963 {
3964   char *name;
3965   void (*fn)();
3966   char *description;
3967 } commands[] = 
3968 {
3969   {"ls",cmd_dir,"<mask> list the contents of the current directory"},
3970   {"dir",cmd_dir,"<mask> list the contents of the current directory"},
3971   {"lcd",cmd_lcd,"[directory] change/report the local current working directory"},
3972   {"cd",cmd_cd,"[directory] change/report the remote directory"},
3973   {"pwd",cmd_pwd,"show current remote directory (same as 'cd' with no args)"},
3974   {"get",cmd_get,"<remote name> [local name] get a file"},
3975   {"mget",cmd_mget,"<mask> get all the matching files"},
3976   {"put",cmd_put,"<local name> [remote name] put a file"},
3977   {"mput",cmd_mput,"<mask> put all matching files"},
3978   {"rename",cmd_rename,"<src> <dest> rename some files"},
3979   {"more",cmd_more,"<remote name> view a remote file with your pager"},  
3980   {"mask",cmd_select,"<mask> mask all filenames against this"},
3981   {"del",cmd_del,"<mask> delete all matching files"},
3982   {"rm",cmd_del,"<mask> delete all matching files"},
3983   {"mkdir",cmd_mkdir,"<directory> make a directory"},
3984   {"md",cmd_mkdir,"<directory> make a directory"},
3985   {"rmdir",cmd_rmdir,"<directory> remove a directory"},
3986   {"rd",cmd_rmdir,"<directory> remove a directory"},
3987   {"pq",cmd_p_queue_4,"enumerate the print queue"},
3988   {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput"},  
3989   {"recurse",cmd_recurse,"toggle directory recursion for mget and mput"},  
3990   {"translate",cmd_translate,"toggle text translation for printing"},  
3991   {"lowercase",cmd_lowercase,"toggle lowercasing of filenames for get"},  
3992   {"print",cmd_print,"<file name> print a file"},
3993   {"printmode",cmd_printmode,"<graphics or text> set the print mode"},
3994   {"queue",cmd_queue,"show the print queue"},
3995   {"qinfo",cmd_qinfo,"show print queue information"},
3996   {"cancel",cmd_cancel,"<jobid> cancel a print queue entry"},
3997   {"stat",cmd_stat,"<file> get info on a file (experimental!)"},
3998   {"quit",send_logout,"logoff the server"},
3999   {"q",send_logout,"logoff the server"},
4000   {"exit",send_logout,"logoff the server"},
4001   {"newer",cmd_newer,"<file> only mget files newer than the specified local file"},
4002   {"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"},
4003   {"tar",cmd_tar,"tar <c|x>[IXbgNa] current directory to/from <file name>" },
4004   {"blocksize",cmd_block,"blocksize <number> (default 20)" },
4005   {"tarmode",cmd_tarmode,
4006      "<full|inc|reset|noreset> tar's behaviour towards archive bits" },
4007   {"setmode",cmd_setmode,"filename <setmode string> change modes of file"},
4008   {"help",cmd_help,"[command] give help on a command"},
4009   {"?",cmd_help,"[command] give help on a command"},
4010   {"!",NULL,"run a shell command on the local system"},
4011   {"",NULL,NULL}
4012 };
4013
4014
4015 /*******************************************************************
4016   lookup a command string in the list of commands, including 
4017   abbreviations
4018   ******************************************************************/
4019 static int process_tok(fstring tok)
4020 {
4021   int i = 0, matches = 0;
4022   int cmd=0;
4023   int tok_len = strlen(tok);
4024   
4025   while (commands[i].fn != NULL)
4026     {
4027       if (strequal(commands[i].name,tok))
4028         {
4029           matches = 1;
4030           cmd = i;
4031           break;
4032         }
4033       else if (strnequal(commands[i].name, tok, tok_len+1))
4034         {
4035           matches++;
4036           cmd = i;
4037         }
4038       i++;
4039     }
4040   
4041   if (matches == 0)
4042     return(-1);
4043   else if (matches == 1)
4044     return(cmd);
4045   else
4046     return(-2);
4047 }
4048
4049 /****************************************************************************
4050 help
4051 ****************************************************************************/
4052 void cmd_help(void)
4053 {
4054   int i=0,j;
4055   fstring buf;
4056
4057   if (next_token(NULL,buf,NULL))
4058     {
4059       if ((i = process_tok(buf)) >= 0)
4060         DEBUG(0,("HELP %s:\n\t%s\n\n",commands[i].name,commands[i].description));                   
4061     }
4062   else
4063     while (commands[i].description)
4064       {
4065         for (j=0; commands[i].description && (j<5); j++) {
4066           DEBUG(0,("%-15s",commands[i].name));
4067           i++;
4068         }
4069         DEBUG(0,("\n"));
4070       }
4071 }
4072
4073 /****************************************************************************
4074 open the client sockets
4075 ****************************************************************************/
4076 static BOOL open_sockets(int port )
4077 {
4078   static int last_port;
4079   char *host;
4080   pstring service2;
4081   extern int Client;
4082 #ifdef USENMB
4083   BOOL failed = True;
4084 #endif
4085
4086   if (port == 0) port=last_port;
4087   last_port=port;
4088
4089   strupper(service);
4090
4091   if (*desthost)
4092     {
4093       host = desthost;
4094     }
4095   else
4096     {
4097       strcpy(service2,service);
4098       host = strtok(service2,"\\/");
4099       if (!host) {
4100         DEBUG(0,("Badly formed host name\n"));
4101         return(False);
4102       }
4103       strcpy(desthost,host);
4104     }
4105
4106   if (*myname == 0) {
4107       get_myname(myname,NULL);
4108   }
4109   strupper(myname);
4110
4111   DEBUG(3,("Opening sockets\n"));
4112
4113   if (!have_ip)
4114     {
4115       struct hostent *hp;
4116
4117       if ((hp = Get_Hostbyname(host))) {
4118         putip((char *)&dest_ip,(char *)hp->h_addr);
4119         failed = False;
4120       } else {
4121 #ifdef USENMB
4122         /* Try and resolve the name with the netbios server */
4123         int             bcast;
4124
4125         if ((bcast = open_socket_in(SOCK_DGRAM, 0, 3,
4126                                     interpret_addr(lp_socket_address()))) != -1) {
4127           set_socket_options(bcast, "SO_BROADCAST");
4128
4129           if (name_query(bcast, host, name_type, True, True, *iface_bcast(dest_ip),
4130                          &dest_ip,0)) {
4131             failed = False;
4132           }
4133           close (bcast);
4134         }
4135 #endif
4136         if (failed) {
4137           DEBUG(0,("Get_Hostbyname: Unknown host %s.\n",host));
4138           return False;
4139         }
4140       }
4141     }
4142
4143   Client = open_socket_out(SOCK_STREAM, &dest_ip, port, LONG_CONNECT_TIMEOUT);
4144   if (Client == -1)
4145     return False;
4146
4147   DEBUG(3,("Connected\n"));
4148   
4149   set_socket_options(Client,user_socket_options);  
4150   
4151   return True;
4152 }
4153
4154 /****************************************************************************
4155 wait for keyboard activity, swallowing network packets
4156 ****************************************************************************/
4157 #ifdef CLIX
4158 static char wait_keyboard(char *buffer)
4159 #else
4160 static void wait_keyboard(char *buffer)
4161 #endif
4162 {
4163   fd_set fds;
4164   int selrtn;
4165   struct timeval timeout;
4166   
4167 #ifdef CLIX
4168   int delay = 0;
4169 #endif
4170   
4171   while (1) 
4172     {
4173       extern int Client;
4174       FD_ZERO(&fds);
4175       FD_SET(Client,&fds);
4176 #ifndef CLIX
4177       FD_SET(fileno(stdin),&fds);
4178 #endif
4179
4180       timeout.tv_sec = 20;
4181       timeout.tv_usec = 0;
4182 #ifdef CLIX
4183       timeout.tv_sec = 0;
4184 #endif
4185       selrtn = sys_select(&fds,&timeout);
4186       
4187 #ifndef CLIX
4188       if (FD_ISSET(fileno(stdin),&fds))
4189         return;
4190 #else
4191       {
4192         char ch;
4193         int f_flags;
4194         int readret;
4195         
4196         f_flags = fcntl(fileno(stdin), F_GETFL, 0);
4197         fcntl( fileno(stdin), F_SETFL, f_flags | O_NONBLOCK);
4198         readret = read_data( fileno(stdin), &ch, 1);
4199         fcntl(fileno(stdin), F_SETFL, f_flags);
4200         if (readret == -1)
4201           {
4202             if (errno != EAGAIN)
4203               {
4204                 /* should crash here */
4205                 DEBUG(1,("readchar stdin failed\n"));
4206               }
4207           }
4208         else if (readret != 0)
4209           {
4210             return ch;
4211           }
4212       }
4213 #endif
4214       if (FD_ISSET(Client,&fds))
4215         receive_smb(Client,buffer,0);
4216       
4217 #ifdef CLIX
4218       delay++;
4219       if (delay > 100000)
4220         {
4221           delay = 0;
4222           chkpath("\\",False);
4223         }
4224 #else
4225       chkpath("\\",False);
4226 #endif
4227     }  
4228 }
4229
4230
4231 /****************************************************************************
4232 close and open the connection again
4233 ****************************************************************************/
4234 BOOL reopen_connection(char *inbuf,char *outbuf)
4235 {
4236   static int open_count=0;
4237
4238   open_count++;
4239
4240   if (open_count>5) return(False);
4241
4242   DEBUG(1,("Trying to re-open connection\n"));
4243
4244   set_message(outbuf,0,0,True);
4245   SCVAL(outbuf,smb_com,SMBtdis);
4246   SSVAL(outbuf,smb_tid,cnum);
4247   setup_pkt(outbuf);
4248
4249   send_smb(Client,outbuf);
4250   receive_smb(Client,inbuf,SHORT_TIMEOUT);
4251
4252   close_sockets();
4253   if (!open_sockets(0)) return(False);
4254
4255   return(send_login(inbuf,outbuf,True,True));
4256 }
4257
4258 /****************************************************************************
4259   process commands from the client
4260 ****************************************************************************/
4261 static BOOL process(char *base_directory)
4262 {
4263   extern FILE *dbf;
4264   pstring line;
4265   char *cmd;
4266
4267   char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
4268   char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
4269
4270   if ((InBuffer == NULL) || (OutBuffer == NULL)) 
4271     return(False);
4272   
4273   bzero(OutBuffer,smb_size);
4274
4275   if (!send_login(InBuffer,OutBuffer,True,True))
4276     return(False);
4277
4278   if (*base_directory) do_cd(base_directory);
4279
4280   cmd = cmdstr;
4281   if (cmd[0] != '\0') while (cmd[0] != '\0')
4282     {
4283       char *p;
4284       fstring tok;
4285       int i;
4286
4287       if ((p = strchr(cmd, ';')) == 0)
4288         {
4289           strncpy(line, cmd, 999);
4290           line[1000] = '\0';
4291           cmd += strlen(cmd);
4292         }
4293       else
4294         {
4295           if (p - cmd > 999) p = cmd + 999;
4296           strncpy(line, cmd, p - cmd);
4297           line[p - cmd] = '\0';
4298           cmd = p + 1;
4299         }
4300
4301       /* input language code to internal one */
4302       CNV_INPUT (line);
4303       
4304       /* and get the first part of the command */
4305       {
4306         char *ptr = line;
4307         if (!next_token(&ptr,tok,NULL)) continue;
4308       }
4309
4310       if ((i = process_tok(tok)) >= 0)
4311         commands[i].fn(InBuffer,OutBuffer);
4312       else if (i == -2)
4313         DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok)));
4314       else
4315         DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
4316     }
4317   else while (!feof(stdin))
4318     {
4319       fstring tok;
4320       int i;
4321
4322       bzero(OutBuffer,smb_size);
4323
4324       /* display a prompt */
4325       DEBUG(1,("smb: %s> ", CNV_LANG(cur_dir)));
4326       fflush(dbf);
4327
4328 #ifdef CLIX
4329       line[0] = wait_keyboard(InBuffer);
4330       /* this might not be such a good idea... */
4331       if ( line[0] == EOF)
4332         break;
4333 #else
4334       wait_keyboard(InBuffer);
4335 #endif
4336   
4337       /* and get a response */
4338 #ifdef CLIX
4339       fgets( &line[1],999, stdin);
4340 #else
4341       if (!fgets(line,1000,stdin))
4342         break;
4343 #endif
4344
4345       /* input language code to internal one */
4346       CNV_INPUT (line);
4347
4348       /* special case - first char is ! */
4349       if (*line == '!')
4350         {
4351           system(line + 1);
4352           continue;
4353         }
4354       
4355       /* and get the first part of the command */
4356       {
4357         char *ptr = line;
4358         if (!next_token(&ptr,tok,NULL)) continue;
4359       }
4360
4361       if ((i = process_tok(tok)) >= 0)
4362         commands[i].fn(InBuffer,OutBuffer);
4363       else if (i == -2)
4364         DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok)));
4365       else
4366         DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
4367     }
4368   
4369   send_logout();
4370   return(True);
4371 }
4372
4373
4374 /****************************************************************************
4375 usage on the program
4376 ****************************************************************************/
4377 static void usage(char *pname)
4378 {
4379   DEBUG(0,("Usage: %s service <password> [-p port] [-d debuglevel] [-l log] ",
4380            pname));
4381
4382 #ifdef KANJI
4383   DEBUG(0,("[-t termcode] "));
4384 #endif /* KANJI */
4385
4386   DEBUG(0,("\nVersion %s\n",VERSION));
4387   DEBUG(0,("\t-p port               listen on the specified port\n"));
4388   DEBUG(0,("\t-d debuglevel         set the debuglevel\n"));
4389   DEBUG(0,("\t-l log basename.      Basename for log/debug files\n"));
4390   DEBUG(0,("\t-n netbios name.      Use this name as my netbios name\n"));
4391   DEBUG(0,("\t-N                    don't ask for a password\n"));
4392   DEBUG(0,("\t-P                    connect to service as a printer\n"));
4393   DEBUG(0,("\t-M host               send a winpopup message to the host\n"));
4394   DEBUG(0,("\t-m max protocol       set the max protocol level\n"));
4395   DEBUG(0,("\t-L host               get a list of shares available on a host\n"));
4396   DEBUG(0,("\t-I dest IP            use this IP to connect to\n"));
4397   DEBUG(0,("\t-E                    write messages to stderr instead of stdout\n"));
4398   DEBUG(0,("\t-U username           set the network username\n"));
4399   DEBUG(0,("\t-W workgroup          set the workgroup name\n"));
4400   DEBUG(0,("\t-c command string     execute semicolon separated commands\n"));
4401 #ifdef KANJI
4402   DEBUG(0,("\t-t terminal code      terminal i/o code {sjis|euc|jis7|jis8|junet|hex}\n"));
4403 #endif /* KANJI */
4404   DEBUG(0,("\t-T<c|x>IXgbNa          command line tar\n"));
4405   DEBUG(0,("\t-D directory          start from directory\n"));
4406   DEBUG(0,("\n"));
4407 }
4408
4409 /****************************************************************************
4410   main program
4411 ****************************************************************************/
4412  int main(int argc,char *argv[])
4413 {
4414   fstring base_directory;
4415   char *pname = argv[0];
4416   int port = SMB_PORT;
4417   int opt;
4418   extern FILE *dbf;
4419   extern char *optarg;
4420   extern int optind;
4421   pstring query_host;
4422   BOOL message = False;
4423   extern char tar_type;
4424   static pstring servicesf = CONFIGFILE;
4425
4426   *query_host = 0;
4427   *base_directory = 0;
4428
4429   DEBUGLEVEL = 2;
4430
4431   setup_logging(pname,True);
4432
4433   TimeInit();
4434   charset_initialise();
4435
4436   pid = getpid();
4437   uid = getuid();
4438   gid = getgid();
4439   mid = pid + 100;
4440   myumask = umask(0);
4441   umask(myumask);
4442
4443   if (getenv("USER"))
4444     {
4445       strcpy(username,getenv("USER"));
4446       strupper(username);
4447     }
4448
4449   if (*username == 0 && getenv("LOGNAME"))
4450     {
4451       strcpy(username,getenv("LOGNAME"));
4452       strupper(username);
4453     }
4454
4455   if (argc < 2)
4456     {
4457       usage(pname);
4458       exit(1);
4459     }
4460   
4461   if (*argv[1] != '-')
4462     {
4463
4464       strcpy(service,argv[1]);  
4465       /* Convert any '/' characters in the service name to '\' characters */
4466       string_replace( service, '/','\\');
4467       argc--;
4468       argv++;
4469
4470       if (count_chars(service,'\\') < 3)
4471         {
4472           usage(pname);
4473           printf("\n%s: Not enough '\\' characters in service\n",service);
4474           exit(1);
4475         }
4476
4477 /*
4478       if (count_chars(service,'\\') > 3)
4479         {
4480           usage(pname);
4481           printf("\n%s: Too many '\\' characters in service\n",service);
4482           exit(1);
4483         }
4484         */
4485
4486       if (argc > 1 && (*argv[1] != '-'))
4487         {
4488           got_pass = True;
4489           strcpy(password,argv[1]);  
4490           memset(argv[1],'X',strlen(argv[1]));
4491           argc--;
4492           argv++;
4493         }
4494     }
4495
4496 #ifdef KANJI
4497   setup_term_code (KANJI);
4498 #endif
4499   while ((opt = 
4500           getopt(argc, argv,"s:B:O:M:i:Nn:d:Pp:l:hI:EB:U:L:t:m:W:T:D:c:")) != EOF)
4501     switch (opt)
4502       {
4503       case 'm':
4504         max_protocol = interpret_protocol(optarg,max_protocol);
4505         break;
4506       case 'O':
4507         strcpy(user_socket_options,optarg);
4508         break;  
4509       case 'M':
4510         name_type = 0x03; /* messages are sent to NetBIOS name type 0x3 */
4511         strcpy(desthost,optarg);
4512         strupper(desthost);
4513         message = True;
4514         break;
4515       case 'B':
4516         iface_set_default(NULL,optarg,NULL);
4517         break;
4518       case 'D':
4519         strcpy(base_directory,optarg);
4520         break;
4521       case 'T':
4522         if (!tar_parseargs(argc, argv, optarg, optind)) {
4523           usage(pname);
4524           exit(1);
4525         }
4526         break;
4527       case 'i':
4528         strcpy(scope,optarg);
4529         break;
4530       case 'L':
4531         got_pass = True;
4532         strcpy(query_host,optarg);
4533         break;
4534       case 'U':
4535         {
4536           char *p;
4537         strcpy(username,optarg);
4538         if ((p=strchr(username,'%')))
4539           {
4540             *p = 0;
4541             strcpy(password,p+1);
4542             got_pass = True;
4543             memset(strchr(optarg,'%')+1,'X',strlen(password));
4544           }
4545         }
4546             
4547         break;
4548       case 'W':
4549         strcpy(workgroup,optarg);
4550         break;
4551       case 'E':
4552         dbf = stderr;
4553         break;
4554       case 'I':
4555         {
4556           dest_ip = *interpret_addr2(optarg);
4557           if (zero_ip(dest_ip)) exit(1);
4558           have_ip = True;
4559         }
4560         break;
4561       case 'n':
4562         strcpy(myname,optarg);
4563         break;
4564       case 'N':
4565         got_pass = True;
4566         break;
4567       case 'P':
4568         connect_as_printer = True;
4569         break;
4570       case 'd':
4571         if (*optarg == 'A')
4572           DEBUGLEVEL = 10000;
4573         else
4574           DEBUGLEVEL = atoi(optarg);
4575         break;
4576       case 'l':
4577         sprintf(debugf,"%s.client",optarg);
4578         break;
4579       case 'p':
4580         port = atoi(optarg);
4581         break;
4582       case 'c':
4583         cmdstr = optarg;
4584         got_pass = True;
4585         break;
4586       case 'h':
4587         usage(pname);
4588         exit(0);
4589         break;
4590       case 's':
4591         strcpy(servicesf, optarg);
4592         break;
4593       case 't':
4594 #ifdef KANJI
4595         if (!setup_term_code (optarg)) {
4596             DEBUG(0, ("%s: unknown terminal code name\n", optarg));
4597             usage (pname);
4598             exit (1);
4599         }
4600 #endif
4601         break;
4602       default:
4603         usage(pname);
4604         exit(1);
4605       }
4606
4607   if (!tar_type && !*query_host && !*service && !message)
4608     {
4609       usage(pname);
4610       exit(1);
4611     }
4612
4613
4614   DEBUG(3,("%s client started (version %s)\n",timestring(),VERSION));
4615
4616   if (!lp_load(servicesf,True)) {
4617     fprintf(stderr, "Can't load %s - run testparm to debug it\n", servicesf);
4618   }
4619
4620   if (*workgroup == 0)
4621     strcpy(workgroup,lp_workgroup());
4622
4623   load_interfaces();
4624   get_myname(*myname?NULL:myname,NULL);  
4625   strupper(myname);
4626
4627   if (tar_type) {
4628     recurse=True;
4629
4630     if (open_sockets(port)) {
4631         char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
4632         char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
4633         int ret;
4634
4635         if ((InBuffer == NULL) || (OutBuffer == NULL)) 
4636           return(1);
4637
4638         bzero(OutBuffer,smb_size);
4639         if (!send_login(InBuffer,OutBuffer,True,True))
4640           return(False);
4641
4642         if (*base_directory) do_cd(base_directory);
4643
4644         ret=process_tar(InBuffer, OutBuffer);
4645
4646         send_logout();
4647         close_sockets();
4648         return(ret);
4649     } else
4650       return(1);
4651   }
4652   
4653   if (*query_host)
4654     {
4655       int ret = 0;
4656       sprintf(service,"\\\\%s\\IPC$",query_host);
4657       strupper(service);
4658       connect_as_ipc = True;
4659       if (open_sockets(port))
4660         {
4661 #if 0
4662           *username = 0;
4663 #endif
4664           if (!send_login(NULL,NULL,True,True))
4665             return(1);
4666
4667           server_info();
4668           if (!browse_host(True)) {
4669             sleep(1);
4670             browse_host(True);
4671           }
4672           if (!list_servers(workgroup)) {
4673             sleep(1);
4674             list_servers(workgroup);
4675           }
4676
4677           send_logout();
4678           close_sockets();
4679         }
4680
4681       return(ret);
4682     }
4683
4684   if (message)
4685     {
4686       int ret = 0;
4687       if (open_sockets(port))
4688         {
4689           pstring inbuf,outbuf;
4690           bzero(outbuf,smb_size);
4691           if (!send_session_request(inbuf,outbuf))
4692             return(1);
4693
4694           send_message(inbuf,outbuf);
4695
4696           close_sockets();
4697         }
4698
4699       return(ret);
4700     }
4701
4702   if (open_sockets(port))
4703     {
4704       if (!process(base_directory))
4705         {
4706           close_sockets();
4707           return(1);
4708         }
4709       close_sockets();
4710     }
4711   else
4712     return(1);
4713
4714   return(0);
4715 }
4716
4717
4718 /* error code stuff - put together by Merik Karman
4719    merik@blackadder.dsh.oz.au */
4720
4721 typedef struct
4722 {
4723   char *name;
4724   int code;
4725   char *message;
4726 } err_code_struct;
4727
4728 /* Dos Error Messages */
4729 err_code_struct dos_msgs[] = {
4730   {"ERRbadfunc",1,"Invalid function."},
4731   {"ERRbadfile",2,"File not found."},
4732   {"ERRbadpath",3,"Directory invalid."},
4733   {"ERRnofids",4,"No file descriptors available"},
4734   {"ERRnoaccess",5,"Access denied."},
4735   {"ERRbadfid",6,"Invalid file handle."},
4736   {"ERRbadmcb",7,"Memory control blocks destroyed."},
4737   {"ERRnomem",8,"Insufficient server memory to perform the requested function."},
4738   {"ERRbadmem",9,"Invalid memory block address."},
4739   {"ERRbadenv",10,"Invalid environment."},
4740   {"ERRbadformat",11,"Invalid format."},
4741   {"ERRbadaccess",12,"Invalid open mode."},
4742   {"ERRbaddata",13,"Invalid data."},
4743   {"ERR",14,"reserved."},
4744   {"ERRbaddrive",15,"Invalid drive specified."},
4745   {"ERRremcd",16,"A Delete Directory request attempted  to  remove  the  server's  current directory."},
4746   {"ERRdiffdevice",17,"Not same device."},
4747   {"ERRnofiles",18,"A File Search command can find no more files matching the specified criteria."},
4748   {"ERRbadshare",32,"The sharing mode specified for an Open conflicts with existing  FIDs  on the file."},
4749   {"ERRlock",33,"A Lock request conflicted with an existing lock or specified an  invalid mode,  or an Unlock requested attempted to remove a lock held by another process."},
4750   {"ERRfilexists",80,"The file named in a Create Directory, Make  New  File  or  Link  request already exists."},
4751   {"ERRbadpipe",230,"Pipe invalid."},
4752   {"ERRpipebusy",231,"All instances of the requested pipe are busy."},
4753   {"ERRpipeclosing",232,"Pipe close in progress."},
4754   {"ERRnotconnected",233,"No process on other end of pipe."},
4755   {"ERRmoredata",234,"There is more data to be returned."},
4756   {"ERRinvgroup",2455,"Invalid workgroup (try the -W option)"},
4757   {NULL,-1,NULL}};
4758
4759 /* Server Error Messages */
4760 err_code_struct server_msgs[] = {
4761   {"ERRerror",1,"Non-specific error code."},
4762   {"ERRbadpw",2,"Bad password - name/password pair in a Tree Connect or Session Setup are invalid."},
4763   {"ERRbadtype",3,"reserved."},
4764   {"ERRaccess",4,"The requester does not have  the  necessary  access  rights  within  the specified  context for the requested function. The context is defined by the TID or the UID."},
4765   {"ERRinvnid",5,"The tree ID (TID) specified in a command was invalid."},
4766   {"ERRinvnetname",6,"Invalid network name in tree connect."},
4767   {"ERRinvdevice",7,"Invalid device - printer request made to non-printer connection or  non-printer request made to printer connection."},
4768   {"ERRqfull",49,"Print queue full (files) -- returned by open print file."},
4769   {"ERRqtoobig",50,"Print queue full -- no space."},
4770   {"ERRqeof",51,"EOF on print queue dump."},
4771   {"ERRinvpfid",52,"Invalid print file FID."},
4772   {"ERRsmbcmd",64,"The server did not recognize the command received."},
4773   {"ERRsrverror",65,"The server encountered an internal error, e.g., system file unavailable."},
4774   {"ERRfilespecs",67,"The file handle (FID) and pathname parameters contained an invalid  combination of values."},
4775   {"ERRreserved",68,"reserved."},
4776   {"ERRbadpermits",69,"The access permissions specified for a file or directory are not a valid combination.  The server cannot set the requested attribute."},
4777   {"ERRreserved",70,"reserved."},
4778   {"ERRsetattrmode",71,"The attribute mode in the Set File Attribute request is invalid."},
4779   {"ERRpaused",81,"Server is paused."},
4780   {"ERRmsgoff",82,"Not receiving messages."},
4781   {"ERRnoroom",83,"No room to buffer message."},
4782   {"ERRrmuns",87,"Too many remote user names."},
4783   {"ERRtimeout",88,"Operation timed out."},
4784   {"ERRnoresource",89,"No resources currently available for request."},
4785   {"ERRtoomanyuids",90,"Too many UIDs active on this session."},
4786   {"ERRbaduid",91,"The UID is not known as a valid ID on this session."},
4787   {"ERRusempx",250,"Temp unable to support Raw, use MPX mode."},
4788   {"ERRusestd",251,"Temp unable to support Raw, use standard read/write."},
4789   {"ERRcontmpx",252,"Continue in MPX mode."},
4790   {"ERRreserved",253,"reserved."},
4791   {"ERRreserved",254,"reserved."},
4792   {"ERRnosupport",0xFFFF,"Function not supported."},
4793   {NULL,-1,NULL}};
4794
4795 /* Hard Error Messages */
4796 err_code_struct hard_msgs[] = {
4797   {"ERRnowrite",19,"Attempt to write on write-protected diskette."},
4798   {"ERRbadunit",20,"Unknown unit."},
4799   {"ERRnotready",21,"Drive not ready."},
4800   {"ERRbadcmd",22,"Unknown command."},
4801   {"ERRdata",23,"Data error (CRC)."},
4802   {"ERRbadreq",24,"Bad request structure length."},
4803   {"ERRseek",25 ,"Seek error."},
4804   {"ERRbadmedia",26,"Unknown media type."},
4805   {"ERRbadsector",27,"Sector not found."},
4806   {"ERRnopaper",28,"Printer out of paper."},
4807   {"ERRwrite",29,"Write fault."},
4808   {"ERRread",30,"Read fault."},
4809   {"ERRgeneral",31,"General failure."},
4810   {"ERRbadshare",32,"A open conflicts with an existing open."},
4811   {"ERRlock",33,"A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."},
4812   {"ERRwrongdisk",34,"The wrong disk was found in a drive."},
4813   {"ERRFCBUnavail",35,"No FCBs are available to process request."},
4814   {"ERRsharebufexc",36,"A sharing buffer has been exceeded."},
4815   {NULL,-1,NULL}};
4816
4817
4818 struct
4819 {
4820   int code;
4821   char *class;
4822   err_code_struct *err_msgs;
4823 } err_classes[] = { 
4824   {0,"SUCCESS",NULL},
4825   {0x01,"ERRDOS",dos_msgs},
4826   {0x02,"ERRSRV",server_msgs},
4827   {0x03,"ERRHRD",hard_msgs},
4828   {0x04,"ERRXOS",NULL},
4829   {0xE1,"ERRRMX1",NULL},
4830   {0xE2,"ERRRMX2",NULL},
4831   {0xE3,"ERRRMX3",NULL},
4832   {0xFF,"ERRCMD",NULL},
4833   {-1,NULL,NULL}};
4834
4835
4836 /****************************************************************************
4837 return a SMB error string from a SMB buffer
4838 ****************************************************************************/
4839 char *smb_errstr(char *inbuf)
4840 {
4841   static pstring ret;
4842   int class = CVAL(inbuf,smb_rcls);
4843   int num = SVAL(inbuf,smb_err);
4844   int i,j;
4845
4846   for (i=0;err_classes[i].class;i++)
4847     if (err_classes[i].code == class)
4848       {
4849         if (err_classes[i].err_msgs)
4850           {
4851             err_code_struct *err = err_classes[i].err_msgs;
4852             for (j=0;err[j].name;j++)
4853               if (num == err[j].code)
4854                 {
4855                   if (DEBUGLEVEL > 0)
4856                     sprintf(ret,"%s - %s (%s)",err_classes[i].class,
4857                             err[j].name,err[j].message);
4858                   else
4859                     sprintf(ret,"%s - %s",err_classes[i].class,err[j].name);
4860                   return ret;
4861                 }
4862           }
4863
4864         sprintf(ret,"%s - %d",err_classes[i].class,num);
4865         return ret;
4866       }
4867   
4868   sprintf(ret,"ERROR: Unknown error (%d,%d)",class,num);
4869   return(ret);
4870 }