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