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