fix up problems with "smbclient -L". It now uses a generic
[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 static struct {
2878   int prot;
2879   char *name;
2880 } prots[] = {
2881   {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"},
2882   {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
2883   {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
2884   {PROTOCOL_LANMAN1,"LANMAN1.0"},
2885   {PROTOCOL_LANMAN2,"LM1.2X002"},
2886   {PROTOCOL_LANMAN2,"Samba"},
2887   {PROTOCOL_NT1,"NT LM 0.12"},
2888   {PROTOCOL_NT1,"NT LANMAN 1.0"},
2889   {-1,NULL}
2890 };
2891
2892
2893 /****************************************************************************
2894 send a login command
2895 ****************************************************************************/
2896 static BOOL send_login(char *inbuf,char *outbuf,BOOL start_session,BOOL use_setup)
2897 {
2898   BOOL was_null = (!inbuf && !outbuf);
2899   int sesskey=0;
2900   time_t servertime = 0;
2901   extern int serverzone;
2902   int sec_mode=0;
2903   int crypt_len;
2904   int max_vcs=0;
2905   char *pass = NULL;  
2906   pstring dev;
2907   char *p;
2908   int numprots;
2909
2910   if (was_null)
2911     {
2912       inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
2913       outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
2914     }
2915
2916 #if AJT
2917   if (strstr(service,"IPC$")) connect_as_ipc = True;
2918 #endif
2919
2920   strcpy(dev,"A:");
2921   if (connect_as_printer)
2922     strcpy(dev,"LPT1:");
2923   if (connect_as_ipc)
2924     strcpy(dev,"IPC");
2925
2926
2927   if (start_session && !send_session_request(inbuf,outbuf))
2928     {
2929       if (was_null)
2930         {
2931           free(inbuf);
2932           free(outbuf);
2933         }      
2934       return(False);
2935     }
2936
2937   bzero(outbuf,smb_size);
2938
2939   /* setup the protocol strings */
2940   {
2941     int plength;
2942
2943     for (plength=0,numprots=0;
2944          prots[numprots].name && prots[numprots].prot<=max_protocol;
2945          numprots++)
2946       plength += strlen(prots[numprots].name)+2;
2947     
2948     set_message(outbuf,0,plength,True);
2949
2950     p = smb_buf(outbuf);
2951     for (numprots=0;
2952          prots[numprots].name && prots[numprots].prot<=max_protocol;
2953          numprots++)
2954       {
2955         *p++ = 2;
2956         strcpy(p,prots[numprots].name);
2957         p += strlen(p) + 1;
2958       }
2959   }
2960
2961   CVAL(outbuf,smb_com) = SMBnegprot;
2962   setup_pkt(outbuf);
2963
2964   CVAL(smb_buf(outbuf),0) = 2;
2965
2966   send_smb(Client,outbuf);
2967   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
2968
2969   show_msg(inbuf);
2970
2971   if (CVAL(inbuf,smb_rcls) != 0 || ((int)SVAL(inbuf,smb_vwv0) >= numprots))
2972     {
2973       DEBUG(0,("SMBnegprot failed. myname=%s destname=%s - %s \n",
2974             myname,desthost,smb_errstr(inbuf)));
2975       if (was_null)
2976         {
2977           free(inbuf);
2978           free(outbuf);
2979         }
2980       return(False);
2981     }
2982
2983   Protocol = prots[SVAL(inbuf,smb_vwv0)].prot;
2984
2985
2986   if (Protocol < PROTOCOL_NT1) {    
2987     sec_mode = SVAL(inbuf,smb_vwv1);
2988     max_xmit = SVAL(inbuf,smb_vwv2);
2989     sesskey = IVAL(inbuf,smb_vwv6);
2990     serverzone = SVALS(inbuf,smb_vwv10)*60;
2991     /* this time is converted to GMT by make_unix_date */
2992     servertime = make_unix_date(inbuf+smb_vwv8);
2993     if (Protocol >= PROTOCOL_COREPLUS) {
2994       readbraw_supported = ((SVAL(inbuf,smb_vwv5) & 0x1) != 0);
2995       writebraw_supported = ((SVAL(inbuf,smb_vwv5) & 0x2) != 0);
2996     }
2997     crypt_len = smb_buflen(inbuf);
2998     memcpy(cryptkey,smb_buf(inbuf),8);
2999     DEBUG(3,("max mux %d\n",SVAL(inbuf,smb_vwv3)));
3000     max_vcs = SVAL(inbuf,smb_vwv4); 
3001     DEBUG(3,("max vcs %d\n",max_vcs)); 
3002     DEBUG(3,("max blk %d\n",SVAL(inbuf,smb_vwv5)));
3003   } else {
3004     /* NT protocol */
3005     sec_mode = CVAL(inbuf,smb_vwv1);
3006     max_xmit = IVAL(inbuf,smb_vwv3+1);
3007     sesskey = IVAL(inbuf,smb_vwv7+1);
3008     serverzone = SVALS(inbuf,smb_vwv15+1)*60;
3009     /* this time arrives in real GMT */
3010     servertime = interpret_long_date(inbuf+smb_vwv11+1);
3011     crypt_len = CVAL(inbuf,smb_vwv16+1);
3012     memcpy(cryptkey,smb_buf(inbuf),8);
3013     if (IVAL(inbuf,smb_vwv9+1) & 1)
3014       readbraw_supported = writebraw_supported = True;      
3015     DEBUG(3,("max mux %d\n",SVAL(inbuf,smb_vwv1+1)));
3016     max_vcs = SVAL(inbuf,smb_vwv2+1); 
3017     DEBUG(3,("max vcs %d\n",max_vcs));
3018     DEBUG(3,("max raw %d\n",IVAL(inbuf,smb_vwv5+1)));
3019     DEBUG(3,("capabilities 0x%x\n",IVAL(inbuf,smb_vwv9+1)));
3020   }
3021
3022   DEBUG(3,("Sec mode %d\n",SVAL(inbuf,smb_vwv1)));
3023   DEBUG(3,("max xmt %d\n",max_xmit));
3024   DEBUG(3,("Got %d byte crypt key\n",crypt_len));
3025   DEBUG(3,("Chose protocol [%s]\n",prots[SVAL(inbuf,smb_vwv0)].name));
3026
3027   doencrypt = ((sec_mode & 2) != 0);
3028
3029   if (servertime) {
3030     static BOOL done_time = False;
3031     if (!done_time) {
3032       DEBUG(1,("Server time is %sTimezone is UTC%+02.1f\n",
3033                asctime(LocalTime(&servertime)),
3034                -(double)(serverzone/3600.0)));
3035       done_time = True;
3036     }
3037   }
3038
3039  get_pass:
3040
3041   if (got_pass)
3042     pass = password;
3043   else
3044     pass = (char *)getpass("Password: ");
3045
3046   if (Protocol >= PROTOCOL_LANMAN1 && use_setup)
3047     {
3048       fstring pword;
3049       int passlen = strlen(pass)+1;
3050       strcpy(pword,pass);      
3051
3052 #ifdef SMB_PASSWD
3053       if (doencrypt && *pass) {
3054         DEBUG(3,("Using encrypted passwords\n"));
3055         passlen = 24;
3056         SMBencrypt(pass,cryptkey,pword);
3057       }
3058 #else
3059       doencrypt = False;
3060 #endif
3061
3062       /* if in share level security then don't send a password now */
3063       if (!(sec_mode & 1)) {strcpy(pword, "");passlen=1;} 
3064
3065       /* send a session setup command */
3066       bzero(outbuf,smb_size);
3067
3068       if (Protocol < PROTOCOL_NT1) {
3069         set_message(outbuf,10,1 + strlen(username) + passlen,True);
3070         CVAL(outbuf,smb_com) = SMBsesssetupX;
3071         setup_pkt(outbuf);
3072
3073         CVAL(outbuf,smb_vwv0) = 0xFF;
3074         SSVAL(outbuf,smb_vwv2,max_xmit);
3075         SSVAL(outbuf,smb_vwv3,2);
3076         SSVAL(outbuf,smb_vwv4,max_vcs-1);
3077         SIVAL(outbuf,smb_vwv5,sesskey);
3078         SSVAL(outbuf,smb_vwv7,passlen);
3079         p = smb_buf(outbuf);
3080         memcpy(p,pword,passlen);
3081         p += passlen;
3082         strcpy(p,username);
3083       } else {
3084         if (!doencrypt) passlen--;
3085         /* for Win95 */
3086         set_message(outbuf,13,0,True);
3087         CVAL(outbuf,smb_com) = SMBsesssetupX;
3088         setup_pkt(outbuf);
3089
3090         CVAL(outbuf,smb_vwv0) = 0xFF;
3091         SSVAL(outbuf,smb_vwv2,BUFFER_SIZE);
3092         SSVAL(outbuf,smb_vwv3,2);
3093         SSVAL(outbuf,smb_vwv4,getpid());
3094         SIVAL(outbuf,smb_vwv5,sesskey);
3095         SSVAL(outbuf,smb_vwv7,passlen);
3096         SSVAL(outbuf,smb_vwv8,0);
3097         p = smb_buf(outbuf);
3098         memcpy(p,pword,passlen); p += SVAL(outbuf,smb_vwv7);
3099         strcpy(p,username);p = skip_string(p,1);
3100         strcpy(p,workgroup);p = skip_string(p,1);
3101         strcpy(p,"Unix");p = skip_string(p,1);
3102         strcpy(p,"Samba");p = skip_string(p,1);
3103         set_message(outbuf,13,PTR_DIFF(p,smb_buf(outbuf)),False);
3104       }
3105
3106       send_smb(Client,outbuf);
3107       receive_smb(Client,inbuf,CLIENT_TIMEOUT);
3108
3109       show_msg(inbuf);
3110
3111       if (CVAL(inbuf,smb_rcls) != 0)
3112         {
3113           if (! *pass &&
3114               ((CVAL(inbuf,smb_rcls) == ERRDOS && 
3115                 SVAL(inbuf,smb_err) == ERRnoaccess) ||
3116                (CVAL(inbuf,smb_rcls) == ERRSRV && 
3117                 SVAL(inbuf,smb_err) == ERRbadpw)))
3118             {
3119               got_pass = False;
3120               DEBUG(3,("resending login\n"));
3121               goto get_pass;
3122             }
3123               
3124           DEBUG(0,("Session setup failed for username=%s myname=%s destname=%s   %s\n",
3125                 username,myname,desthost,smb_errstr(inbuf)));
3126           DEBUG(0,("You might find the -U, -W or -n options useful\n"));
3127           DEBUG(0,("Sometimes you have to use `-n USERNAME' (particularly with OS/2)\n"));
3128           DEBUG(0,("Some servers also insist on uppercase-only passwords\n"));
3129           if (was_null)
3130             {
3131               free(inbuf);
3132               free(outbuf);
3133             }
3134           return(False);
3135         }
3136
3137       if (Protocol >= PROTOCOL_NT1) {
3138         char *domain,*os,*lanman;
3139         p = smb_buf(inbuf);
3140         os = p;
3141         lanman = skip_string(os,1);
3142         domain = skip_string(lanman,1);
3143         if (*domain || *os || *lanman)
3144           DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",domain,os,lanman));
3145       }
3146
3147       /* use the returned uid from now on */
3148       if (SVAL(inbuf,smb_uid) != uid)
3149         DEBUG(3,("Server gave us a UID of %d. We gave %d\n",
3150               SVAL(inbuf,smb_uid),uid));
3151       uid = SVAL(inbuf,smb_uid);
3152     }
3153
3154   /* now we've got a connection - send a tcon message */
3155   bzero(outbuf,smb_size);
3156
3157   if (strncmp(service,"\\\\",2) != 0)
3158     {
3159       DEBUG(0,("\nWarning: Your service name doesn't start with \\\\. This is probably incorrect.\n"));
3160       DEBUG(0,("Perhaps try replacing each \\ with \\\\ on the command line?\n\n"));
3161     }
3162
3163
3164  again2:
3165
3166   {
3167     int passlen = strlen(pass)+1;
3168     fstring pword;
3169     strcpy(pword,pass);
3170
3171 #ifdef SMB_PASSWD
3172     if (doencrypt && *pass) {
3173       passlen=24;
3174       SMBencrypt(pass,cryptkey,pword);      
3175     }
3176 #endif
3177
3178     /* if in user level security then don't send a password now */
3179     if ((sec_mode & 1)) {
3180       strcpy(pword, ""); passlen=1; 
3181     }
3182
3183     if (Protocol <= PROTOCOL_CORE) {
3184       set_message(outbuf,0,6 + strlen(service) + passlen + strlen(dev),True);
3185       CVAL(outbuf,smb_com) = SMBtcon;
3186       setup_pkt(outbuf);
3187
3188       p = smb_buf(outbuf);
3189       *p++ = 0x04;
3190       strcpy(p, service);
3191       p = skip_string(p,1);
3192       *p++ = 0x04;
3193       memcpy(p,pword,passlen);
3194       p += passlen;
3195       *p++ = 0x04;
3196       strcpy(p, dev);
3197     }
3198     else {
3199       set_message(outbuf,4,2 + strlen(service) + passlen + strlen(dev),True);
3200       CVAL(outbuf,smb_com) = SMBtconX;
3201       setup_pkt(outbuf);
3202   
3203       SSVAL(outbuf,smb_vwv0,0xFF);
3204       SSVAL(outbuf,smb_vwv3,passlen);
3205   
3206       p = smb_buf(outbuf);
3207       memcpy(p,pword,passlen);
3208       p += passlen;
3209       strcpy(p,service);
3210       p = skip_string(p,1);
3211       strcpy(p,dev);
3212     }
3213   }
3214
3215   send_smb(Client,outbuf);
3216   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
3217
3218   /* trying again with a blank password */
3219   if (CVAL(inbuf,smb_rcls) != 0 && 
3220       (int)strlen(pass) > 0 && 
3221       !doencrypt &&
3222       Protocol >= PROTOCOL_LANMAN1)
3223     {
3224       DEBUG(2,("first SMBtconX failed, trying again. %s\n",smb_errstr(inbuf)));
3225       strcpy(pass,"");
3226       goto again2;
3227     }  
3228
3229   if (CVAL(inbuf,smb_rcls) != 0)
3230     {
3231       DEBUG(0,("SMBtconX failed. %s\n",smb_errstr(inbuf)));
3232       DEBUG(0,("Perhaps you are using the wrong sharename, username or password?\n"));
3233       DEBUG(0,("Some servers insist that these be in uppercase\n"));
3234       if (was_null)
3235         {
3236           free(inbuf);
3237           free(outbuf);
3238         }
3239       return(False);
3240     }
3241   
3242
3243   if (Protocol <= PROTOCOL_CORE) {
3244     max_xmit = SVAL(inbuf,smb_vwv0);
3245
3246     cnum = SVAL(inbuf,smb_vwv1);
3247   }
3248   else {
3249     max_xmit = MIN(max_xmit,BUFFER_SIZE-4);
3250     if (max_xmit <= 0)
3251       max_xmit = BUFFER_SIZE - 4;
3252
3253     cnum = SVAL(inbuf,smb_tid);
3254   }
3255
3256   DEBUG(3,("Connected with cnum=%d max_xmit=%d\n",cnum,max_xmit));
3257
3258   if (was_null)
3259     {
3260       free(inbuf);
3261       free(outbuf);
3262     }
3263   return True;
3264 }
3265
3266
3267 /****************************************************************************
3268 send a logout command
3269 ****************************************************************************/
3270 static void send_logout(void )
3271 {
3272   pstring inbuf,outbuf;
3273
3274   bzero(outbuf,smb_size);
3275   set_message(outbuf,0,0,True);
3276   CVAL(outbuf,smb_com) = SMBtdis;
3277   SSVAL(outbuf,smb_tid,cnum);
3278   setup_pkt(outbuf);
3279
3280   send_smb(Client,outbuf);
3281   receive_smb(Client,inbuf,SHORT_TIMEOUT);
3282
3283   if (CVAL(inbuf,smb_rcls) != 0)
3284     {
3285       DEBUG(0,("SMBtdis failed %s\n",smb_errstr(inbuf)));
3286     }
3287
3288   
3289 #ifdef STATS
3290   stats_report();
3291 #endif
3292   exit(0);
3293 }
3294
3295
3296
3297 /****************************************************************************
3298 call a remote api
3299 ****************************************************************************/
3300 static BOOL call_api(int prcnt,int drcnt,
3301                      int mprcnt,int mdrcnt,
3302                      int *rprcnt,int *rdrcnt,
3303                      char *param,char *data,
3304                      char **rparam,char **rdata)
3305 {
3306   static char *inbuf=NULL;
3307   static char *outbuf=NULL;
3308
3309   if (!inbuf) inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
3310   if (!outbuf) outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
3311
3312   send_trans_request(outbuf,SMBtrans,"\\PIPE\\LANMAN",0,0,
3313                      data,param,NULL,
3314                      drcnt,prcnt,0,
3315                      mdrcnt,mprcnt,0);
3316
3317   return (receive_trans_response(inbuf,SMBtrans,
3318                                  rdrcnt,rprcnt,
3319                                  rdata,rparam));
3320 }
3321
3322 /****************************************************************************
3323   send a SMB trans or trans2 request
3324   ****************************************************************************/
3325 static BOOL send_trans_request(char *outbuf,int trans,
3326                                char *name,int fid,int flags,
3327                                char *data,char *param,uint16 *setup,
3328                                int ldata,int lparam,int lsetup,
3329                                int mdata,int mparam,int msetup)
3330 {
3331   int i;
3332   int this_ldata,this_lparam;
3333   int tot_data=0,tot_param=0;
3334   char *outdata,*outparam;
3335   pstring inbuf;
3336   char *p;
3337
3338   this_lparam = MIN(lparam,max_xmit - (500+lsetup*SIZEOFWORD)); /* hack */
3339   this_ldata = MIN(ldata,max_xmit - (500+lsetup*SIZEOFWORD+this_lparam));
3340
3341   bzero(outbuf,smb_size);
3342   set_message(outbuf,14+lsetup,0,True);
3343   CVAL(outbuf,smb_com) = trans;
3344   SSVAL(outbuf,smb_tid,cnum);
3345   setup_pkt(outbuf);
3346
3347   outparam = smb_buf(outbuf)+(trans==SMBtrans ? strlen(name)+1 : 3);
3348   outdata = outparam+this_lparam;
3349
3350   /* primary request */
3351   SSVAL(outbuf,smb_tpscnt,lparam);      /* tpscnt */
3352   SSVAL(outbuf,smb_tdscnt,ldata);       /* tdscnt */
3353   SSVAL(outbuf,smb_mprcnt,mparam);      /* mprcnt */
3354   SSVAL(outbuf,smb_mdrcnt,mdata);       /* mdrcnt */
3355   SCVAL(outbuf,smb_msrcnt,msetup);      /* msrcnt */
3356   SSVAL(outbuf,smb_flags,flags);        /* flags */
3357   SIVAL(outbuf,smb_timeout,0);          /* timeout */
3358   SSVAL(outbuf,smb_pscnt,this_lparam);  /* pscnt */
3359   SSVAL(outbuf,smb_psoff,smb_offset(outparam,outbuf)); /* psoff */
3360   SSVAL(outbuf,smb_dscnt,this_ldata);   /* dscnt */
3361   SSVAL(outbuf,smb_dsoff,smb_offset(outdata,outbuf)); /* dsoff */
3362   SCVAL(outbuf,smb_suwcnt,lsetup);      /* suwcnt */
3363   for (i=0;i<lsetup;i++)                /* setup[] */
3364     SSVAL(outbuf,smb_setup+i*SIZEOFWORD,setup[i]);
3365   p = smb_buf(outbuf);
3366   if (trans==SMBtrans)
3367     strcpy(p,name);                     /* name[] */
3368   else
3369     {
3370       *p++ = 0;                         /* put in a null smb_name */
3371       *p++ = 'D'; *p++ = ' ';           /* this was added because OS/2 does it */
3372     }
3373   if (this_lparam)                      /* param[] */
3374     memcpy(outparam,param,this_lparam);
3375   if (this_ldata)                       /* data[] */
3376     memcpy(outdata,data,this_ldata);
3377   set_message(outbuf,14+lsetup,         /* wcnt, bcc */
3378               PTR_DIFF(outdata+this_ldata,smb_buf(outbuf)),False);
3379
3380   show_msg(outbuf);
3381   send_smb(Client,outbuf);
3382
3383   if (this_ldata < ldata || this_lparam < lparam)
3384     {
3385       /* receive interim response */
3386       if (!receive_smb(Client,inbuf,SHORT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
3387         {
3388           DEBUG(0,("%s request failed (%s)\n",
3389                    trans==SMBtrans?"SMBtrans":"SMBtrans2", smb_errstr(inbuf)));
3390           return(False);
3391         }      
3392
3393       tot_data = this_ldata;
3394       tot_param = this_lparam;
3395
3396       while (tot_data < ldata || tot_param < lparam)
3397     {
3398           this_lparam = MIN(lparam-tot_param,max_xmit - 500); /* hack */
3399           this_ldata = MIN(ldata-tot_data,max_xmit - (500+this_lparam));
3400
3401           set_message(outbuf,trans==SMBtrans?8:9,0,True);
3402           CVAL(outbuf,smb_com) = trans==SMBtrans ? SMBtranss : SMBtranss2;
3403
3404           outparam = smb_buf(outbuf);
3405           outdata = outparam+this_lparam;
3406
3407           /* secondary request */
3408           SSVAL(outbuf,smb_tpscnt,lparam);      /* tpscnt */
3409           SSVAL(outbuf,smb_tdscnt,ldata);       /* tdscnt */
3410           SSVAL(outbuf,smb_spscnt,this_lparam); /* pscnt */
3411           SSVAL(outbuf,smb_spsoff,smb_offset(outparam,outbuf)); /* psoff */
3412           SSVAL(outbuf,smb_spsdisp,tot_param);  /* psdisp */
3413           SSVAL(outbuf,smb_sdscnt,this_ldata);  /* dscnt */
3414           SSVAL(outbuf,smb_sdsoff,smb_offset(outdata,outbuf)); /* dsoff */
3415           SSVAL(outbuf,smb_sdsdisp,tot_data);   /* dsdisp */
3416           if (trans==SMBtrans2)
3417             SSVAL(outbuf,smb_sfid,fid);         /* fid */
3418           if (this_lparam)                      /* param[] */
3419             memcpy(outparam,param,this_lparam);
3420           if (this_ldata)                       /* data[] */
3421             memcpy(outdata,data,this_ldata);
3422           set_message(outbuf,trans==SMBtrans?8:9, /* wcnt, bcc */
3423                       PTR_DIFF(outdata+this_ldata,smb_buf(outbuf)),False);
3424
3425           show_msg(outbuf);
3426           send_smb(Client,outbuf);
3427
3428           tot_data += this_ldata;
3429           tot_param += this_lparam;
3430         }
3431     }
3432
3433     return(True);
3434 }
3435
3436 /****************************************************************************
3437 try and browse available connections on a host
3438 ****************************************************************************/
3439 static BOOL browse_host(BOOL sort)
3440 {
3441 #ifdef NOSTRCASECMP
3442 #define strcasecmp StrCaseCmp
3443 #endif
3444   extern int strcasecmp();
3445
3446   char *rparam = NULL;
3447   char *rdata = NULL;
3448   char *p;
3449   int rdrcnt,rprcnt;
3450   pstring param;
3451   int count = -1;
3452
3453   /* now send a SMBtrans command with api RNetShareEnum */
3454   p = param;
3455   SSVAL(p,0,0); /* api number */
3456   p += 2;
3457   strcpy(p,"WrLeh");
3458   p = skip_string(p,1);
3459   strcpy(p,"B13BWz");
3460   p = skip_string(p,1);
3461   SSVAL(p,0,1);
3462   SSVAL(p,2,BUFFER_SIZE);
3463   p += 4;
3464
3465   if (call_api(PTR_DIFF(p,param),0,
3466                1024,BUFFER_SIZE,
3467                &rprcnt,&rdrcnt,
3468                param,NULL,
3469                &rparam,&rdata))
3470     {
3471       int res = SVAL(rparam,0);
3472       int converter=SVAL(rparam,2);
3473       int i;
3474       BOOL long_share_name=False;
3475       
3476       if (res == 0)
3477         {
3478           count=SVAL(rparam,4);
3479           p = rdata;
3480
3481           if (count > 0)
3482             {
3483               printf("\n\tSharename      Type      Comment\n");
3484               printf("\t---------      ----      -------\n");
3485             }
3486
3487           if (sort)
3488             qsort(p,count,20,QSORT_CAST strcasecmp);
3489
3490           for (i=0;i<count;i++)
3491             {
3492               char *sname = p;
3493               int type = SVAL(p,14);
3494               int comment_offset = IVAL(p,16) & 0xFFFF;
3495               fstring typestr;
3496               *typestr=0;
3497
3498               switch (type)
3499                 {
3500                 case STYPE_DISKTREE:
3501                   strcpy(typestr,"Disk"); break;
3502                 case STYPE_PRINTQ:
3503                   strcpy(typestr,"Printer"); break;           
3504                 case STYPE_DEVICE:
3505                   strcpy(typestr,"Device"); break;
3506                 case STYPE_IPC:
3507                   strcpy(typestr,"IPC"); break;      
3508                 }
3509
3510               printf("\t%-15.15s%-10.10s%s\n",
3511                      sname,
3512                      typestr,
3513                      comment_offset?rdata+comment_offset-converter:"");
3514           
3515               if (strlen(sname)>8) long_share_name=True;
3516           
3517               p += 20;
3518             }
3519
3520           if (long_share_name) {
3521             printf("\nNOTE: There were share names longer than 8 chars.\nOn older clients these may not be accessible or may give browsing errors\n");
3522           }
3523         }
3524     }
3525   
3526   if (rparam) free(rparam);
3527   if (rdata) free(rdata);
3528
3529   return(count>0);
3530 }
3531
3532
3533 /****************************************************************************
3534 get some server info
3535 ****************************************************************************/
3536 static void server_info()
3537 {
3538   char *rparam = NULL;
3539   char *rdata = NULL;
3540   char *p;
3541   int rdrcnt,rprcnt;
3542   pstring param;
3543
3544   bzero(param,sizeof(param));
3545
3546   p = param;
3547   SSVAL(p,0,63); /* api number */
3548   p += 2;
3549   strcpy(p,"WrLh");
3550   p = skip_string(p,1);
3551   strcpy(p,"zzzBBzz");
3552   p = skip_string(p,1);
3553   SSVAL(p,0,10); /* level 10 */
3554   SSVAL(p,2,1000);
3555   p += 6;
3556
3557   if (call_api(PTR_DIFF(p,param),0,
3558                6,1000,
3559                &rprcnt,&rdrcnt,
3560                param,NULL,
3561                &rparam,&rdata))
3562     {
3563       int res = SVAL(rparam,0);
3564       int converter=SVAL(rparam,2);
3565
3566       if (res == 0)
3567         {
3568       p = rdata;
3569
3570       printf("\nServer=[%s] User=[%s] Workgroup=[%s] Domain=[%s]\n",
3571              rdata+SVAL(p,0)-converter,
3572              rdata+SVAL(p,4)-converter,
3573              rdata+SVAL(p,8)-converter,
3574              rdata+SVAL(p,14)-converter);
3575     }
3576     }
3577
3578   if (rparam) free(rparam);
3579   if (rdata) free(rdata);
3580
3581   return;
3582 }
3583
3584
3585 /****************************************************************************
3586 try and browse available connections on a host
3587 ****************************************************************************/
3588 static BOOL list_servers(char *wk_grp)
3589 {
3590   char *rparam = NULL;
3591   char *rdata = NULL;
3592   int rdrcnt,rprcnt;
3593   char *p,*svtype_p;
3594   pstring param;
3595   int uLevel = 1;
3596   int count = 0;
3597   BOOL ok = False;
3598   BOOL generic_request = False;
3599
3600
3601   if (strequal(wk_grp,"WORKGROUP")) {
3602     /* we won't specify a workgroup */
3603     generic_request = True;
3604   } 
3605
3606   /* now send a SMBtrans command with api ServerEnum? */
3607   p = param;
3608   SSVAL(p,0,0x68); /* api number */
3609   p += 2;
3610
3611   strcpy(p,generic_request?"WrLehDO":"WrLehDz");
3612   p = skip_string(p,1);
3613
3614   strcpy(p,"B16BBDz");
3615
3616   p = skip_string(p,1);
3617   SSVAL(p,0,uLevel);
3618   SSVAL(p,2,0x2000); /* buf length */
3619   p += 4;
3620
3621   svtype_p = p;
3622   p += 4;
3623
3624   if (!generic_request) {
3625     strcpy(p, wk_grp);
3626     p = skip_string(p,1);
3627   }
3628
3629   /* first ask for a list of servers in this workgroup */
3630   SIVAL(svtype_p,0,SV_TYPE_ALL);
3631
3632   if (call_api(PTR_DIFF(p+4,param),0,
3633                8,10000,
3634                &rprcnt,&rdrcnt,
3635                param,NULL,
3636                &rparam,&rdata))
3637     {
3638       int res = SVAL(rparam,0);
3639       int converter=SVAL(rparam,2);
3640       int i;
3641
3642       if (res == 0) {   
3643         char *p2 = rdata;
3644         count=SVAL(rparam,4);
3645
3646         if (count > 0) {
3647           printf("\n\nThis machine has a browse list:\n");
3648           printf("\n\tServer               Comment\n");
3649           printf("\t---------            -------\n");
3650         }
3651         
3652         for (i=0;i<count;i++) {
3653           char *sname = p2;
3654           int comment_offset = IVAL(p2,22) & 0xFFFF;
3655           printf("\t%-16.16s     %s\n",
3656                  sname,
3657                  comment_offset?rdata+comment_offset-converter:"");
3658
3659           ok=True;
3660           p2 += 26;
3661         }
3662       }
3663     }
3664
3665   if (rparam) {free(rparam); rparam = NULL;}
3666   if (rdata) {free(rdata); rdata = NULL;}
3667
3668   /* now ask for a list of workgroups */
3669   SIVAL(svtype_p,0,SV_TYPE_DOMAIN_ENUM);
3670
3671   if (call_api(PTR_DIFF(p+4,param),0,
3672                8,10000,
3673                &rprcnt,&rdrcnt,
3674                param,NULL,
3675                &rparam,&rdata))
3676     {
3677       int res = SVAL(rparam,0);
3678       int converter=SVAL(rparam,2);
3679       int i;
3680
3681       if (res == 0) {
3682         char *p2 = rdata;
3683         count=SVAL(rparam,4);
3684
3685         if (count > 0) {
3686           printf("\n\nThis machine has a workgroup list:\n");
3687           printf("\n\tWorkgroup            Master\n");
3688           printf("\t---------            -------\n");
3689         }
3690         
3691         for (i=0;i<count;i++) {
3692           char *sname = p2;
3693           int comment_offset = IVAL(p2,22) & 0xFFFF;
3694           printf("\t%-16.16s     %s\n",
3695                  sname,
3696                  comment_offset?rdata+comment_offset-converter:"");
3697           
3698           ok=True;
3699           p2 += 26;
3700         }
3701       }
3702     }
3703
3704   if (rparam) free(rparam);
3705   if (rdata) free(rdata);
3706
3707   return(ok);
3708 }
3709
3710
3711 /* This defines the commands supported by this client */
3712 struct
3713 {
3714   char *name;
3715   void (*fn)();
3716   char *description;
3717 } commands[] = 
3718 {
3719   {"ls",cmd_dir,"<mask> list the contents of the current directory"},
3720   {"dir",cmd_dir,"<mask> list the contents of the current directory"},
3721   {"lcd",cmd_lcd,"[directory] change/report the local current working directory"},
3722   {"cd",cmd_cd,"[directory] change/report the remote directory"},
3723   {"pwd",cmd_pwd,"show current remote directory (same as 'cd' with no args)"},
3724   {"get",cmd_get,"<remote name> [local name] get a file"},
3725   {"mget",cmd_mget,"<mask> get all the matching files"},
3726   {"put",cmd_put,"<local name> [remote name] put a file"},
3727   {"mput",cmd_mput,"<mask> put all matching files"},
3728   {"rename",cmd_rename,"<src> <dest> rename some files"},
3729   {"more",cmd_more,"<remote name> view a remote file with your pager"},  
3730   {"mask",cmd_select,"<mask> mask all filenames against this"},
3731   {"del",cmd_del,"<mask> delete all matching files"},
3732   {"rm",cmd_del,"<mask> delete all matching files"},
3733   {"mkdir",cmd_mkdir,"<directory> make a directory"},
3734   {"md",cmd_mkdir,"<directory> make a directory"},
3735   {"rmdir",cmd_rmdir,"<directory> remove a directory"},
3736   {"rd",cmd_rmdir,"<directory> remove a directory"},
3737   {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput"},  
3738   {"recurse",cmd_recurse,"toggle directory recursion for mget and mput"},  
3739   {"translate",cmd_translate,"toggle text translation for printing"},  
3740   {"lowercase",cmd_lowercase,"toggle lowercasing of filenames for get"},  
3741   {"print",cmd_print,"<file name> print a file"},
3742   {"printmode",cmd_printmode,"<graphics or text> set the print mode"},
3743   {"queue",cmd_queue,"show the print queue"},
3744   {"cancel",cmd_cancel,"<jobid> cancel a print queue entry"},
3745   {"stat",cmd_stat,"<file> get info on a file (experimental!)"},
3746   {"quit",send_logout,"logoff the server"},
3747   {"q",send_logout,"logoff the server"},
3748   {"exit",send_logout,"logoff the server"},
3749   {"newer",cmd_newer,"<file> only mget files newer than the specified local file"},
3750   {"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"},
3751   {"tar",cmd_tar,"tar <c|x>[IXbgNa] current directory to/from <file name>" },
3752   {"blocksize",cmd_block,"blocksize <number> (default 20)" },
3753   {"tarmode",cmd_tarmode,
3754      "<full|inc|reset|noreset> tar's behaviour towards archive bits" },
3755   {"setmode",cmd_setmode,"filename <setmode string> change modes of file"},
3756   {"help",cmd_help,"[command] give help on a command"},
3757   {"?",cmd_help,"[command] give help on a command"},
3758   {"!",NULL,"run a shell command on the local system"},
3759   {"",NULL,NULL}
3760 };
3761
3762
3763 /*******************************************************************
3764   lookup a command string in the list of commands, including 
3765   abbreviations
3766   ******************************************************************/
3767 static int process_tok(fstring tok)
3768 {
3769   int i = 0, matches = 0;
3770   int cmd=0;
3771   int tok_len = strlen(tok);
3772   
3773   while (commands[i].fn != NULL)
3774     {
3775       if (strequal(commands[i].name,tok))
3776         {
3777           matches = 1;
3778           cmd = i;
3779           break;
3780         }
3781       else if (strnequal(commands[i].name, tok, tok_len+1))
3782         {
3783           matches++;
3784           cmd = i;
3785         }
3786       i++;
3787     }
3788   
3789   if (matches == 0)
3790     return(-1);
3791   else if (matches == 1)
3792     return(cmd);
3793   else
3794     return(-2);
3795 }
3796
3797 /****************************************************************************
3798 help
3799 ****************************************************************************/
3800 void cmd_help(void)
3801 {
3802   int i=0,j;
3803   fstring buf;
3804
3805   if (next_token(NULL,buf,NULL))
3806     {
3807       if ((i = process_tok(buf)) >= 0)
3808         DEBUG(0,("HELP %s:\n\t%s\n\n",commands[i].name,commands[i].description));                   
3809     }
3810   else
3811     while (commands[i].description)
3812       {
3813         for (j=0; commands[i].description && (j<5); j++) {
3814           DEBUG(0,("%-15s",commands[i].name));
3815           i++;
3816         }
3817         DEBUG(0,("\n"));
3818       }
3819 }
3820
3821 /****************************************************************************
3822 open the client sockets
3823 ****************************************************************************/
3824 static BOOL open_sockets(int port )
3825 {
3826   static int last_port;
3827   char *host;
3828   pstring service2;
3829   extern int Client;
3830 #ifdef USENMB
3831   BOOL failed = True;
3832 #endif
3833
3834   if (port == 0) port=last_port;
3835   last_port=port;
3836
3837   strupper(service);
3838
3839   if (*desthost)
3840     {
3841       host = desthost;
3842     }
3843   else
3844     {
3845       strcpy(service2,service);
3846       host = strtok(service2,"\\/");
3847       if (!host) {
3848         DEBUG(0,("Badly formed host name\n"));
3849         return(False);
3850       }
3851       strcpy(desthost,host);
3852     }
3853
3854   if (*myname == 0)
3855     {
3856       get_myname(myname,NULL);
3857       strupper(myname);
3858     }
3859
3860   DEBUG(3,("Opening sockets\n"));
3861
3862   if (!have_ip)
3863     {
3864       struct hostent *hp;
3865
3866       if ((hp = Get_Hostbyname(host))) {
3867         putip((char *)&dest_ip,(char *)hp->h_addr);
3868         failed = False;
3869       } else {
3870 #ifdef USENMB
3871         /* Try and resolve the name with the netbios server */
3872         int             bcast;
3873
3874         if ((bcast = open_socket_in(SOCK_DGRAM, 0, 3)) != -1) {
3875           set_socket_options(bcast, "SO_BROADCAST");
3876
3877           if (name_query(bcast, host, 0x20, True, True, *iface_bcast(dest_ip),
3878                          &dest_ip,0)) {
3879             failed = False;
3880           }
3881           close (bcast);
3882         }
3883 #endif
3884         if (failed) {
3885           DEBUG(0,("Get_Hostbyname: Unknown host %s.\n",host));
3886           return False;
3887         }
3888       }
3889     }
3890
3891   Client = open_socket_out(SOCK_STREAM, &dest_ip, port);
3892   if (Client == -1)
3893     return False;
3894
3895   DEBUG(3,("Connected\n"));
3896   
3897   set_socket_options(Client,user_socket_options);  
3898   
3899   return True;
3900 }
3901
3902 /****************************************************************************
3903 wait for keyboard activity, swallowing network packets
3904 ****************************************************************************/
3905 #ifdef CLIX
3906 static char wait_keyboard(char *buffer)
3907 #else
3908 static void wait_keyboard(char *buffer)
3909 #endif
3910 {
3911   fd_set fds;
3912   int selrtn;
3913   struct timeval timeout;
3914   
3915 #ifdef CLIX
3916   int delay = 0;
3917 #endif
3918   
3919   while (1) 
3920     {
3921       extern int Client;
3922       FD_ZERO(&fds);
3923       FD_SET(Client,&fds);
3924 #ifndef CLIX
3925       FD_SET(fileno(stdin),&fds);
3926 #endif
3927
3928       timeout.tv_sec = 20;
3929       timeout.tv_usec = 0;
3930 #ifdef CLIX
3931       timeout.tv_sec = 0;
3932 #endif
3933       selrtn = sys_select(&fds,&timeout);
3934       
3935 #ifndef CLIX
3936       if (FD_ISSET(fileno(stdin),&fds))
3937         return;
3938 #else
3939       {
3940         char ch;
3941         int f_flags;
3942         int readret;
3943         
3944         f_flags = fcntl(fileno(stdin), F_GETFL, 0);
3945         fcntl( fileno(stdin), F_SETFL, f_flags | O_NONBLOCK);
3946         readret = read_data( fileno(stdin), &ch, 1);
3947         fcntl(fileno(stdin), F_SETFL, f_flags);
3948         if (readret == -1)
3949           {
3950             if (errno != EAGAIN)
3951               {
3952                 /* should crash here */
3953                 DEBUG(1,("readchar stdin failed\n"));
3954               }
3955           }
3956         else if (readret != 0)
3957           {
3958             return ch;
3959           }
3960       }
3961 #endif
3962       if (FD_ISSET(Client,&fds))
3963         receive_smb(Client,buffer,0);
3964       
3965 #ifdef CLIX
3966       delay++;
3967       if (delay > 100000)
3968         {
3969           delay = 0;
3970           chkpath("\\",False);
3971         }
3972 #else
3973       chkpath("\\",False);
3974 #endif
3975     }  
3976 }
3977
3978
3979 /****************************************************************************
3980 close and open the connection again
3981 ****************************************************************************/
3982 BOOL reopen_connection(char *inbuf,char *outbuf)
3983 {
3984   static int open_count=0;
3985
3986   open_count++;
3987
3988   if (open_count>5) return(False);
3989
3990   DEBUG(1,("Trying to re-open connection\n"));
3991
3992   set_message(outbuf,0,0,True);
3993   SCVAL(outbuf,smb_com,SMBtdis);
3994   SSVAL(outbuf,smb_tid,cnum);
3995   setup_pkt(outbuf);
3996
3997   send_smb(Client,outbuf);
3998   receive_smb(Client,inbuf,SHORT_TIMEOUT);
3999
4000   close_sockets();
4001   if (!open_sockets(0)) return(False);
4002
4003   return(send_login(inbuf,outbuf,True,True));
4004 }
4005
4006 /****************************************************************************
4007   process commands from the client
4008 ****************************************************************************/
4009 static BOOL process(char *base_directory)
4010 {
4011   extern FILE *dbf;
4012   pstring line;
4013   char *cmd;
4014
4015   char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
4016   char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
4017
4018   if ((InBuffer == NULL) || (OutBuffer == NULL)) 
4019     return(False);
4020   
4021   bzero(OutBuffer,smb_size);
4022
4023   if (!send_login(InBuffer,OutBuffer,True,True))
4024     return(False);
4025
4026   if (*base_directory) do_cd(base_directory);
4027
4028   cmd = cmdstr;
4029   if (cmd[0] != '\0') while (cmd[0] != '\0')
4030     {
4031       char *p;
4032       fstring tok;
4033       int i;
4034
4035       if ((p = strchr(cmd, ';')) == 0)
4036         {
4037           strncpy(line, cmd, 999);
4038           line[1000] = '\0';
4039           cmd += strlen(cmd);
4040         }
4041       else
4042         {
4043           if (p - cmd > 999) p = cmd + 999;
4044           strncpy(line, cmd, p - cmd);
4045           line[p - cmd] = '\0';
4046           cmd = p + 1;
4047         }
4048
4049       /* input language code to internal one */
4050       CNV_INPUT (line);
4051       
4052       /* and get the first part of the command */
4053       {
4054         char *ptr = line;
4055         if (!next_token(&ptr,tok,NULL)) continue;
4056       }
4057
4058       if ((i = process_tok(tok)) >= 0)
4059         commands[i].fn(InBuffer,OutBuffer);
4060       else if (i == -2)
4061         DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok)));
4062       else
4063         DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
4064     }
4065   else while (!feof(stdin))
4066     {
4067       fstring tok;
4068       int i;
4069
4070       bzero(OutBuffer,smb_size);
4071
4072       /* display a prompt */
4073       DEBUG(1,("smb: %s> ", CNV_LANG(cur_dir)));
4074       fflush(dbf);
4075
4076 #ifdef CLIX
4077       line[0] = wait_keyboard(InBuffer);
4078       /* this might not be such a good idea... */
4079       if ( line[0] == EOF)
4080         break;
4081 #else
4082       wait_keyboard(InBuffer);
4083 #endif
4084   
4085       /* and get a response */
4086 #ifdef CLIX
4087       fgets( &line[1],999, stdin);
4088 #else
4089       if (!fgets(line,1000,stdin))
4090         break;
4091 #endif
4092
4093       /* input language code to internal one */
4094       CNV_INPUT (line);
4095
4096       /* special case - first char is ! */
4097       if (*line == '!')
4098         {
4099           system(line + 1);
4100           continue;
4101         }
4102       
4103       /* and get the first part of the command */
4104       {
4105         char *ptr = line;
4106         if (!next_token(&ptr,tok,NULL)) continue;
4107       }
4108
4109       if ((i = process_tok(tok)) >= 0)
4110         commands[i].fn(InBuffer,OutBuffer);
4111       else if (i == -2)
4112         DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok)));
4113       else
4114         DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
4115     }
4116   
4117   send_logout();
4118   return(True);
4119 }
4120
4121
4122 /****************************************************************************
4123 usage on the program
4124 ****************************************************************************/
4125 static void usage(char *pname)
4126 {
4127   DEBUG(0,("Usage: %s service <password> [-p port] [-d debuglevel] [-l log] ",
4128            pname));
4129
4130 #ifdef KANJI
4131   DEBUG(0,("[-t termcode] "));
4132 #endif /* KANJI */
4133
4134   DEBUG(0,("\nVersion %s\n",VERSION));
4135   DEBUG(0,("\t-p port               listen on the specified port\n"));
4136   DEBUG(0,("\t-d debuglevel         set the debuglevel\n"));
4137   DEBUG(0,("\t-l log basename.      Basename for log/debug files\n"));
4138   DEBUG(0,("\t-n netbios name.      Use this name as my netbios name\n"));
4139   DEBUG(0,("\t-N                    don't ask for a password\n"));
4140   DEBUG(0,("\t-P                    connect to service as a printer\n"));
4141   DEBUG(0,("\t-M host               send a winpopup message to the host\n"));
4142   DEBUG(0,("\t-m max protocol       set the max protocol level\n"));
4143   DEBUG(0,("\t-L host               get a list of shares available on a host\n"));
4144   DEBUG(0,("\t-I dest IP            use this IP to connect to\n"));
4145   DEBUG(0,("\t-E                    write messages to stderr instead of stdout\n"));
4146   DEBUG(0,("\t-U username           set the network username\n"));
4147   DEBUG(0,("\t-W workgroup          set the workgroup name\n"));
4148   DEBUG(0,("\t-c command string     execute semicolon separated commands\n"));
4149 #ifdef KANJI
4150   DEBUG(0,("\t-t terminal code      terminal i/o code {sjis|euc|jis7|jis8|junet|hex}\n"));
4151 #endif /* KANJI */
4152   DEBUG(0,("\t-T<c|x>IXgbNa          command line tar\n"));
4153   DEBUG(0,("\t-D directory          start from directory\n"));
4154   DEBUG(0,("\n"));
4155 }
4156
4157
4158
4159 /****************************************************************************
4160   main program
4161 ****************************************************************************/
4162  int main(int argc,char *argv[])
4163 {
4164   fstring base_directory;
4165   char *pname = argv[0];
4166   int port = SMB_PORT;
4167   int opt;
4168   extern FILE *dbf;
4169   extern char *optarg;
4170   extern int optind;
4171   pstring query_host;
4172   BOOL message = False;
4173   extern char tar_type;
4174
4175   *query_host = 0;
4176   *base_directory = 0;
4177
4178   DEBUGLEVEL = 2;
4179
4180   setup_logging(pname,True);
4181
4182   TimeInit();
4183   charset_initialise();
4184
4185   pid = getpid();
4186   uid = getuid();
4187   gid = getgid();
4188   mid = pid + 100;
4189   myumask = umask(0);
4190   umask(myumask);
4191
4192   if (getenv("USER"))
4193     {
4194       strcpy(username,getenv("USER"));
4195       strupper(username);
4196     }
4197
4198   if (*username == 0 && getenv("LOGNAME"))
4199     {
4200       strcpy(username,getenv("LOGNAME"));
4201       strupper(username);
4202     }
4203
4204   if (argc < 2)
4205     {
4206       usage(pname);
4207       exit(1);
4208     }
4209   
4210   if (*argv[1] != '-')
4211     {
4212
4213       strcpy(service,argv[1]);  
4214       argc--;
4215       argv++;
4216
4217       if (count_chars(service,'\\') < 3)
4218         {
4219           usage(pname);
4220           printf("\n%s: Not enough '\\' characters in service\n",service);
4221           exit(1);
4222         }
4223
4224 /*
4225       if (count_chars(service,'\\') > 3)
4226         {
4227           usage(pname);
4228           printf("\n%s: Too many '\\' characters in service\n",service);
4229           exit(1);
4230         }
4231         */
4232
4233       if (argc > 1 && (*argv[1] != '-'))
4234         {
4235           got_pass = True;
4236           strcpy(password,argv[1]);  
4237           memset(argv[1],'X',strlen(argv[1]));
4238           argc--;
4239           argv++;
4240         }
4241     }
4242
4243 #ifdef KANJI
4244   setup_term_code (KANJI);
4245 #endif
4246   while ((opt = 
4247           getopt(argc, argv,"B:O:M:i:Nn:d:Pp:l:hI:EB:U:L:t:m:W:T:D:c:")) != EOF)
4248     switch (opt)
4249       {
4250       case 'm':
4251         max_protocol = interpret_protocol(optarg,max_protocol);
4252         break;
4253       case 'O':
4254         strcpy(user_socket_options,optarg);
4255         break;  
4256       case 'M':
4257         name_type = 3;
4258         strcpy(desthost,optarg);
4259         strupper(desthost);
4260         message = True;
4261         break;
4262       case 'B':
4263         iface_set_default(NULL,optarg,NULL);
4264         break;
4265       case 'D':
4266         strcpy(base_directory,optarg);
4267         break;
4268       case 'T':
4269         if (!tar_parseargs(argc, argv, optarg, optind)) {
4270           usage(pname);
4271           exit(1);
4272         }
4273         break;
4274       case 'i':
4275         strcpy(scope,optarg);
4276         break;
4277       case 'L':
4278         got_pass = True;
4279         strcpy(query_host,optarg);
4280         break;
4281       case 'U':
4282         {
4283           char *p;
4284         strcpy(username,optarg);
4285         if ((p=strchr(username,'%')))
4286           {
4287             *p = 0;
4288             strcpy(password,p+1);
4289             got_pass = True;
4290             memset(strchr(optarg,'%')+1,'X',strlen(password));
4291           }
4292         }
4293             
4294         break;
4295       case 'W':
4296         strcpy(workgroup,optarg);
4297         break;
4298       case 'E':
4299         dbf = stderr;
4300         break;
4301       case 'I':
4302         {
4303           dest_ip = *interpret_addr2(optarg);
4304           if (zero_ip(dest_ip)) exit(1);
4305           have_ip = True;
4306         }
4307         break;
4308       case 'n':
4309         strcpy(myname,optarg);
4310         break;
4311       case 'N':
4312         got_pass = True;
4313         break;
4314       case 'P':
4315         connect_as_printer = True;
4316         break;
4317       case 'd':
4318         if (*optarg == 'A')
4319           DEBUGLEVEL = 10000;
4320         else
4321           DEBUGLEVEL = atoi(optarg);
4322         break;
4323       case 'l':
4324         sprintf(debugf,"%s.client",optarg);
4325         break;
4326       case 'p':
4327         port = atoi(optarg);
4328         break;
4329       case 'c':
4330         cmdstr = optarg;
4331         got_pass = True;
4332         break;
4333       case 'h':
4334         usage(pname);
4335         exit(0);
4336         break;
4337       case 't':
4338 #ifdef KANJI
4339         if (!setup_term_code (optarg)) {
4340             DEBUG(0, ("%s: unknown terminal code name\n", optarg));
4341             usage (pname);
4342             exit (1);
4343         }
4344 #endif
4345         break;
4346       default:
4347         usage(pname);
4348         exit(1);
4349       }
4350
4351   if (!tar_type && !*query_host && !*service && !message)
4352     {
4353       usage(pname);
4354       exit(1);
4355     }
4356
4357
4358   DEBUG(3,("%s client started (version %s)\n",timestring(),VERSION));
4359
4360   load_interfaces();
4361   get_myname(*myname?NULL:myname,NULL);  
4362   strupper(myname);
4363
4364   if (tar_type) {
4365     recurse=True;
4366
4367     if (open_sockets(port)) {
4368         char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
4369         char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
4370         int ret;
4371
4372         if ((InBuffer == NULL) || (OutBuffer == NULL)) 
4373           return(1);
4374
4375         bzero(OutBuffer,smb_size);
4376         if (!send_login(InBuffer,OutBuffer,True,True))
4377           return(False);
4378
4379         if (*base_directory) do_cd(base_directory);
4380
4381         ret=process_tar(InBuffer, OutBuffer);
4382
4383         send_logout();
4384         close_sockets();
4385         return(ret);
4386     } else
4387       return(1);
4388   }
4389   
4390   if (*query_host)
4391     {
4392       int ret = 0;
4393       sprintf(service,"\\\\%s\\IPC$",query_host);
4394       strupper(service);
4395       connect_as_ipc = True;
4396       if (open_sockets(port))
4397         {
4398 #if 0
4399           *username = 0;
4400 #endif
4401           if (!send_login(NULL,NULL,True,True))
4402             return(1);
4403
4404           server_info();
4405           if (!browse_host(True)) {
4406             sleep(1);
4407             browse_host(True);
4408           }
4409           if (!list_servers(workgroup)) {
4410             sleep(1);
4411             list_servers(workgroup);
4412           }
4413
4414           send_logout();
4415           close_sockets();
4416         }
4417
4418       return(ret);
4419     }
4420
4421   if (message)
4422     {
4423       int ret = 0;
4424       if (open_sockets(port))
4425         {
4426           pstring inbuf,outbuf;
4427           bzero(outbuf,smb_size);
4428           if (!send_session_request(inbuf,outbuf))
4429             return(1);
4430
4431           send_message(inbuf,outbuf);
4432
4433           close_sockets();
4434         }
4435
4436       return(ret);
4437     }
4438
4439   if (open_sockets(port))
4440     {
4441       if (!process(base_directory))
4442         {
4443           close_sockets();
4444           return(1);
4445         }
4446       close_sockets();
4447     }
4448   else
4449     return(1);
4450
4451   return(0);
4452 }
4453
4454
4455 /* error code stuff - put together by Merik Karman
4456    merik@blackadder.dsh.oz.au */
4457
4458 typedef struct
4459 {
4460   char *name;
4461   int code;
4462   char *message;
4463 } err_code_struct;
4464
4465 /* Dos Error Messages */
4466 err_code_struct dos_msgs[] = {
4467   {"ERRbadfunc",1,"Invalid function."},
4468   {"ERRbadfile",2,"File not found."},
4469   {"ERRbadpath",3,"Directory invalid."},
4470   {"ERRnofids",4,"No file descriptors available"},
4471   {"ERRnoaccess",5,"Access denied."},
4472   {"ERRbadfid",6,"Invalid file handle."},
4473   {"ERRbadmcb",7,"Memory control blocks destroyed."},
4474   {"ERRnomem",8,"Insufficient server memory to perform the requested function."},
4475   {"ERRbadmem",9,"Invalid memory block address."},
4476   {"ERRbadenv",10,"Invalid environment."},
4477   {"ERRbadformat",11,"Invalid format."},
4478   {"ERRbadaccess",12,"Invalid open mode."},
4479   {"ERRbaddata",13,"Invalid data."},
4480   {"ERR",14,"reserved."},
4481   {"ERRbaddrive",15,"Invalid drive specified."},
4482   {"ERRremcd",16,"A Delete Directory request attempted  to  remove  the  server's  current directory."},
4483   {"ERRdiffdevice",17,"Not same device."},
4484   {"ERRnofiles",18,"A File Search command can find no more files matching the specified criteria."},
4485   {"ERRbadshare",32,"The sharing mode specified for an Open conflicts with existing  FIDs  on the file."},
4486   {"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."},
4487   {"ERRfilexists",80,"The file named in a Create Directory, Make  New  File  or  Link  request already exists."},
4488   {"ERRbadpipe",230,"Pipe invalid."},
4489   {"ERRpipebusy",231,"All instances of the requested pipe are busy."},
4490   {"ERRpipeclosing",232,"Pipe close in progress."},
4491   {"ERRnotconnected",233,"No process on other end of pipe."},
4492   {"ERRmoredata",234,"There is more data to be returned."},
4493   {"ERRinvgroup",2455,"Invalid workgroup (try the -W option)"},
4494   {NULL,-1,NULL}};
4495
4496 /* Server Error Messages */
4497 err_code_struct server_msgs[] = {
4498   {"ERRerror",1,"Non-specific error code."},
4499   {"ERRbadpw",2,"Bad password - name/password pair in a Tree Connect or Session Setup are invalid."},
4500   {"ERRbadtype",3,"reserved."},
4501   {"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."},
4502   {"ERRinvnid",5,"The tree ID (TID) specified in a command was invalid."},
4503   {"ERRinvnetname",6,"Invalid network name in tree connect."},
4504   {"ERRinvdevice",7,"Invalid device - printer request made to non-printer connection or  non-printer request made to printer connection."},
4505   {"ERRqfull",49,"Print queue full (files) -- returned by open print file."},
4506   {"ERRqtoobig",50,"Print queue full -- no space."},
4507   {"ERRqeof",51,"EOF on print queue dump."},
4508   {"ERRinvpfid",52,"Invalid print file FID."},
4509   {"ERRsmbcmd",64,"The server did not recognize the command received."},
4510   {"ERRsrverror",65,"The server encountered an internal error, e.g., system file unavailable."},
4511   {"ERRfilespecs",67,"The file handle (FID) and pathname parameters contained an invalid  combination of values."},
4512   {"ERRreserved",68,"reserved."},
4513   {"ERRbadpermits",69,"The access permissions specified for a file or directory are not a valid combination.  The server cannot set the requested attribute."},
4514   {"ERRreserved",70,"reserved."},
4515   {"ERRsetattrmode",71,"The attribute mode in the Set File Attribute request is invalid."},
4516   {"ERRpaused",81,"Server is paused."},
4517   {"ERRmsgoff",82,"Not receiving messages."},
4518   {"ERRnoroom",83,"No room to buffer message."},
4519   {"ERRrmuns",87,"Too many remote user names."},
4520   {"ERRtimeout",88,"Operation timed out."},
4521   {"ERRnoresource",89,"No resources currently available for request."},
4522   {"ERRtoomanyuids",90,"Too many UIDs active on this session."},
4523   {"ERRbaduid",91,"The UID is not known as a valid ID on this session."},
4524   {"ERRusempx",250,"Temp unable to support Raw, use MPX mode."},
4525   {"ERRusestd",251,"Temp unable to support Raw, use standard read/write."},
4526   {"ERRcontmpx",252,"Continue in MPX mode."},
4527   {"ERRreserved",253,"reserved."},
4528   {"ERRreserved",254,"reserved."},
4529   {"ERRnosupport",0xFFFF,"Function not supported."},
4530   {NULL,-1,NULL}};
4531
4532 /* Hard Error Messages */
4533 err_code_struct hard_msgs[] = {
4534   {"ERRnowrite",19,"Attempt to write on write-protected diskette."},
4535   {"ERRbadunit",20,"Unknown unit."},
4536   {"ERRnotready",21,"Drive not ready."},
4537   {"ERRbadcmd",22,"Unknown command."},
4538   {"ERRdata",23,"Data error (CRC)."},
4539   {"ERRbadreq",24,"Bad request structure length."},
4540   {"ERRseek",25 ,"Seek error."},
4541   {"ERRbadmedia",26,"Unknown media type."},
4542   {"ERRbadsector",27,"Sector not found."},
4543   {"ERRnopaper",28,"Printer out of paper."},
4544   {"ERRwrite",29,"Write fault."},
4545   {"ERRread",30,"Read fault."},
4546   {"ERRgeneral",31,"General failure."},
4547   {"ERRbadshare",32,"A open conflicts with an existing open."},
4548   {"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."},
4549   {"ERRwrongdisk",34,"The wrong disk was found in a drive."},
4550   {"ERRFCBUnavail",35,"No FCBs are available to process request."},
4551   {"ERRsharebufexc",36,"A sharing buffer has been exceeded."},
4552   {NULL,-1,NULL}};
4553
4554
4555 struct
4556 {
4557   int code;
4558   char *class;
4559   err_code_struct *err_msgs;
4560 } err_classes[] = { 
4561   {0,"SUCCESS",NULL},
4562   {0x01,"ERRDOS",dos_msgs},
4563   {0x02,"ERRSRV",server_msgs},
4564   {0x03,"ERRHRD",hard_msgs},
4565   {0x04,"ERRXOS",NULL},
4566   {0xE1,"ERRRMX1",NULL},
4567   {0xE2,"ERRRMX2",NULL},
4568   {0xE3,"ERRRMX3",NULL},
4569   {0xFF,"ERRCMD",NULL},
4570   {-1,NULL,NULL}};
4571
4572
4573 /****************************************************************************
4574 return a SMB error string from a SMB buffer
4575 ****************************************************************************/
4576 char *smb_errstr(char *inbuf)
4577 {
4578   static pstring ret;
4579   int class = CVAL(inbuf,smb_rcls);
4580   int num = SVAL(inbuf,smb_err);
4581   int i,j;
4582
4583   for (i=0;err_classes[i].class;i++)
4584     if (err_classes[i].code == class)
4585       {
4586         if (err_classes[i].err_msgs)
4587           {
4588             err_code_struct *err = err_classes[i].err_msgs;
4589             for (j=0;err[j].name;j++)
4590               if (num == err[j].code)
4591                 {
4592                   if (DEBUGLEVEL > 0)
4593                     sprintf(ret,"%s - %s (%s)",err_classes[i].class,
4594                             err[j].name,err[j].message);
4595                   else
4596                     sprintf(ret,"%s - %s",err_classes[i].class,err[j].name);
4597                   return ret;
4598                 }
4599           }
4600
4601         sprintf(ret,"%s - %d",err_classes[i].class,num);
4602         return ret;
4603       }
4604   
4605   sprintf(ret,"ERROR: Unknown error (%d,%d)",class,num);
4606   return(ret);
4607 }